feat(commands): add dispatcher and request/result contracts
This commit is contained in:
parent
885dc310e3
commit
6975ab1945
3 changed files with 88 additions and 0 deletions
|
|
@ -6,4 +6,5 @@ type Definition struct {
|
||||||
Usage string
|
Usage string
|
||||||
Aliases []string
|
Aliases []string
|
||||||
Channels []string
|
Channels []string
|
||||||
|
Handler Handler
|
||||||
}
|
}
|
||||||
|
|
|
||||||
59
pkg/commands/dispatcher.go
Normal file
59
pkg/commands/dispatcher.go
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler func(ctx context.Context, req Request) error
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Channel string
|
||||||
|
ChatID string
|
||||||
|
SenderID string
|
||||||
|
Text string
|
||||||
|
MessageID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Matched bool
|
||||||
|
Command string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dispatcher struct {
|
||||||
|
reg *Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDispatcher(reg *Registry) *Dispatcher {
|
||||||
|
return &Dispatcher{reg: reg}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dispatcher) Dispatch(ctx context.Context, req Request) Result {
|
||||||
|
token := firstToken(req.Text)
|
||||||
|
if token == "" {
|
||||||
|
return Result{Matched: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdName := strings.TrimPrefix(token, "/")
|
||||||
|
for _, def := range d.reg.ForChannel(req.Channel) {
|
||||||
|
if def.Name != cmdName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if def.Handler == nil {
|
||||||
|
return Result{Matched: true, Command: def.Name}
|
||||||
|
}
|
||||||
|
err := def.Handler(ctx, req)
|
||||||
|
return Result{Matched: true, Command: def.Name, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result{Matched: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
func firstToken(input string) string {
|
||||||
|
parts := strings.Fields(strings.TrimSpace(input))
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return parts[0]
|
||||||
|
}
|
||||||
28
pkg/commands/dispatcher_test.go
Normal file
28
pkg/commands/dispatcher_test.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDispatcher_MatchSlashCommand(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
defs := []Definition{
|
||||||
|
{
|
||||||
|
Name: "help",
|
||||||
|
Handler: func(context.Context, Request) error {
|
||||||
|
called = true
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
d := NewDispatcher(NewRegistry(defs))
|
||||||
|
|
||||||
|
res := d.Dispatch(context.Background(), Request{
|
||||||
|
Channel: "telegram",
|
||||||
|
Text: "/help",
|
||||||
|
})
|
||||||
|
if !res.Matched || !called || res.Err != nil {
|
||||||
|
t.Fatalf("dispatch result = %+v, called=%v", res, called)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue