refactor(telegram): use shared command dispatcher for incoming commands

This commit is contained in:
mingmxren 2026-03-01 02:31:53 +08:00
parent 5db50ee5ca
commit 9350e9d4c4
4 changed files with 113 additions and 16 deletions

View file

@ -44,6 +44,7 @@ type TelegramChannel struct {
bot *telego.Bot
bh *telegohandler.BotHandler
commands TelegramCommander
dispatcher commands.Dispatching
config *config.Config
chatIDs map[string]int64
ctx context.Context
@ -94,6 +95,7 @@ func NewTelegramChannel(cfg *config.Config, bus *bus.MessageBus) (*TelegramChann
return &TelegramChannel{
BaseChannel: base,
commands: NewTelegramCommands(bot, cfg),
dispatcher: commands.NewDispatcher(commands.NewRegistry(commands.BuiltinDefinitions(cfg))),
bot: bot,
config: cfg,
chatIDs: make(map[string]int64),
@ -121,22 +123,9 @@ func (c *TelegramChannel) Start(ctx context.Context) error {
c.bh = bh
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
c.commands.Help(ctx, message)
if c.dispatchCommand(ctx, message) {
return nil
}, th.CommandEqual("help"))
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
return c.commands.Start(ctx, message)
}, th.CommandEqual("start"))
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
return c.commands.Show(ctx, message)
}, th.CommandEqual("show"))
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
return c.commands.List(ctx, message)
}, th.CommandEqual("list"))
bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
}
return c.handleMessage(ctx, &message)
}, th.AnyMessage())

View file

@ -0,0 +1,66 @@
package telegram
import (
"context"
"strconv"
"github.com/mymmrac/telego"
"github.com/sipeed/picoclaw/pkg/commands"
"github.com/sipeed/picoclaw/pkg/logger"
)
func (c *TelegramChannel) dispatchCommand(ctx context.Context, message telego.Message) bool {
if c.dispatcher == nil {
return false
}
senderID := ""
if message.From != nil {
senderID = strconv.FormatInt(message.From.ID, 10)
}
res := c.dispatcher.Dispatch(ctx, commands.Request{
Channel: "telegram",
ChatID: strconv.FormatInt(message.Chat.ID, 10),
SenderID: senderID,
Text: message.Text,
MessageID: strconv.Itoa(message.MessageID),
})
if !res.Matched {
return false
}
switch res.Command {
case "help":
if err := c.commands.Help(ctx, message); err != nil {
logger.ErrorCF("telegram", "Command execution failed", map[string]any{
"command": "help",
"error": err.Error(),
})
}
case "start":
if err := c.commands.Start(ctx, message); err != nil {
logger.ErrorCF("telegram", "Command execution failed", map[string]any{
"command": "start",
"error": err.Error(),
})
}
case "show":
if err := c.commands.Show(ctx, message); err != nil {
logger.ErrorCF("telegram", "Command execution failed", map[string]any{
"command": "show",
"error": err.Error(),
})
}
case "list":
if err := c.commands.List(ctx, message); err != nil {
logger.ErrorCF("telegram", "Command execution failed", map[string]any{
"command": "list",
"error": err.Error(),
})
}
}
return true
}

View file

@ -0,0 +1,32 @@
package telegram
import (
"context"
"testing"
"github.com/mymmrac/telego"
"github.com/sipeed/picoclaw/pkg/commands"
)
func TestDispatchCommand_UsesDispatcher(t *testing.T) {
ch := &TelegramChannel{}
called := false
ch.dispatcher = commands.DispatchFunc(func(context.Context, commands.Request) commands.Result {
called = true
return commands.Result{Matched: true, Command: "noop"}
})
msg := telego.Message{
Text: "/help",
MessageID: 7,
Chat: telego.Chat{
ID: 123,
},
}
handled := ch.dispatchCommand(context.Background(), msg)
if !handled || !called {
t.Fatalf("handled=%v called=%v", handled, called)
}
}

View file

@ -25,6 +25,16 @@ type Dispatcher struct {
reg *Registry
}
type Dispatching interface {
Dispatch(ctx context.Context, req Request) Result
}
type DispatchFunc func(ctx context.Context, req Request) Result
func (f DispatchFunc) Dispatch(ctx context.Context, req Request) Result {
return f(ctx, req)
}
func NewDispatcher(reg *Registry) *Dispatcher {
return &Dispatcher{reg: reg}
}