Implemented basic group behaviour.
This commit is contained in:
parent
e3045862c4
commit
c2562cc54c
8 changed files with 409 additions and 204 deletions
|
@ -150,13 +150,29 @@ func mutateMessage(fn func(string) string) tx.ActionFunc {
|
|||
}
|
||||
}
|
||||
|
||||
var gBeh = tx.NewGroupBehaviour().
|
||||
InitFunc(func(a *tx.GA) {
|
||||
}).
|
||||
WithCommands(
|
||||
tx.NewGroupCommand("hello").ActionFunc(func(a *tx.GA) {
|
||||
a.Send("Hello, World!")
|
||||
}),
|
||||
tx.NewGroupCommand("mycounter").ActionFunc(func(a *tx.GA) {
|
||||
d := a.GetSessionValue().(*UserData)
|
||||
a.Sendf("Your counter value is %d", d.Counter)
|
||||
}),
|
||||
)
|
||||
|
||||
func main() {
|
||||
token := os.Getenv("BOT_TOKEN")
|
||||
|
||||
bot, err := tx.NewBot(token, beh, nil)
|
||||
bot, err := tx.NewBot(token)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
bot = bot.
|
||||
WithBehaviour(beh).
|
||||
WithGroupBehaviour(gBeh)
|
||||
|
||||
bot.Debug = true
|
||||
|
||||
|
|
110
src/tx/action.go
110
src/tx/action.go
|
@ -1,10 +1,41 @@
|
|||
package tx
|
||||
|
||||
import (
|
||||
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
//apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
|
||||
type Update = apix.Update
|
||||
type Action interface {
|
||||
Act(*Arg)
|
||||
}
|
||||
|
||||
type GroupAction interface {
|
||||
Act(*GroupArg)
|
||||
}
|
||||
|
||||
// Customized actions for the bot.
|
||||
|
||||
type ActionFunc func(*Arg)
|
||||
|
||||
func (af ActionFunc) Act(a *Arg) {
|
||||
af(a)
|
||||
}
|
||||
|
||||
type GroupActionFunc func(*GroupArg)
|
||||
|
||||
func (af GroupActionFunc) Act(a *GroupArg) {
|
||||
af(a)
|
||||
}
|
||||
|
||||
// The type implements changing screen to the underlying ScreenId
|
||||
type ScreenChange ScreenId
|
||||
|
||||
func (sc ScreenChange) Act(c *Arg) {
|
||||
if !c.B.behaviour.ScreenExist(ScreenId(sc)) {
|
||||
panic(ScreenNotExistErr)
|
||||
}
|
||||
err := c.ChangeScreen(ScreenId(sc))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// The argument for handling.
|
||||
type Arg struct {
|
||||
|
@ -15,14 +46,57 @@ type Arg struct {
|
|||
}
|
||||
type A = Arg
|
||||
|
||||
// Changes screen of user to the Id one.
|
||||
func (c *Arg) ChangeScreen(screenId ScreenId) error {
|
||||
// Return if it will not change anything.
|
||||
if c.CurrentScreenId == screenId {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !c.B.behaviour.ScreenExist(screenId) {
|
||||
return ScreenNotExistErr
|
||||
}
|
||||
|
||||
// Stop the reading by sending the nil.
|
||||
if c.readingUpdate {
|
||||
c.updates <- nil
|
||||
}
|
||||
|
||||
screen := c.B.behaviour.Screens[screenId]
|
||||
screen.Render(c.Context)
|
||||
|
||||
c.Session.ChangeScreen(screenId)
|
||||
c.KeyboardId = screen.KeyboardId
|
||||
|
||||
if screen.Action != nil {
|
||||
c.run(screen.Action, c.U)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The argument for handling in group behaviour.
|
||||
type GroupArg struct {
|
||||
GroupArg *GroupContext
|
||||
U *Update
|
||||
*GroupContext
|
||||
*Update
|
||||
}
|
||||
type GA = GroupArg
|
||||
|
||||
type Action interface {
|
||||
Act(*Arg)
|
||||
func (a *GA) SentFromSid() SessionId {
|
||||
return SessionId(a.SentFrom().ID)
|
||||
}
|
||||
|
||||
func (a *GA) GetSessionValue() any {
|
||||
v, _ := a.B.GetSessionValueBySid(a.SentFromSid())
|
||||
return v
|
||||
}
|
||||
|
||||
// The argument for handling in channenl behaviours.
|
||||
type ChannelArg struct {
|
||||
}
|
||||
type CA = ChannelArg
|
||||
type ChannelAction struct {
|
||||
Act (*ChannelArg)
|
||||
}
|
||||
|
||||
type JsonTyper interface {
|
||||
|
@ -37,23 +111,3 @@ type JsonAction struct {
|
|||
func (ja JsonAction) UnmarshalJSON(bts []byte, ptr any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Customized action for the bot.
|
||||
type ActionFunc func(*Arg)
|
||||
|
||||
// The type implements changing screen to the underlying ScreenId
|
||||
type ScreenChange ScreenId
|
||||
|
||||
func (sc ScreenChange) Act(c *Arg) {
|
||||
if !c.B.ScreenExist(ScreenId(sc)) {
|
||||
panic(ScreenNotExistErr)
|
||||
}
|
||||
err := c.ChangeScreen(ScreenId(sc))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (af ActionFunc) Act(c *Arg) {
|
||||
af(c)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@ package tx
|
|||
// The package implements
|
||||
// behaviour for the Telegram bots.
|
||||
|
||||
// The type describes behaviour for the bot in channels.
|
||||
type ChannelBehaviour struct {
|
||||
}
|
||||
|
||||
// The type describes behaviour for the bot in personal chats.
|
||||
type Behaviour struct {
|
||||
Start Action
|
||||
|
@ -11,18 +15,6 @@ type Behaviour struct {
|
|||
Commands CommandMap
|
||||
}
|
||||
|
||||
// The type describes behaviour for the bot in group chats.
|
||||
type GroupBehaviour struct {
|
||||
// Will be called on adding the bot to the group.
|
||||
//Add GroupAction
|
||||
// List of commands
|
||||
Commands CommandMap
|
||||
}
|
||||
|
||||
// The type describes behaviour for the bot in channels.
|
||||
type ChannelBehaviour struct {
|
||||
}
|
||||
|
||||
// Returns new empty behaviour.
|
||||
func NewBehaviour() *Behaviour {
|
||||
return &Behaviour{
|
||||
|
@ -128,3 +120,41 @@ func (beh *Behaviour) GetScreen(id ScreenId) *Screen {
|
|||
screen := beh.Screens[id]
|
||||
return screen
|
||||
}
|
||||
|
||||
// The type describes behaviour for the bot in group chats.
|
||||
type GroupBehaviour struct {
|
||||
Init GroupAction
|
||||
// List of commands
|
||||
Commands GroupCommandMap
|
||||
}
|
||||
|
||||
func NewGroupBehaviour() *GroupBehaviour {
|
||||
return &GroupBehaviour{
|
||||
Commands: make(GroupCommandMap),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *GroupBehaviour) WithInitAction(a GroupAction) *GroupBehaviour {
|
||||
b.Init = a
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *GroupBehaviour) InitFunc(fn GroupActionFunc) *GroupBehaviour {
|
||||
return b.WithInitAction(fn)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
211
src/tx/bot.go
211
src/tx/bot.go
|
@ -1,60 +1,113 @@
|
|||
package tx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
//"fmt"
|
||||
|
||||
"errors"
|
||||
|
||||
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
type Update = apix.Update
|
||||
type Chat = apix.Chat
|
||||
type User = apix.User
|
||||
|
||||
// The wrapper around Telegram API.
|
||||
type Bot struct {
|
||||
*apix.BotAPI
|
||||
*Behaviour
|
||||
sessions SessionMap
|
||||
Me *User
|
||||
// Private bot behaviour.
|
||||
behaviour *Behaviour
|
||||
// Group bot behaviour.
|
||||
groupBehaviour *GroupBehaviour
|
||||
// Bot behaviour in channels.
|
||||
channelBehaviour *ChannelBehaviour
|
||||
sessions SessionMap
|
||||
groupSessions GroupSessionMap
|
||||
}
|
||||
|
||||
// Return the new bot for running the Behaviour.
|
||||
func NewBot(token string, beh *Behaviour, sessions SessionMap) (*Bot, error) {
|
||||
// Return the new bot with empty sessions and behaviour.
|
||||
func NewBot(token string) (*Bot, error) {
|
||||
bot, err := apix.NewBotAPI(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make new sessions if no current are provided.
|
||||
if sessions == nil {
|
||||
sessions = make(SessionMap)
|
||||
}
|
||||
|
||||
return &Bot{
|
||||
BotAPI: bot,
|
||||
Behaviour: beh,
|
||||
sessions: make(SessionMap),
|
||||
BotAPI: bot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (bot *Bot) GetSessionValueBySid(
|
||||
sid SessionId,
|
||||
) (any, bool) {
|
||||
v, ok := bot.sessions[sid]
|
||||
return v.V, ok
|
||||
}
|
||||
|
||||
func (bot *Bot) GetGroupSessionValue(
|
||||
sid SessionId,
|
||||
) (any, bool) {
|
||||
v, ok := bot.groupSessions[sid]
|
||||
return v.V, ok
|
||||
}
|
||||
|
||||
func (b *Bot) WithBehaviour(beh *Behaviour) *Bot {
|
||||
b.behaviour = beh
|
||||
b.sessions = make(SessionMap)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bot) WithSessions(sessions SessionMap) *Bot {
|
||||
b.sessions = sessions
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bot) WithGroupBehaviour(beh *GroupBehaviour) *Bot {
|
||||
b.groupBehaviour = beh
|
||||
b.groupSessions = make(GroupSessionMap)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bot) WithGroupSessions(sessions GroupSessionMap) *Bot {
|
||||
b.groupSessions = sessions
|
||||
return b
|
||||
}
|
||||
|
||||
// Run the bot with the Behaviour.
|
||||
func (bot *Bot) Run() error {
|
||||
if bot.behaviour == nil &&
|
||||
bot.groupBehaviour == nil {
|
||||
return errors.New("no behaviour defined")
|
||||
}
|
||||
bot.Debug = true
|
||||
uc := apix.NewUpdate(0)
|
||||
uc.Timeout = 60
|
||||
updates := bot.GetUpdatesChan(uc)
|
||||
privateChans := make(map[SessionId]chan *Update)
|
||||
groupChans := make(map[SessionId]chan *Update)
|
||||
handles := make(map[string]chan *Update)
|
||||
|
||||
if bot.behaviour != nil {
|
||||
chn := make(chan *Update)
|
||||
handles["private"] = chn
|
||||
go bot.handlePrivate(chn)
|
||||
}
|
||||
|
||||
if bot.groupBehaviour != nil {
|
||||
chn := make(chan *Update)
|
||||
handles["group"] = chn
|
||||
handles["supergroup"] = chn
|
||||
go bot.handleGroup(chn)
|
||||
}
|
||||
|
||||
me, _ := bot.GetMe()
|
||||
bot.Me = &me
|
||||
for u := range updates {
|
||||
var chatType string
|
||||
|
||||
if u.Message != nil {
|
||||
chatType = u.Message.Chat.Type
|
||||
} else if u.CallbackQuery != nil {
|
||||
chatType = u.Message.Chat.Type
|
||||
chn, ok := handles[u.FromChat().Type]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
switch chatType {
|
||||
case "private":
|
||||
bot.handlePrivate(&u, privateChans)
|
||||
case "group", "supergroup":
|
||||
bot.handleGroup(&u, groupChans)
|
||||
}
|
||||
chn <- &u
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -62,55 +115,69 @@ func (bot *Bot) Run() error {
|
|||
|
||||
// The function handles updates supposed for the private
|
||||
// chat with the bot.
|
||||
func (bot *Bot) handlePrivate(u *Update, chans map[SessionId]chan *Update) {
|
||||
func (bot *Bot) handlePrivate(updates chan *Update) {
|
||||
chans := make(map[SessionId]chan *Update)
|
||||
var sid SessionId
|
||||
if u.Message != nil {
|
||||
msg := u.Message
|
||||
|
||||
if bot.Debug {
|
||||
fmt.Printf("is command: %q\n", u.Message.IsCommand())
|
||||
fmt.Printf("command itself: %q\n", msg.Command())
|
||||
fmt.Printf("command arguments: %q\n", msg.CommandArguments())
|
||||
fmt.Printf("is to me: %q\n", bot.IsMessageToMe(*msg))
|
||||
}
|
||||
|
||||
// Create new session if the one does not exist
|
||||
// for this user.
|
||||
sid = SessionId(u.Message.Chat.ID)
|
||||
if _, ok := bot.sessions[sid]; !ok {
|
||||
bot.sessions.Add(sid)
|
||||
}
|
||||
|
||||
// The "start" command resets the bot
|
||||
// by executing the Start Action.
|
||||
if u.Message.IsCommand() {
|
||||
cmdName := CommandName(u.Message.Command())
|
||||
if cmdName == "start" {
|
||||
// Getting current session and context.
|
||||
session := bot.sessions[sid]
|
||||
ctx := &Context{
|
||||
B: bot,
|
||||
Session: session,
|
||||
updates: make(chan *Update),
|
||||
}
|
||||
|
||||
chn := make(chan *Update)
|
||||
chans[sid] = chn
|
||||
// Starting the goroutine for the user.
|
||||
go ctx.handleUpdateChan(chn)
|
||||
for u := range updates {
|
||||
if u.Message != nil {
|
||||
// Create new session if the one does not exist
|
||||
// for this user.
|
||||
sid = SessionId(u.Message.Chat.ID)
|
||||
if _, ok := bot.sessions[sid]; !ok {
|
||||
bot.sessions.Add(sid)
|
||||
}
|
||||
|
||||
// The "start" command resets the bot
|
||||
// by executing the Start Action.
|
||||
if u.Message.IsCommand() {
|
||||
cmdName := CommandName(u.Message.Command())
|
||||
if cmdName == "start" {
|
||||
// Getting current session and context.
|
||||
session := bot.sessions[sid]
|
||||
ctx := &Context{
|
||||
B: bot,
|
||||
Session: session,
|
||||
updates: make(chan *Update),
|
||||
}
|
||||
|
||||
chn := make(chan *Update)
|
||||
chans[sid] = chn
|
||||
// Starting the goroutine for the user.
|
||||
go ctx.handleUpdateChan(chn)
|
||||
}
|
||||
}
|
||||
} else if u.CallbackQuery != nil {
|
||||
sid = SessionId(u.CallbackQuery.Message.Chat.ID)
|
||||
}
|
||||
chn, ok := chans[sid]
|
||||
// The bot MUST get the "start" command.
|
||||
// It will do nothing otherwise.
|
||||
if ok {
|
||||
chn <- u
|
||||
}
|
||||
} else if u.CallbackQuery != nil {
|
||||
sid = SessionId(u.CallbackQuery.Message.Chat.ID)
|
||||
}
|
||||
chn, ok := chans[sid]
|
||||
// The bot MUST get the "start" command.
|
||||
// It will do nothing otherwise.
|
||||
if ok {
|
||||
}
|
||||
|
||||
func (bot *Bot) handleGroup(updates chan *Update) {
|
||||
var sid SessionId
|
||||
chans := make(map[SessionId]chan *Update)
|
||||
for u := range updates {
|
||||
sid = SessionId(u.FromChat().ID)
|
||||
// If no session add new.
|
||||
if _, ok := bot.groupSessions[sid]; !ok {
|
||||
bot.groupSessions.Add(sid)
|
||||
session := bot.groupSessions[sid]
|
||||
ctx := &GroupContext{
|
||||
B: bot,
|
||||
GroupSession: session,
|
||||
updates: make(chan *Update),
|
||||
}
|
||||
chn := make(chan *Update)
|
||||
chans[sid] = chn
|
||||
go ctx.handleUpdateChan(chn)
|
||||
}
|
||||
|
||||
chn := chans[sid]
|
||||
chn <- u
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented yet.
|
||||
func (bot *Bot) handleGroup(u *Update, chans map[SessionId]chan *Update) {
|
||||
}
|
||||
|
|
|
@ -7,28 +7,14 @@ import (
|
|||
)
|
||||
|
||||
type Message = apix.Message
|
||||
|
||||
type CommandName string
|
||||
|
||||
type CommandContext struct {
|
||||
// The field declares way to interact with the group chat in
|
||||
// general.
|
||||
*Context
|
||||
Message *Message
|
||||
}
|
||||
|
||||
type CommandMap map[CommandName]*Command
|
||||
|
||||
type CommandHandlerFunc func(*CommandContext)
|
||||
type CommandHandler interface {
|
||||
Run(*Context)
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
Name CommandName
|
||||
Description string
|
||||
Action Action
|
||||
}
|
||||
type CommandMap map[CommandName]*Command
|
||||
|
||||
func NewCommand(name CommandName) *Command {
|
||||
return &Command{
|
||||
|
@ -49,3 +35,30 @@ func (c *Command) Desc(desc string) *Command {
|
|||
c.Description = desc
|
||||
return c
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -17,31 +17,26 @@ type Context struct {
|
|||
readingUpdate bool
|
||||
}
|
||||
|
||||
// Context for interaction inside groups.
|
||||
type GroupContext struct {
|
||||
*GroupSession
|
||||
B *Bot
|
||||
}
|
||||
|
||||
// Goroutie function to handle each user.
|
||||
func (c *Context) handleUpdateChan(updates chan *Update) {
|
||||
var act Action
|
||||
bot := c.B
|
||||
session := c.Session
|
||||
c.run(bot.Start, nil)
|
||||
beh := bot.behaviour
|
||||
c.run(beh.Start, nil)
|
||||
for u := range updates {
|
||||
screen := bot.Screens[session.CurrentScreenId]
|
||||
screen := bot.behaviour.Screens[session.CurrentScreenId]
|
||||
// The part is added to implement custom update handling.
|
||||
if u.Message != nil {
|
||||
var act Action
|
||||
if u.Message.IsCommand() && !c.readingUpdate {
|
||||
cmdName := CommandName(u.Message.Command())
|
||||
cmd, ok := bot.Behaviour.Commands[cmdName]
|
||||
cmd, ok := beh.Commands[cmdName]
|
||||
if ok {
|
||||
act = cmd.Action
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
kbd := bot.Keyboards[screen.KeyboardId]
|
||||
kbd := beh.Keyboards[screen.KeyboardId]
|
||||
btns := kbd.buttonMap()
|
||||
text := u.Message.Text
|
||||
btn, ok := btns[text]
|
||||
|
@ -65,10 +60,6 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
|||
act = btn.Action
|
||||
}
|
||||
}
|
||||
|
||||
if act != nil {
|
||||
c.run(act, u)
|
||||
}
|
||||
} else if u.CallbackQuery != nil {
|
||||
cb := apix.NewCallback(u.CallbackQuery.ID, u.CallbackQuery.Data)
|
||||
data := u.CallbackQuery.Data
|
||||
|
@ -77,49 +68,26 @@ func (c *Context) handleUpdateChan(updates chan *Update) {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
kbd := bot.Keyboards[screen.InlineKeyboardId]
|
||||
kbd := beh.Keyboards[screen.InlineKeyboardId]
|
||||
btns := kbd.buttonMap()
|
||||
btn, ok := btns[data]
|
||||
if !ok && c.readingUpdate {
|
||||
c.updates <- u
|
||||
continue
|
||||
}
|
||||
c.run(btn.Action, u)
|
||||
act = btn.Action
|
||||
}
|
||||
if act != nil {
|
||||
c.run(act, u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) run(a Action, u *Update) {
|
||||
go a.Act(&A{c, u})
|
||||
}
|
||||
|
||||
// Changes screen of user to the Id one.
|
||||
func (c *Arg) ChangeScreen(screenId ScreenId) error {
|
||||
// Return if it will not change anything.
|
||||
if c.CurrentScreenId == screenId {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !c.B.ScreenExist(screenId) {
|
||||
return ScreenNotExistErr
|
||||
}
|
||||
|
||||
// Stop the reading by sending the nil.
|
||||
if c.readingUpdate {
|
||||
c.updates <- nil
|
||||
}
|
||||
|
||||
screen := c.B.Screens[screenId]
|
||||
screen.Render(c.Context)
|
||||
|
||||
c.Session.ChangeScreen(screenId)
|
||||
c.KeyboardId = screen.KeyboardId
|
||||
|
||||
if screen.Action != nil {
|
||||
c.run(screen.Action, c.U)
|
||||
}
|
||||
|
||||
return nil
|
||||
go a.Act(&A{
|
||||
Context: c,
|
||||
U: u,
|
||||
})
|
||||
}
|
||||
|
||||
// Returns the next update ignoring current screen.
|
||||
|
@ -158,3 +126,56 @@ func (c *Context) Send(v ...any) error {
|
|||
func (c *Context) Sendf(format string, v ...any) error {
|
||||
return c.Send(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Context for interaction inside groups.
|
||||
type GroupContext struct {
|
||||
*GroupSession
|
||||
B *Bot
|
||||
updates chan *Update
|
||||
}
|
||||
|
||||
func (c *GroupContext) run(a GroupAction, u *Update) {
|
||||
go a.Act(&GA{
|
||||
GroupContext: c,
|
||||
Update: u,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *GroupContext) handleUpdateChan(updates chan *Update) {
|
||||
var act GroupAction
|
||||
beh := c.B.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.
|
||||
atName := msg.CommandWithAt()[len(cmdName)+1:]
|
||||
if c.B.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) error {
|
||||
return c.Send(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Sends into the chat specified values converted to strings.
|
||||
func (c *GroupContext) Send(v ...any) error {
|
||||
msg := apix.NewMessage(c.Id.ToTelegram(), fmt.Sprint(v...))
|
||||
_, err := c.B.Send(msg)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ func (s *Screen) Render(c *Context) error {
|
|||
msg := apix.NewMessage(id, s.Text.String())
|
||||
|
||||
if s.InlineKeyboardId != "" {
|
||||
kbd, ok := c.B.Keyboards[s.InlineKeyboardId]
|
||||
kbd, ok := c.B.behaviour.Keyboards[s.InlineKeyboardId]
|
||||
if !ok {
|
||||
return KeyboardNotExistErr
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ func (s *Screen) Render(c *Context) error {
|
|||
|
||||
// Replace keyboard with the new one.
|
||||
if s.KeyboardId != "" {
|
||||
kbd, ok := c.B.Keyboards[s.KeyboardId]
|
||||
kbd, ok := c.B.behaviour.Keyboards[s.KeyboardId]
|
||||
if !ok {
|
||||
return KeyboardNotExistErr
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@ package tx
|
|||
// In fact is simply ID of the chat.
|
||||
type SessionId int64
|
||||
|
||||
// Convert the SessionId to Telegram API's type.
|
||||
func (si SessionId) ToTelegram() int64 {
|
||||
return int64(si)
|
||||
}
|
||||
|
||||
// The type represents current state of
|
||||
// user interaction per each of them.
|
||||
type Session struct {
|
||||
|
@ -17,20 +22,6 @@ type Session struct {
|
|||
V any
|
||||
}
|
||||
|
||||
// The type represents map of sessions using
|
||||
// as key.
|
||||
type SessionMap map[SessionId]*Session
|
||||
|
||||
// Session information for a group.
|
||||
type GroupSession struct {
|
||||
Id SessionId
|
||||
// Information for each user in the group.
|
||||
V map[SessionId]any
|
||||
}
|
||||
|
||||
// Map for every user in every chat sessions.
|
||||
type GroupSessionMap map[SessionId]*GroupSession
|
||||
|
||||
// Return new empty session with specified user ID.
|
||||
func NewSession(id SessionId) *Session {
|
||||
return &Session{
|
||||
|
@ -39,6 +30,28 @@ func NewSession(id SessionId) *Session {
|
|||
}
|
||||
}
|
||||
|
||||
// Changes screen of user to the Id one for the session.
|
||||
func (c *Session) ChangeScreen(screenId ScreenId) {
|
||||
c.PreviousScreenId = c.CurrentScreenId
|
||||
c.CurrentScreenId = screenId
|
||||
}
|
||||
|
||||
// The type represents map of sessions using
|
||||
// as key.
|
||||
type SessionMap map[SessionId]*Session
|
||||
|
||||
// Add new empty session by it's ID.
|
||||
func (sm SessionMap) Add(sid SessionId) {
|
||||
sm[sid] = NewSession(sid)
|
||||
}
|
||||
|
||||
// Session information for a group.
|
||||
type GroupSession struct {
|
||||
Id SessionId
|
||||
// Information for each user in the group.
|
||||
V map[SessionId]any
|
||||
}
|
||||
|
||||
// Returns new empty group session with specified group and user IDs.
|
||||
func NewGroupSession(id SessionId) *GroupSession {
|
||||
return &GroupSession{
|
||||
|
@ -47,18 +60,9 @@ func NewGroupSession(id SessionId) *GroupSession {
|
|||
}
|
||||
}
|
||||
|
||||
// Changes screen of user to the Id one for the session.
|
||||
func (c *Session) ChangeScreen(screenId ScreenId) {
|
||||
c.PreviousScreenId = c.CurrentScreenId
|
||||
c.CurrentScreenId = screenId
|
||||
}
|
||||
// Map for every group the bot is in.
|
||||
type GroupSessionMap map[SessionId]*GroupSession
|
||||
|
||||
// Convert the SessionId to Telegram API's type.
|
||||
func (si SessionId) ToTelegram() int64 {
|
||||
return int64(si)
|
||||
}
|
||||
|
||||
// Add new empty session by it's ID.
|
||||
func (sm SessionMap) Add(sid SessionId) {
|
||||
sm[sid] = NewSession(sid)
|
||||
func (sm GroupSessionMap) Add(sid SessionId) {
|
||||
sm[sid] = NewGroupSession(sid)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue