FILE / ScuroNeko/Laniakea
msg_handler.go
Исходный файл и его история в репозитории.
Instrument command, payload, update, scene, runner, polling, and policy flows Add observer regression coverage and mark observability backlog item done
220 lines
5.2 KiB
Go
220 lines
5.2 KiB
Go
package laniakea
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
|
|
)
|
|
|
|
func (bot *Bot[T]) handleMessage(update *tgapi.Update, ctx *MsgContext) bool {
|
|
var msg *tgapi.Message
|
|
if update.Message != nil {
|
|
msg = update.Message
|
|
} else if update.ChannelPost != nil {
|
|
msg = update.ChannelPost
|
|
} else {
|
|
return false
|
|
}
|
|
|
|
var text string
|
|
if len(msg.Text) > 0 {
|
|
text = msg.Text
|
|
} else if len(msg.Caption) > 0 {
|
|
text = msg.Caption
|
|
} else {
|
|
return false
|
|
}
|
|
|
|
prefix, cmd, args := bot.parseCommand(text)
|
|
if cmd == "" {
|
|
return false
|
|
}
|
|
ctx.Prefix = prefix
|
|
|
|
if strings.Contains(cmd, "@") {
|
|
botUsername := bot.username
|
|
if botUsername != "" && strings.HasSuffix(cmd, "@"+botUsername) {
|
|
cmd = cmd[:len(cmd)-len("@"+botUsername)] // убираем @botname
|
|
}
|
|
}
|
|
// Ищем команду по точному совпадению
|
|
for _, plugin := range bot.plugins {
|
|
if _, exists := plugin.commands[cmd]; exists {
|
|
|
|
ctx.Text = args
|
|
ctx.Args = strings.Fields(args) // Убирает лишние пробелы
|
|
|
|
if plugin.logger != nil {
|
|
ctx.Logger = plugin.logger
|
|
}
|
|
if !plugin.executeMiddlewares(ctx, bot.appData) {
|
|
return false
|
|
}
|
|
|
|
startTime := time.Now()
|
|
bot.safeEmitEvent(ctx.Context(), HandlerStartedEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: plugin.name,
|
|
HandlerKind: HandlerCommandKind,
|
|
HandlerName: cmd,
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
})
|
|
|
|
err := plugin.executeCmd(cmd, ctx, bot.appData)
|
|
handlerEndEvent := HandlerFinishedEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: plugin.name,
|
|
HandlerKind: HandlerCommandKind,
|
|
HandlerName: cmd,
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
Duration: time.Since(startTime),
|
|
}
|
|
|
|
var errorEvent *ErrorEvent = nil
|
|
if err != nil {
|
|
ctx.error(err)
|
|
handlerEndEvent.Err = err
|
|
handlerEndEvent.UserFacing = IsUserError(err)
|
|
errorEvent = &ErrorEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: plugin.name,
|
|
HandlerKind: HandlerCommandKind,
|
|
HandlerName: cmd,
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
Err: err,
|
|
UserFacing: handlerEndEvent.UserFacing,
|
|
}
|
|
}
|
|
bot.safeEmitEvent(ctx.Context(), handlerEndEvent)
|
|
if errorEvent != nil {
|
|
bot.safeEmitEvent(ctx.Context(), *errorEvent)
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (bot *Bot[T]) handleCallback(update *tgapi.Update, ctx *MsgContext) bool {
|
|
data, err := bot.decodePayload(update.CallbackQuery.Data)
|
|
if err != nil {
|
|
bot.logger.Errorln(err)
|
|
bot.safeEmitEvent(ctx.Context(), ErrorEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: "bot",
|
|
HandlerKind: HandlerPayloadKind,
|
|
HandlerName: "decodePayload",
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
Err: err,
|
|
UserFacing: false,
|
|
})
|
|
return false
|
|
}
|
|
|
|
ctx.Args = data.Args
|
|
|
|
for _, plugin := range bot.plugins {
|
|
_, ok := plugin.payloads[data.Command]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
ctx.Logger = plugin.logger
|
|
if ctx.Logger == nil {
|
|
ctx.Logger = bot.logger
|
|
}
|
|
|
|
if !plugin.executeMiddlewares(ctx, bot.appData) {
|
|
return false
|
|
}
|
|
|
|
startTime := time.Now()
|
|
bot.safeEmitEvent(ctx.Context(), HandlerStartedEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: plugin.name,
|
|
HandlerKind: HandlerPayloadKind,
|
|
HandlerName: data.Command,
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
})
|
|
err := plugin.executePayload(data.Command, ctx, bot.appData)
|
|
|
|
endEvent := HandlerFinishedEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: plugin.name,
|
|
HandlerKind: HandlerPayloadKind,
|
|
HandlerName: data.Command,
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
Duration: time.Since(startTime),
|
|
}
|
|
var errorEvent *ErrorEvent = nil
|
|
if err != nil {
|
|
ctx.error(err)
|
|
errorEvent = &ErrorEvent{
|
|
UpdateID: update.UpdateID,
|
|
UpdateType: update.Type,
|
|
Plugin: plugin.name,
|
|
HandlerKind: HandlerPayloadKind,
|
|
HandlerName: data.Command,
|
|
FromID: ctx.FromID,
|
|
ChatID: ctx.ChatID,
|
|
Err: err,
|
|
UserFacing: IsUserError(err),
|
|
}
|
|
endEvent.Err = err
|
|
endEvent.UserFacing = errorEvent.UserFacing
|
|
}
|
|
bot.safeEmitEvent(ctx.Context(), endEvent)
|
|
if errorEvent != nil {
|
|
bot.safeEmitEvent(ctx.Context(), *errorEvent)
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (bot *Bot[T]) checkPrefixes(text string) (string, bool) {
|
|
for _, prefix := range bot.prefixes {
|
|
if prefix == "" {
|
|
if bot.logger != nil {
|
|
bot.logger.Warnln("empty prefix is not allowed")
|
|
}
|
|
continue
|
|
}
|
|
if strings.HasPrefix(text, prefix) {
|
|
return prefix, true
|
|
}
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
func (bot *Bot[T]) parseCommand(text string) (prefix, cmd, args string) {
|
|
if prefix, hasPrefix := bot.checkPrefixes(text); hasPrefix {
|
|
text = strings.TrimSpace(text[len(prefix):])
|
|
spaceIndex := strings.Index(text, " ")
|
|
var cmd string
|
|
var args string
|
|
if spaceIndex == -1 {
|
|
cmd = text
|
|
args = ""
|
|
} else {
|
|
cmd = text[:spaceIndex]
|
|
args = strings.TrimSpace(text[spaceIndex:])
|
|
}
|
|
return prefix, cmd, args
|
|
}
|
|
return "", "", ""
|
|
}
|