diff --git a/cmd/test/main.go b/cmd/test/main.go index 917ea51..5257e83 100644 --- a/cmd/test/main.go +++ b/cmd/test/main.go @@ -84,8 +84,10 @@ var beh = tg.NewBehaviour(). WithInitFunc(func(c *tg.Context) { // The session initialization. c.Session.Value = &UserData{} - c.ChangeScreen("start") + }). // On any message update before the bot created session. + WithPreStartFunc(func(c *tg.Context){ + c.Send("Please, use the /start command to start the bot") }).WithScreens( tg.NewScreen("start"). WithText( @@ -141,6 +143,11 @@ var beh = tg.NewBehaviour(). ), ), ).WithCommands( + tg.NewCommand("start"). + Desc("start the bot"). + ActionFunc(func(c *tg.Context){ + c.ChangeScreen("start") + }), tg.NewCommand("hello"). Desc("sends the 'Hello, World!' message back"). ActionFunc(func(c *tg.Context) { diff --git a/media/bot.png b/media/bot.png new file mode 100644 index 0000000..10968bd Binary files /dev/null and b/media/bot.png differ diff --git a/tg/beh.go b/tg/beh.go index 192baef..f34c18e 100644 --- a/tg/beh.go +++ b/tg/beh.go @@ -5,6 +5,7 @@ package tg // The type describes behaviour for the bot in personal chats. type Behaviour struct { + PreStart *action Init *action Screens ScreenMap Keyboards KeyboardMap @@ -27,12 +28,27 @@ func (b *Behaviour) WithInit(a Action) *Behaviour { return b } +// Alias to WithInit to simplify behaviour definitions. func (b *Behaviour) WithInitFunc( fn ActionFunc, ) *Behaviour { return b.WithInit(fn) } +// Defines pre-start action. +// E. g. when the user has not type the "/start" command. +// Mostly used to send the "/start" command back +// with some warning. +func (b *Behaviour) WithPreStart(a Action) *Behaviour { + b.PreStart = newAction(a) + return b +} + +// Alias for WithPreStart to be used with function inside. +func (b *Behaviour) WithPreStartFunc(fn ActionFunc) *Behaviour { + return b.WithPreStart(fn) +} + // The function sets screens. func (b *Behaviour) WithScreens( screens ...*Screen, diff --git a/tg/bot.go b/tg/bot.go index e158340..fcb25e5 100644 --- a/tg/bot.go +++ b/tg/bot.go @@ -168,6 +168,9 @@ func (bot *Bot) handlePrivate(updates chan *Update) { session, sessionOk := bot.sessions[sid] chn, chnOk := chans[sid] if sessionOk { + // Creating new goroutine for + // the session that exists + // but has none. if !chnOk { ctx := &context{ Bot: bot, @@ -178,21 +181,19 @@ func (bot *Bot) handlePrivate(updates chan *Update) { chans[sid] = chn go ctx.handleUpdateChan(chn) } - } else { - if u.Message != nil && u.Message.Command() == "start" { - if !sessionOk { - bot.sessions.Add(sid) - } - lsession := bot.sessions[sid] - ctx := &context{ - Bot: bot, - Session: lsession, - updates: make(chan *Update), - } - chn := make(chan *Update) - chans[sid] = chn - go ctx.handleUpdateChan(chn) + } else if u.Message != nil { + // Create session on any message + // if we have no one. + bot.sessions.Add(sid) + lsession := bot.sessions[sid] + ctx := &context{ + Bot: bot, + Session: lsession, + updates: make(chan *Update), } + chn := make(chan *Update) + chans[sid] = chn + go ctx.handleUpdateChan(chn) } chn, ok := chans[sid] diff --git a/tg/private.go b/tg/private.go index 96ec730..8f6beae 100644 --- a/tg/private.go +++ b/tg/private.go @@ -23,6 +23,8 @@ type context struct { func (c *context) handleUpdateChan(updates chan *Update) { beh := c.Bot.behaviour + session := c.Session + preStart := beh.PreStart if beh.Init != nil { c.run(beh.Init, nil) } @@ -31,14 +33,34 @@ func (c *context) handleUpdateChan(updates chan *Update) { screen := c.curScreen // The part is added to implement custom update handling. if u.Message != nil { - if u.Message.IsCommand() && !c.readingUpdate { + if !session.Started { + if u.Message.IsCommand() && + u.Message.Command() == "start" { + // Special treatment for the "/start" + // command. + session.Started = true + cmdName := CommandName("start") + cmd, ok := beh.Commands[cmdName] + if ok { + act = cmd.Action + } else { + // Some usage. + } + } else { + // Prestart handling. + act = preStart + } + } else if u.Message.IsCommand() { + // Command handling. cmdName := CommandName(u.Message.Command()) cmd, ok := beh.Commands[cmdName] if ok { act = cmd.Action } else { + // Some usage. } } else { + // Simple messages handling. kbd := screen.Keyboard if kbd == nil { if c.readingUpdate { @@ -69,7 +91,7 @@ func (c *context) handleUpdateChan(updates chan *Update) { act = btn.Action } } - } else if u.CallbackQuery != nil { + } else if u.CallbackQuery != nil && session.Started { cb := tgbotapi.NewCallback( u.CallbackQuery.ID, u.CallbackQuery.Data, diff --git a/tg/session.go b/tg/session.go index 5161376..31be1f4 100644 --- a/tg/session.go +++ b/tg/session.go @@ -14,6 +14,9 @@ func (si SessionId) ToApi() int64 { type Session struct { // Id of the chat of the user. Id SessionId + // True if the session started. + // (got the '/start' command. + Started bool // Custom value for each user. Value any }