Small fixes and a bit of refactoring.

This commit is contained in:
Andrey Parhomenko 2023-09-30 09:55:45 +03:00
parent b39e63cbaa
commit 37cd1d37fd
8 changed files with 56 additions and 227 deletions

View file

@ -112,6 +112,14 @@ WithInitFunc(func(c *tg.Context) {
tg.NewButton("Send location").Go("/send-location"), tg.NewButton("Send location").Go("/send-location"),
).Reply(), ).Reply(),
), ),
tg.Func(func(c *tg.Context){
for u := range c.Input() {
if u.EditedMessage != nil {
c.Sendf2("The new message is `%s`", u.EditedMessage.Text)
}
}
}),
} }
}), }),
@ -208,7 +216,7 @@ WithInitFunc(func(c *tg.Context) {
return tg.UI{ return tg.UI{
kbd, kbd,
tg.NewMessage("").Reply( tg.NewMessage("Use the reply keyboard to get back").Reply(
backKeyboard.Reply(), backKeyboard.Reply(),
), ),
} }
@ -242,7 +250,9 @@ WithInitFunc(func(c *tg.Context) {
}), }),
), ),
)).WithRoot(tg.NewCommandCompo(). )).WithRoot(tg.NewCommandCompo().
WithPreStart(tg.Func(func(c *tg.Context){ WithUsage(tg.Func(func(c *tg.Context){
c.Sendf("There is no such command %q", c.Message.Command())
})).WithPreStart(tg.Func(func(c *tg.Context){
c.Sendf("Please, use /start ") c.Sendf("Please, use /start ")
})).WithCommands( })).WithCommands(
tg.NewCommand("info"). tg.NewCommand("info").

View file

@ -77,50 +77,3 @@ func (beh *Behaviour) GetScreen(pth Path) *Screen {
return screen return screen
} }
// The type describes behaviour for the bot in group chats.
type GroupBehaviour struct {
Init GroupAction
// List of commands
Commands GroupCommandMap
}
// Returns new empty group behaviour object.
func NewGroupBehaviour() *GroupBehaviour {
return &GroupBehaviour{
Commands: make(GroupCommandMap),
}
}
// Sets an Action for initialization on each group connected to the
// group bot.
func (b *GroupBehaviour) WithInitAction(a GroupAction) *GroupBehaviour {
b.Init = a
return b
}
// The method reciveies a function to be called on initialization of the
// bot group bot.
func (b *GroupBehaviour) InitFunc(fn GroupActionFunc) *GroupBehaviour {
return b.WithInitAction(fn)
}
// The method sets group commands.
func (b *GroupBehaviour) WithCommands(
cmds ...*GroupCommand,
) *GroupBehaviour {
for _, cmd := range cmds {
if cmd.Name == "" {
panic("empty command name")
}
_, ok := b.Commands[cmd.Name]
if ok {
panic("duplicate command definition")
}
b.Commands[cmd.Name] = cmd
}
return b
}
// The type describes behaviour for the bot in channels.
type ChannelBehaviour struct {
}

View file

@ -22,12 +22,12 @@ type Bot struct {
// Private bot behaviour. // Private bot behaviour.
behaviour *Behaviour behaviour *Behaviour
// Group bot behaviour. // Group bot behaviour.
groupBehaviour *GroupBehaviour //groupBehaviour *GroupBehaviour
// Bot behaviour in channels. // Bot behaviour in channels.
channelBehaviour *ChannelBehaviour //channelBehaviour *ChannelBehaviour
contexts map[SessionId] *context contexts map[SessionId] *context
sessions SessionMap sessions SessionMap
groupSessions GroupSessionMap //groupSessions GroupSessionMap
} }
// Return the new bot with empty sessions and behaviour. // Return the new bot with empty sessions and behaviour.
@ -65,28 +65,8 @@ func (bot *Bot) Send(
return c.Bot.Send(c.Session.Id, v) return c.Bot.Send(c.Session.Id, v)
} }
/*func (bot *Bot) Render( // Get session by its ID. Can be used for any scope
sid SessionId, r Renderable, // including private, group and channel.
) (MessageMap, error) {
configs := r.Render(sid, bot)
if configs == nil {
return nil, MapCollisionErr
}
messages := make(MessageMap)
for _, config := range configs {
_, collision := messages[config.Name]
if collision {
return messages, MapCollisionErr
}
msg, err := bot.Api.Send(config.ToApi())
if err != nil {
return messages, err
}
messages[config.Name] = &msg
}
return messages, nil
}*/
func (bot *Bot) GetSession( func (bot *Bot) GetSession(
sid SessionId, sid SessionId,
) (*Session, bool) { ) (*Session, bool) {
@ -94,13 +74,6 @@ func (bot *Bot) GetSession(
return session, ok return session, ok
} }
func (bot *Bot) GetGroupSession(
sid SessionId,
) (*GroupSession, bool) {
session, ok := bot.groupSessions[sid]
return session, ok
}
func (b *Bot) WithBehaviour(beh *Behaviour) *Bot { func (b *Bot) WithBehaviour(beh *Behaviour) *Bot {
b.behaviour = beh b.behaviour = beh
b.sessions = make(SessionMap) b.sessions = make(SessionMap)
@ -112,7 +85,7 @@ func (b *Bot) WithSessions(sessions SessionMap) *Bot {
return b return b
} }
func (b *Bot) WithGroupBehaviour(beh *GroupBehaviour) *Bot { /*func (b *Bot) WithGroupBehaviour(beh *GroupBehaviour) *Bot {
b.groupBehaviour = beh b.groupBehaviour = beh
b.groupSessions = make(GroupSessionMap) b.groupSessions = make(GroupSessionMap)
return b return b
@ -121,12 +94,18 @@ func (b *Bot) WithGroupBehaviour(beh *GroupBehaviour) *Bot {
func (b *Bot) WithGroupSessions(sessions GroupSessionMap) *Bot { func (b *Bot) WithGroupSessions(sessions GroupSessionMap) *Bot {
b.groupSessions = sessions b.groupSessions = sessions
return b return b
}*/
func (bot *Bot) DeleteCommands() {
//tgbotapi.NewBotCommandScopeAllPrivateChats(),
cfg := tgbotapi.NewDeleteMyCommands()
bot.Api.Request(cfg)
} }
// Setting the command on the user side. // Setting the command on the user side.
func (bot *Bot) SetCommands( func (bot *Bot) SetCommands(
scope tgbotapi.BotCommandScope, scope tgbotapi.BotCommandScope,
cmdMap map[CommandName] BotCommander, cmdMap CommandMap,
) { ) {
// First the private commands. // First the private commands.
names := []string{} names := []string{}
@ -135,7 +114,7 @@ func (bot *Bot) SetCommands(
} }
sort.Strings([]string(names)) sort.Strings([]string(names))
cmds := []BotCommander{} cmds := []*Command{}
for _, name := range names { for _, name := range names {
cmds = append( cmds = append(
cmds, cmds,
@ -159,8 +138,7 @@ func (bot *Bot) SetCommands(
// Run the bot with the Behaviour. // Run the bot with the Behaviour.
func (bot *Bot) Run() error { func (bot *Bot) Run() error {
if bot.behaviour == nil && if bot.behaviour == nil {
bot.groupBehaviour == nil {
return errors.New("no behaviour defined") return errors.New("no behaviour defined")
} }
@ -169,9 +147,9 @@ func (bot *Bot) Run() error {
} }
uc := tgbotapi.NewUpdate(0) uc := tgbotapi.NewUpdate(0)
uc.Timeout = 60 uc.Timeout = 10
updates := bot.Api.GetUpdatesChan(uc) updates := bot.Api.GetUpdatesChan(uc)
handles := make(map[string]chan *Update) handles := make(map[string] chan *Update)
if bot.behaviour != nil { if bot.behaviour != nil {
chn := make(chan *Update) chn := make(chan *Update)
@ -179,7 +157,7 @@ func (bot *Bot) Run() error {
go bot.handlePrivate(chn) go bot.handlePrivate(chn)
} }
if bot.groupBehaviour != nil { /*if bot.groupBehaviour != nil {
commanders := make(map[CommandName] BotCommander) commanders := make(map[CommandName] BotCommander)
for k, v := range bot.groupBehaviour.Commands { for k, v := range bot.groupBehaviour.Commands {
commanders[k] = v commanders[k] = v
@ -192,7 +170,7 @@ func (bot *Bot) Run() error {
handles["group"] = chn handles["group"] = chn
handles["supergroup"] = chn handles["supergroup"] = chn
go bot.handleGroup(chn) go bot.handleGroup(chn)
} }*/
me, _ := bot.Api.GetMe() me, _ := bot.Api.GetMe()
bot.Me = &me bot.Me = &me
@ -249,7 +227,7 @@ func (bot *Bot) handlePrivate(updates chan *Update) {
} }
} }
} }
/*
func (bot *Bot) handleGroup(updates chan *Update) { func (bot *Bot) handleGroup(updates chan *Update) {
var sid SessionId var sid SessionId
chans := make(map[SessionId]chan *Update) chans := make(map[SessionId]chan *Update)
@ -273,3 +251,4 @@ func (bot *Bot) handleGroup(updates chan *Update) {
chn <- u chn <- u
} }
} }
*/

View file

@ -6,14 +6,18 @@ import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
) )
type BotCommander interface { type CommandType uint8
ToApi() tgbotapi.BotCommand const (
} PrivateCommandType CommandType = iota
type Message = tgbotapi.Message GroupCommandType
ChannelCommandType
)
type CommandName string type CommandName string
type Command struct { type Command struct {
Name CommandName Name CommandName
Type CommandType
Description string Description string
Action Action Action Action
Widget Widget Widget Widget
@ -63,41 +67,6 @@ func (c *Command) Go(pth Path, args ...any) *Command {
}) })
} }
type GroupCommand struct {
Name CommandName
Description string
Action GroupAction
}
type GroupCommandMap map[CommandName]*GroupCommand
func NewGroupCommand(name CommandName) *GroupCommand {
return &GroupCommand{
Name: name,
}
}
func (cmd *GroupCommand) WithAction(a GroupAction) *GroupCommand {
cmd.Action = a
return cmd
}
func (cmd *GroupCommand) ActionFunc(fn GroupActionFunc) *GroupCommand {
return cmd.WithAction(fn)
}
func (cmd *GroupCommand) Desc(desc string) *GroupCommand {
cmd.Description = desc
return cmd
}
func (c *GroupCommand) ToApi() tgbotapi.BotCommand {
ret := tgbotapi.BotCommand{}
ret.Command = string(c.Name)
ret.Description = c.Description
return ret
}
// The type is used to recognize commands and execute // The type is used to recognize commands and execute
// its actions and widgets . // its actions and widgets .
type CommandCompo struct { type CommandCompo struct {
@ -165,13 +134,14 @@ func (widget *CommandCompo) Filter(
// Implementing server. // Implementing server.
func (compo *CommandCompo) Serve(c *Context) { func (compo *CommandCompo) Serve(c *Context) {
commanders := make(map[CommandName] BotCommander) /*commanders := make(map[CommandName] BotCommander)
for k, v := range compo.Commands { for k, v := range compo.Commands {
commanders[k] = v commanders[k] = v
} }*/
c.Bot.DeleteCommands()
c.Bot.SetCommands( c.Bot.SetCommands(
tgbotapi.NewBotCommandScopeAllPrivateChats(), tgbotapi.NewBotCommandScopeAllPrivateChats(),
commanders, compo.Commands,
) )
var cmdUpdates *UpdateChan var cmdUpdates *UpdateChan

View file

@ -32,6 +32,6 @@ func DefineAction(typeName string, a Action) error {
return nil return nil
} }
func DefineGroupAction(typ string, a GroupAction) error { /*func DefineGroupAction(typ string, a GroupAction) error {
return nil return nil
} }*/

View file

@ -1,94 +1,2 @@
package tg package tg
import (
"fmt"
//tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
// Customized actions for the group behaviour.
type GroupAction interface {
Act(*GroupContext)
}
// The handler function type.
type GroupActionFunc func(*GroupContext)
func (af GroupActionFunc) Act(a *GroupContext) {
af(a)
}
type GC = GroupContext
func (c *GroupContext) Session() *GroupSession {
session, _ := c.Bot.GetGroupSession(
SessionId(c.SentFrom().ID),
)
return session
}
type GroupContext struct {
*groupContext
*Update
}
// Context for interaction inside groups.
type groupContext struct {
Session *GroupSession
Bot *Bot
updates chan *Update
}
func (c *groupContext) run(a GroupAction, u *Update) {
go a.Act(&GroupContext{
groupContext: c,
Update: u,
})
}
func (c *groupContext) handleUpdateChan(updates chan *Update) {
var act GroupAction
beh := c.Bot.groupBehaviour
for u := range updates {
if u.Message != nil {
msg := u.Message
if msg.IsCommand() {
cmdName := CommandName(msg.Command())
// Skipping the commands sent not to us.
withAt := msg.CommandWithAt()
if len(cmdName) == len(withAt) {
continue
}
atName := withAt[len(cmdName)+1:]
if c.Bot.Me.UserName != atName {
continue
}
cmd, ok := beh.Commands[cmdName]
if !ok {
// Some lack of command handling
continue
}
act = cmd.Action
}
}
if act != nil {
c.run(act, u)
}
}
}
func (c *groupContext) Sendf(
format string,
v ...any,
) (*Message, error) {
return c.Send(NewMessage(
fmt.Sprintf(format, v...),
))
}
// Sends into the chat specified values converted to strings.
func (c *groupContext) Send(v Sendable) (*Message, error) {
return c.Bot.Send(c.Session.Id, v)
}

View file

@ -3,6 +3,7 @@ package tg
import ( import (
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
) )
type Message = tgbotapi.Message
// Simple text message type. // Simple text message type.
type MessageCompo struct { type MessageCompo struct {

8
tg/poll.go Normal file
View file

@ -0,0 +1,8 @@
package tg
type Poll struct {
}
type PollCompo struct {
}