tg/command.go

178 lines
3.5 KiB
Go
Raw Normal View History

2023-08-19 09:12:26 +03:00
package tg
2023-08-12 14:35:33 +03:00
import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
2023-08-12 14:35:33 +03:00
)
2023-09-30 09:55:45 +03:00
type CommandType uint8
const (
PrivateCommandType CommandType = iota
GroupCommandType
ChannelCommandType
)
2023-08-12 14:35:33 +03:00
type CommandName string
type Command struct {
Name CommandName
2023-09-30 09:55:45 +03:00
Type CommandType
2023-08-12 14:35:33 +03:00
Description string
Action Action
Widget Widget
2024-03-29 14:30:48 +03:00
WidgetArg any
2023-08-12 14:35:33 +03:00
}
2024-03-29 14:30:48 +03:00
type CommandMap map[CommandName]Command
2023-08-12 14:35:33 +03:00
func NewCommand(name CommandName, desc string) Command {
if name == "" || desc == "" {
panic("name and description cannot be an empty string")
}
2024-03-29 14:30:48 +03:00
return Command{
2023-08-12 14:35:33 +03:00
Name: name,
Description: desc,
2023-08-12 14:35:33 +03:00
}
}
2024-03-29 14:30:48 +03:00
func (c Command) WithAction(a Action) Command {
c.Action = a
2023-08-12 14:35:33 +03:00
return c
}
func (c Command) WithWidget(w Widget) Command {
c.Widget = w
return c
}
2024-03-29 14:30:48 +03:00
// Convert command into the tgbotapi.BotCommand
func (c Command) ToAPI() tgbotapi.BotCommand {
ret := tgbotapi.BotCommand{}
ret.Command = string(c.Name)
ret.Description = c.Description
return ret
}
2024-03-29 14:30:48 +03:00
// Simple command to go to another screen.
func (c Command) Go(pth Widget) Command {
return c.WithAction(WidgetGo{
2024-03-29 14:30:48 +03:00
Path: pth,
})
}
func (c Command) GoWithArg(pth Widget, arg any) Command {
return c.WithAction(WidgetGo{
Path: pth,
2024-03-29 14:30:48 +03:00
Arg: arg,
})
}
// The type is used to recognize commands and execute
// its actions and widgets .
type CommandCompo struct {
PreStart Action
Commands CommandMap
Usage Action
}
// Returns new empty CommandCompo.
2024-03-29 14:30:48 +03:00
func NewCommandCompo(cmds ...Command) *CommandCompo {
ret := (&CommandCompo{}).SetCommands(cmds...)
return ret
}
// Set the commands to handle.
2024-03-29 14:30:48 +03:00
func (w *CommandCompo) SetCommands(cmds ...Command) *CommandCompo {
if w.Commands == nil {
w.Commands = make(CommandMap)
}
for _, cmd := range cmds {
if cmd.Name == "" {
panic("empty command name")
}
_, ok := w.Commands[cmd.Name]
if ok {
panic("duplicate command definition")
}
w.Commands[cmd.Name] = cmd
}
return w
}
// Set the prestart action.
2024-03-29 14:30:48 +03:00
func (w *CommandCompo) SetPreStart(a Action) *CommandCompo {
w.PreStart = a
return w
}
// Set the usage action.
2024-03-29 14:30:48 +03:00
func (w *CommandCompo) SetUsage(a Action) *CommandCompo {
w.Usage = a
return w
}
2024-03-29 14:30:48 +03:00
// Filtering all the non commands.
func (widget *CommandCompo) Filter(
u Update,
) bool {
if u.Message == nil || !u.Message.IsCommand() {
return false
}
return false
}
// Implementing server.
2024-03-29 14:30:48 +03:00
func (compo *CommandCompo) Serve(c Context) {
// First should bring the new command into the action.
c.Bot().DeleteCommands()
err := c.Bot().SetCommands(
tgbotapi.NewBotCommandScopeChat(c.SessionID().ToAPI()),
2023-09-30 09:55:45 +03:00
compo.Commands,
)
2024-03-29 14:30:48 +03:00
if err != nil {
c.Sendf("error: %q", err)
}
2023-09-16 15:40:30 +03:00
var cmdUpdates *UpdateChan
for u := range c.Input() {
if c.Path() == nil && u.Message != nil {
// Skipping and executing the preinit action
// while we have the empty screen.
// E. g. the session did not start.
if !u.Message.IsCommand() ||
u.Message.Command() != "start" {
c.WithUpdate(u).Run(compo.PreStart)
continue
}
}
if u.Message != nil && u.Message.IsCommand() {
// Command handling.
cmdName := CommandName(u.Message.Command())
cmd, ok := compo.Commands[cmdName]
if !ok {
c.WithUpdate(u).Run(compo.Usage)
continue
}
c.WithUpdate(u).Run(cmd.Action)
if cmd.Widget != nil {
2024-03-29 14:30:48 +03:00
// Closing current widget
2023-09-16 15:40:30 +03:00
cmdUpdates.Close()
2024-03-29 14:30:48 +03:00
// And running the other one.
2024-07-23 15:41:31 +03:00
cmdUpdates, _ = c.WithArg(cmd.WidgetArg).RunWidget(cmd.Widget)
}
continue
}
if !cmdUpdates.Closed() {
// Send to the commands channel if we are
// executing one.
2023-09-16 15:40:30 +03:00
cmdUpdates.Send(u)
} else {
2024-03-29 14:30:48 +03:00
c.SkipUpdate(u)
}
}
}