Simplified behaviour definition functions.

This commit is contained in:
Andrey Parhomenko 2023-08-10 15:49:25 +03:00
parent 03a2f60436
commit fbfa0ec388
15 changed files with 297 additions and 268 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
exe exe
*.exe *.exe
*.swp *.swp
tmp

View file

@ -1,111 +1,65 @@
package main package main
import ( import (
"log" "log"
"os" "os"
//tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/mojosa-software/got/src/tx"
"boteval/src/behx"
) )
var rootKbd = behx.NewKeyboard( var navKeyboard = tx.NewKeyboard("nav").Row(
behx.NewButtonRow( tx.NewButton().WithText("Inc/Dec").ScreenChange("inc/dec"),
behx.NewButton( ).Row(
"Increment", tx.NewButton().WithText("Upper case").ScreenChange("upper-case"),
behx.NewCustomAction(func(c *behx.Context){ tx.NewButton().WithText("Lower case").ScreenChange("lower-case"),
counter := c.V["counter"].(*int)
*counter++
c.Sendf("%d", *counter)
}),
),
behx.NewButton(
"Decrement",
behx.NewCustomAction(func(c *behx.Context){
counter := c.V["counter"].(*int)
*counter--
c.Sendf("%d", *counter)
}),
),
),
behx.NewButtonRow(
behx.NewButton("To second screen", behx.NewScreenChange("second")),
),
) )
var secondKbd = behx.NewKeyboard( var incKeyboard = tx.NewKeyboard("inc/dec").Row(
behx.NewButtonRow( tx.NewButton().WithText("+").ActionFunc(func(c *tx.Context) {
behx.NewButton( counter := c.V["counter"].(*int)
"❤", *counter++
behx.NewScreenChange("start"), c.Sendf("%d", *counter)
),
),
)
var inlineKbd = behx.NewKeyboard(
behx.NewButtonRow(
behx.NewButton(
"INLINE PRESS ME",
behx.NewCustomAction(func(c *behx.Context){
log.Println("INLINE pressed the button!")
}),
),
behx.NewButton("INLINE PRESS ME 2", behx.NewCustomAction(func(c *behx.Context){
log.Println("INLINE pressed another button!")
})),
),
behx.NewButtonRow(
behx.NewButton(
"INLINE PRESS ME 3",
behx.ScreenChange("second"),
),
),
)
var startScreen = behx.NewScreen(
"Hello, World!",
"inline",
"root",
)
var secondScreen = behx.NewScreen(
"Second screen!",
"",
"second",
)
var behaviour = behx.NewBehaviour(
behx.NewCustomAction(func(c *behx.Context){
// This way we provide counter for EACH user.
c.V["counter"] = new(int)
// Do NOT forget to change to some of the screens
// since they are the ones who provide behaviour
// definition.
c.ChangeScreen("start")
}), }),
behx.ScreenMap{ tx.NewButton().WithText("-").ActionFunc(func(c *tx.Context) {
"start": startScreen, counter := c.V["counter"].(*int)
"second": secondScreen, *counter--
}, c.Sendf("%d", *counter)
behx.KeyboardMap{ }),
"root": rootKbd, )
"inline": inlineKbd,
"second": secondKbd, var startScreen = tx.NewScreen("start").
}, WithText("The bot started!").
Keyboard("nav")
var incScreen = tx.NewScreen("inc/dec").
WithText("The screen shows how user separated data works").
IKeyboard("inc/dec").
Keyboard("nav")
var beh = tx.NewBehaviour().
OnStartFunc(func(c *tx.Context) {
// The function will be called every time
// the bot is started.
c.V["counter"] = new(int)
c.ChangeScreen("start")
}).WithKeyboards(
navKeyboard,
incKeyboard,
).WithScreens(
startScreen,
incScreen,
) )
func main() { func main() {
token := os.Getenv("BOT_TOKEN") token := os.Getenv("BOT_TOKEN")
bot, err := behx.NewBot(token, behaviour, nil)
if err != nil {
log.Panic(err)
}
bot.Debug = true bot, err := tx.NewBot(token, beh, nil)
if err != nil {
log.Panic(err)
}
log.Printf("Authorized on account %s", bot.Self.UserName) bot.Debug = true
bot.Run()
log.Printf("Authorized on account %s", bot.Self.UserName)
bot.Run()
} }

2
go.mod
View file

@ -1,4 +1,4 @@
module boteval module github.com/mojosa-software/got
go 1.20 go 1.20

View file

@ -1,39 +0,0 @@
package behx
// The package implements
// behaviour for the Telegram bots.
// The type describes behaviour for the bot.
type Behaviour struct {
Start Action
Screens ScreenMap
Keyboards KeyboardMap
}
func NewBehaviour(
start Action,
screens ScreenMap,
keyboards KeyboardMap,
) *Behaviour {
return &Behaviour{
start, screens, keyboards,
}
}
// Check whether the screen exists in the behaviour.
func (beh *Behaviour) ScreenExists(id ScreenId) bool {
_, ok := beh.Screens[id]
return ok
}
// Returns the screen by it's ID.
func (beh *Behaviour) GetScreen(id ScreenId) *Screen {
if !beh.ScreenExists(id) {
panic(ScreenNotExistErr)
}
screen := beh.Screens[id]
return screen
}

View file

@ -1,13 +0,0 @@
package behx
import (
"errors"
)
var (
ScreenNotExistErr = errors.New("screen does not exist")
SessionNotExistErr = errors.New("session does not exist")
KeyboardNotExistErr = errors.New("keyboard does not exist")
)

View file

@ -1,4 +1,4 @@
package behx package tx
// Implementing the intereface lets you // Implementing the intereface lets you
// provide behaviour for the buttons etc. // provide behaviour for the buttons etc.
@ -7,29 +7,21 @@ type Action interface {
} }
// Customized action for the bot. // Customized action for the bot.
type CustomAction func(*Context) type ActionFunc func(*Context)
// The type implements changing screen to the underlying ScreenId // The type implements changing screen to the underlying ScreenId
type ScreenChange ScreenId type ScreenChange ScreenId
// Returns new ScreenChange.
func NewScreenChange(screen string) ScreenChange {
return ScreenChange(screen)
}
// Returns new CustomAction.
func NewCustomAction(fn func(*Context)) CustomAction {
return CustomAction(fn)
}
func (sc ScreenChange) Act(c *Context) { func (sc ScreenChange) Act(c *Context) {
if !c.B.ScreenExist(ScreenId(sc)) {
panic(ScreenNotExistErr)
}
err := c.ChangeScreen(ScreenId(sc)) err := c.ChangeScreen(ScreenId(sc))
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
func (ca CustomAction) Act(c *Context) { func (af ActionFunc) Act(c *Context) {
ca(c) af(c)
} }

86
src/tx/beh.go Normal file
View file

@ -0,0 +1,86 @@
package tx
// The package implements
// behaviour for the Telegram bots.
// The type describes behaviour for the bot.
type Behaviour struct {
Start Action
Screens ScreenMap
Keyboards KeyboardMap
}
// Returns new empty behaviour.
func NewBehaviour() *Behaviour {
return &Behaviour{
Screens: make(ScreenMap),
Keyboards: make(KeyboardMap),
}
}
func (b *Behaviour) WithStart(a Action) *Behaviour {
b.Start = a
return b
}
func (b *Behaviour) OnStartFunc(
fn ActionFunc,
) *Behaviour {
return b.WithStart(fn)
}
func (b *Behaviour) OnStartChangeScreen(
id ScreenId,
) *Behaviour {
return b.WithStart(ScreenChange(id))
}
// The function sets keyboards.
func (b *Behaviour) WithKeyboards(
kbds ...*Keyboard,
) *Behaviour {
for _, kbd := range kbds {
if kbd.Id == "" {
panic("empty keyboard ID")
}
_, ok := b.Keyboards[kbd.Id]
if ok {
panic("duplicate keyboard IDs")
}
b.Keyboards[kbd.Id] = kbd
}
return b
}
// The function sets screens.
func (b *Behaviour) WithScreens(
screens ...*Screen,
) *Behaviour {
for _, screen := range screens {
if screen.Id == "" {
panic("empty screen ID")
}
_, ok := b.Screens[screen.Id]
if ok {
panic("duplicate keyboard IDs")
}
b.Screens[screen.Id] = screen
}
return b
}
// Check whether the screen exists in the behaviour.
func (beh *Behaviour) ScreenExist(id ScreenId) bool {
_, ok := beh.Screens[id]
return ok
}
// Returns the screen by it's ID.
func (beh *Behaviour) GetScreen(id ScreenId) *Screen {
if !beh.ScreenExist(id) {
panic(ScreenNotExistErr)
}
screen := beh.Screens[id]
return screen
}

View file

@ -1,8 +1,8 @@
package behx package tx
import ( import (
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5" apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
//"log" //"log"
) )
// The wrapper around Telegram API. // The wrapper around Telegram API.
@ -14,45 +14,43 @@ type Bot struct {
// Return the new bot for running the Behaviour. // Return the new bot for running the Behaviour.
func NewBot(token string, beh *Behaviour, sessions SessionMap) (*Bot, error) { func NewBot(token string, beh *Behaviour, sessions SessionMap) (*Bot, error) {
bot, err := apix.NewBotAPI(token) bot, err := apix.NewBotAPI(token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Make new sessions if no current are provided. // Make new sessions if no current are provided.
if sessions == nil { if sessions == nil {
sessions = make(SessionMap) sessions = make(SessionMap)
} }
return &Bot{ return &Bot{
BotAPI: bot, BotAPI: bot,
Behaviour: beh, Behaviour: beh,
sessions: make(SessionMap), sessions: make(SessionMap),
}, nil
}, nil
} }
// Run the bot with the Behaviour. // Run the bot with the Behaviour.
func (bot *Bot) Run() error { func (bot *Bot) Run() error {
bot.Debug = true bot.Debug = true
uc := apix.NewUpdate(0) uc := apix.NewUpdate(0)
uc.Timeout = 60 uc.Timeout = 60
updates := bot.GetUpdatesChan(uc) updates := bot.GetUpdatesChan(uc)
chans := make(map[SessionId] chan *Update) chans := make(map[SessionId]chan *Update)
for u := range updates { for u := range updates {
var sid SessionId var sid SessionId
if u.Message != nil { if u.Message != nil {
// Create new session if the one does not exist // Create new session if the one does not exist
// for this user. // for this user.
sid = SessionId(u.Message.Chat.ID) sid = SessionId(u.Message.Chat.ID)
if _, ok := bot.sessions[sid] ; !ok { if _, ok := bot.sessions[sid]; !ok {
bot.sessions.Add(sid) bot.sessions.Add(sid)
} }
// The "start" command resets the bot // The "start" command resets the bot
// by executing the Start Action. // by executing the Start Action.
if u.Message.IsCommand() { if u.Message.IsCommand() {
@ -61,10 +59,10 @@ func (bot *Bot) Run() error {
// Getting current session and context. // Getting current session and context.
session := bot.sessions[sid] session := bot.sessions[sid]
ctx := &Context{ ctx := &Context{
B: bot, B: bot,
Session: session, Session: session,
} }
chn := make(chan *Update) chn := make(chan *Update)
chans[sid] = chn chans[sid] = chn
// Starting the goroutine for the user. // Starting the goroutine for the user.
@ -80,7 +78,6 @@ func (bot *Bot) Run() error {
chn <- &u chn <- &u
} }
} }
return nil return nil
} }

View file

@ -1,42 +1,62 @@
package behx package tx
import ( import (
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5" apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
) )
// The type wraps Telegram API's button to provide Action functionality. // The type wraps Telegram API's button to provide Action functionality.
type Button struct { type Button struct {
Text string Text string
Data string Data string
Url string Url string
Action Action Action Action
} }
type ButtonMap map[string] *Button type ButtonMap map[string]*Button
// Represents the reply button row. // Represents the reply button row.
type ButtonRow []*Button type ButtonRow []*Button
// Returns new button with specified text and action. // Returns new button with specified text and action.
func NewButton(text string, action Action) *Button { func NewButton() *Button {
return &Button{ return &Button{}
Text: text, }
Action: action,
} func (btn *Button) WithText(text string) *Button {
btn.Text = text
return btn
}
func (btn *Button) WithUrl(url string) *Button {
btn.Url = url
return btn
}
func (btn *Button) WithAction(a Action) *Button {
btn.Action = a
return btn
}
func (btn *Button) ActionFunc(fn ActionFunc) *Button {
return btn.WithAction(fn)
}
func (btn *Button) ScreenChange(sc ScreenChange) *Button {
return btn.WithAction(sc)
} }
func NewButtonData(text string, data string, action Action) *Button { func NewButtonData(text string, data string, action Action) *Button {
return &Button{ return &Button{
Text: text, Text: text,
Data: data, Data: data,
Action: action, Action: action,
} }
} }
func NewButtonUrl(text string, url string, action Action) *Button { func NewButtonUrl(text string, url string, action Action) *Button {
return &Button{ return &Button{
Text: text, Text: text,
Url: url, Url: url,
Action: action, Action: action,
} }
} }
@ -49,11 +69,11 @@ func (btn *Button) ToTelegramInline() apix.InlineKeyboardButton {
if btn.Data != "" { if btn.Data != "" {
return apix.NewInlineKeyboardButtonData(btn.Text, btn.Data) return apix.NewInlineKeyboardButtonData(btn.Text, btn.Data)
} }
if btn.Url != "" { if btn.Url != "" {
return apix.NewInlineKeyboardButtonURL(btn.Text, btn.Url) return apix.NewInlineKeyboardButtonURL(btn.Text, btn.Url)
} }
// If no match then return the data one with data the same as the text. // If no match then return the data one with data the same as the text.
return apix.NewInlineKeyboardButtonData(btn.Text, btn.Text) return apix.NewInlineKeyboardButtonData(btn.Text, btn.Text)
} }
@ -63,7 +83,7 @@ func (btn *Button) Key() string {
if btn.Data != "" { if btn.Data != "" {
return btn.Data return btn.Data
} }
// If no match then return the data one with data the same as the text. // If no match then return the data one with data the same as the text.
return btn.Text return btn.Text
} }
@ -71,4 +91,3 @@ func (btn *Button) Key() string {
func NewButtonRow(btns ...*Button) ButtonRow { func NewButtonRow(btns ...*Button) ButtonRow {
return btns return btns
} }

View file

@ -1,8 +1,9 @@
package behx package tx
import ( import (
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"fmt" "fmt"
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
) )
// The type represents way to interact with user in // The type represents way to interact with user in
@ -19,24 +20,24 @@ func (ctx *Context) handleUpdateChan(updates chan *Update) {
bot.Start.Act(ctx) bot.Start.Act(ctx)
for u := range updates { for u := range updates {
screen := bot.Screens[session.CurrentScreenId] screen := bot.Screens[session.CurrentScreenId]
if u.Message != nil { if u.Message != nil {
kbd := bot.Keyboards[screen.KeyboardId] kbd := bot.Keyboards[screen.KeyboardId]
btns := kbd.buttonMap() btns := kbd.buttonMap()
text := u.Message.Text text := u.Message.Text
btn, ok := btns[text] btn, ok := btns[text]
// Skipping wrong text messages. // Skipping wrong text messages.
if !ok { if !ok {
continue continue
} }
btn.Action.Act(ctx) btn.Action.Act(ctx)
} else if u.CallbackQuery != nil { } else if u.CallbackQuery != nil {
cb := apix.NewCallback(u.CallbackQuery.ID, u.CallbackQuery.Data) cb := apix.NewCallback(u.CallbackQuery.ID, u.CallbackQuery.Data)
data := u.CallbackQuery.Data data := u.CallbackQuery.Data
_, err := bot.Request(cb) _, err := bot.Request(cb)
if err != nil { if err != nil {
panic(err) panic(err)
@ -55,17 +56,17 @@ func (c *Context) ChangeScreen(screenId ScreenId) error {
if c.CurrentScreenId == screenId { if c.CurrentScreenId == screenId {
return nil return nil
} }
if !c.B.ScreenExists(screenId) { if !c.B.ScreenExist(screenId) {
return ScreenNotExistErr return ScreenNotExistErr
} }
screen := c.B.Screens[screenId] screen := c.B.Screens[screenId]
screen.Render(c) screen.Render(c)
c.Session.ChangeScreen(screenId) c.Session.ChangeScreen(screenId)
c.KeyboardId = screen.KeyboardId c.KeyboardId = screen.KeyboardId
return nil return nil
} }
@ -79,4 +80,3 @@ func (c *Context) Send(text string) error {
func (c *Context) Sendf(format string, v ...any) error { func (c *Context) Sendf(format string, v ...any) error {
return c.Send(fmt.Sprintf(format, v...)) return c.Send(fmt.Sprintf(format, v...))
} }

11
src/tx/errors.go Normal file
View file

@ -0,0 +1,11 @@
package tx
import (
"errors"
)
var (
ScreenNotExistErr = errors.New("screen does not exist")
SessionNotExistErr = errors.New("session does not exist")
KeyboardNotExistErr = errors.New("keyboard does not exist")
)

View file

@ -1,8 +1,9 @@
package behx package tx
import ( import (
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5" apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
) )
/* /*
var otherKeyboard = tgbotapi.NewReplyKeyboard( var otherKeyboard = tgbotapi.NewReplyKeyboard(
tgbotapi.NewKeyboardButtonRow( tgbotapi.NewKeyboardButtonRow(
@ -22,20 +23,27 @@ type KeyboardId string
// The type represents reply keyboard which // The type represents reply keyboard which
// is supposed to be showed on a Screen. // is supposed to be showed on a Screen.
type Keyboard struct { type Keyboard struct {
Id KeyboardId
Rows []ButtonRow Rows []ButtonRow
} }
type KeyboardMap map[KeyboardId] *Keyboard type KeyboardMap map[KeyboardId]*Keyboard
// Return the new reply keyboard with rows as specified. // Return the new reply keyboard with rows as specified.
func NewKeyboard(rows ...ButtonRow) *Keyboard { func NewKeyboard(id KeyboardId) *Keyboard {
return &Keyboard{ return &Keyboard{
Rows: rows, Id: id,
} }
} }
// Adds a new button row to the current keyboard.
func (kbd *Keyboard) Row(btns ...*Button) *Keyboard {
kbd.Rows = append(kbd.Rows, btns)
return kbd
}
// Convert the Keyboard to the Telegram API type. // Convert the Keyboard to the Telegram API type.
func (kbd *Keyboard) ToTelegram() apix.ReplyKeyboardMarkup { func (kbd *Keyboard) toTelegram() apix.ReplyKeyboardMarkup {
rows := [][]apix.KeyboardButton{} rows := [][]apix.KeyboardButton{}
for _, row := range kbd.Rows { for _, row := range kbd.Rows {
buttons := []apix.KeyboardButton{} buttons := []apix.KeyboardButton{}
@ -43,12 +51,12 @@ func (kbd *Keyboard) ToTelegram() apix.ReplyKeyboardMarkup {
buttons = append(buttons, button.ToTelegram()) buttons = append(buttons, button.ToTelegram())
} }
rows = append(rows, buttons) rows = append(rows, buttons)
} }
return apix.NewReplyKeyboard(rows...) return apix.NewReplyKeyboard(rows...)
} }
func (kbd *Keyboard) ToTelegramInline() apix.InlineKeyboardMarkup { func (kbd *Keyboard) toTelegramInline() apix.InlineKeyboardMarkup {
rows := [][]apix.InlineKeyboardButton{} rows := [][]apix.InlineKeyboardButton{}
for _, row := range kbd.Rows { for _, row := range kbd.Rows {
buttons := []apix.InlineKeyboardButton{} buttons := []apix.InlineKeyboardButton{}
@ -56,8 +64,8 @@ func (kbd *Keyboard) ToTelegramInline() apix.InlineKeyboardMarkup {
buttons = append(buttons, button.ToTelegramInline()) buttons = append(buttons, button.ToTelegramInline())
} }
rows = append(rows, buttons) rows = append(rows, buttons)
} }
return apix.NewInlineKeyboardMarkup(rows...) return apix.NewInlineKeyboardMarkup(rows...)
} }
@ -69,7 +77,6 @@ func (kbd *Keyboard) buttonMap() ButtonMap {
ret[vj.Key()] = vj ret[vj.Key()] = vj
} }
} }
return ret return ret
} }

View file

@ -1,5 +1,4 @@
package behx package tx
// The package implements behaviourial // The package implements behaviourial
// definition for the Telegram bots through the API. // definition for the Telegram bots through the API.

View file

@ -1,4 +1,4 @@
package behx package tx
import ( import (
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5" apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
@ -14,28 +14,44 @@ type ScreenText string
// Screen statement of the bot. // Screen statement of the bot.
// Mostly what buttons to show. // Mostly what buttons to show.
type Screen struct { type Screen struct {
Id ScreenId
// Text to be sent to the user when changing to the screen. // Text to be sent to the user when changing to the screen.
Text ScreenText Text ScreenText
// The keyboard to be sent in the message part. // The keyboard to be sent in the message part.
InlineKeyboardId KeyboardId InlineKeyboardId KeyboardId
// Keyboard to be displayed on the screen. // Keyboard to be displayed on the screen.
KeyboardId KeyboardId KeyboardId KeyboardId
} }
// Map structure for the screens. // Map structure for the screens.
type ScreenMap map[ScreenId] *Screen type ScreenMap map[ScreenId]*Screen
// Returns the new screen with specified Text and Keyboard. // Returns the new screen with specified Text and Keyboard.
func NewScreen(text ScreenText, ikbd KeyboardId, kbd KeyboardId) *Screen { func NewScreen(id ScreenId) *Screen {
return &Screen { return &Screen{
Text: text, Id: id,
InlineKeyboardId: ikbd,
KeyboardId: kbd,
} }
} }
// Returns the screen with specified text printing on appearing.
func (s *Screen) WithText(text ScreenText) *Screen {
s.Text = text
return s
}
func (s *Screen) IKeyboard(kbdId KeyboardId) *Screen {
s.InlineKeyboardId = kbdId
return s
}
func (s *Screen) Keyboard(kbdId KeyboardId) *Screen {
s.KeyboardId = kbdId
return s
}
// Rendering the screen text to string to be sent or printed. // Rendering the screen text to string to be sent or printed.
func (st ScreenText) String() string { func (st ScreenText) String() string {
return string(st) return string(st)
@ -44,44 +60,43 @@ func (st ScreenText) String() string {
// Renders output of the screen only to the side of the user. // Renders output of the screen only to the side of the user.
func (s *Screen) Render(c *Context) error { func (s *Screen) Render(c *Context) error {
id := c.Id.ToTelegram() id := c.Id.ToTelegram()
msg := apix.NewMessage(id, s.Text.String()) msg := apix.NewMessage(id, s.Text.String())
if s.InlineKeyboardId != "" { if s.InlineKeyboardId != "" {
kbd, ok := c.B.Keyboards[s.InlineKeyboardId] kbd, ok := c.B.Keyboards[s.InlineKeyboardId]
if !ok { if !ok {
return KeyboardNotExistErr return KeyboardNotExistErr
} }
msg.ReplyMarkup = kbd.ToTelegramInline() msg.ReplyMarkup = kbd.toTelegramInline()
} }
_, err := c.B.Send(msg) _, err := c.B.Send(msg)
if err != nil { if err != nil {
return err return err
} }
msg = apix.NewMessage(id, ">") msg = apix.NewMessage(id, ">")
// Checking if we need to resend the keyboard. // Checking if we need to resend the keyboard.
if s.KeyboardId != c.KeyboardId { if s.KeyboardId != c.KeyboardId {
// Remove keyboard by default. // Remove keyboard by default.
var tkbd any var tkbd any
tkbd = apix.NewRemoveKeyboard(true) tkbd = apix.NewRemoveKeyboard(true)
// Replace keyboard with the new one. // Replace keyboard with the new one.
if s.KeyboardId != "" { if s.KeyboardId != "" {
kbd, ok := c.B.Keyboards[s.KeyboardId] kbd, ok := c.B.Keyboards[s.KeyboardId]
if !ok { if !ok {
return KeyboardNotExistErr return KeyboardNotExistErr
} }
tkbd = kbd.ToTelegram() tkbd = kbd.toTelegram()
} }
msg.ReplyMarkup = tkbd msg.ReplyMarkup = tkbd
if _, err := c.B.Send(msg) ; err != nil { if _, err := c.B.Send(msg); err != nil {
return err return err
} }
} }
return nil return nil
} }

View file

@ -1,4 +1,4 @@
package behx package tx
import ( import (
apix "github.com/go-telegram-bot-api/telegram-bot-api/v5" apix "github.com/go-telegram-bot-api/telegram-bot-api/v5"
@ -21,20 +21,20 @@ type Session struct {
PreviousScreenId ScreenId PreviousScreenId ScreenId
// The currently showed on display keyboard. // The currently showed on display keyboard.
KeyboardId KeyboardId KeyboardId KeyboardId
// Custom data for each user. // Custom data for each user.
V map[string] any V map[string]any
} }
// The type represents map of sessions using // The type represents map of sessions using
// as key. // as key.
type SessionMap map[SessionId] *Session type SessionMap map[SessionId]*Session
// Return new empty session with // Return new empty session with
func NewSession(id SessionId) *Session { func NewSession(id SessionId) *Session {
return &Session{ return &Session{
Id: id, Id: id,
V: make(map[string] any), V: make(map[string]any),
} }
} }