Files
trbot/utils/plugin_utils/handler_state.go
Hubert Chen 13a6b46911 fix state handler trigger
handler_state.go:
    use chat ID to get handler
utils.go:
     `GetMessageFromHyperLink()` fix format
    add `TextBlockquoteMarkdown()` function
plugin_detect_keyword.go:
    stop convert text to lowercase
    use `contain.SubStringCaseInsensitive()` replace `strings.Contains()`
    use `models.ParseModeMarkdown` in `notifyUser()`
2025-08-05 00:26:56 +08:00

150 lines
4.3 KiB
Go

package plugin_utils
import (
"errors"
"fmt"
"trbot/utils/flaterr"
"trbot/utils/handler_params"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
type StateHandler struct {
ForChatID int64
PluginName string
// StopTimeout time.Time
// handler will auto remove when Remaining == 0
//
// if Remaining == -1, it will never remove
Remaining int
MessageHandler func(*handler_params.Message) error
// A function that will be run after the user sends the `/cancle` command
//
// If it is nil, the program will send a message to the user that the operation
// has been canceled, otherwise CancelHandler will handle it by itself.
//
// And then the program will remove this state handler
CancelHandler func(*handler_params.Message) error
}
func AddStateHandler(handler StateHandler) bool {
if AllPlugins.StateHandler == nil { AllPlugins.StateHandler = map[int64]StateHandler{} }
if handler.ForChatID == 0 {
log.Error().
Str("funcName", "AddStateHandler").
Int64("forChatID", handler.ForChatID).
Str("name", handler.PluginName).
Int("Remaining", handler.Remaining).
Msg("Duplicate plugin exists, registration skipped")
return false
}
if handler.Remaining == 0 {
log.Error().
Str("funcName", "AddStateHandler").
Int64("forChatID", handler.ForChatID).
Str("name", handler.PluginName).
Int("Remaining", handler.Remaining).
Msg("No remaining times set, registration skipped")
return false
}
if handler.MessageHandler == nil {
log.Error().
Str("funcName", "AddStateHandler").
Int64("forChatID", handler.ForChatID).
Str("name", handler.PluginName).
Int("Remaining", handler.Remaining).
Msg("No handler set, registration skipped")
return false
}
AllPlugins.StateHandler[handler.ForChatID] = handler
return true
}
func RemoveStateHandler(chatID int64) {
if chatID == 0 { return }
delete(AllPlugins.StateHandler, chatID)
}
// this can't edit `remainingTime` to `0` or `stateFunc` to `nil`, if you need remove state handler, use `plugin_utils.RemoveStateHandler()`
func EditStateHandler(chatID int64, remainingTime int, stateFunc func(*handler_params.Message) error) (bool, error) {
if chatID == 0 { return false, errors.New("chatID is required") }
targetHandler, isExist := AllPlugins.StateHandler[chatID]
if !isExist {
log.Warn().
Str("funcName", "EditStateHandler").
Int64("forChatID", chatID).
Msg("No state handler exists, edit stopped")
return false, fmt.Errorf("no state handler for %d chatID", chatID)
}
if remainingTime != 0 {
targetHandler.Remaining = remainingTime
}
if stateFunc != nil {
targetHandler.MessageHandler = stateFunc
}
AllPlugins.StateHandler[chatID] = targetHandler
return true, nil
}
func RunStateHandler(opts *handler_params.Message) bool {
if AllPlugins.StateHandler == nil{ return false }
handler, isExist := AllPlugins.StateHandler[opts.Message.Chat.ID]
if isExist {
logger := zerolog.Ctx(opts.Ctx).
With().
Str("funcName", "RunStateHandler").
Int64("forChatID", handler.ForChatID).
Str("pluginName", handler.PluginName).
Logger()
if opts.Message.Text == "/cancel" {
if handler.CancelHandler != nil {
err := handler.CancelHandler(opts)
if err != nil {
logger.Error().
Err(err).
Msg("Error in CancelHandler")
}
} else {
_, err := opts.Thebot.SendMessage(opts.Ctx, &bot.SendMessageParams{
ChatID: handler.ForChatID,
ReplyParameters: &models.ReplyParameters{ MessageID: opts.Message.ID },
Text: fmt.Sprintf("已取消当前 [ %s ] 操作", handler.PluginName),
})
if err != nil {
logger.Error().
Err(err).
Str("content", "state canceled").
Msg(flaterr.SendMessage.Str())
}
}
delete(AllPlugins.StateHandler, opts.ChatInfo.ID)
return true
}
logger.Info().Msg("Hit state handler")
if handler.MessageHandler == nil {
logger.Error().Msg("Handler is nil")
return false
}
if handler.Remaining > 0 { handler.Remaining-- }
err := handler.MessageHandler(opts)
if err != nil {
logger.Error().
Err(err).
Msg("Error in state handler")
}
if handler.Remaining == 0 {
delete(AllPlugins.StateHandler, opts.ChatInfo.ID)
} else {
AllPlugins.StateHandler[opts.ChatInfo.ID] = handler
}
}
return isExist
}