From ab1437a15bdac85d9f715e82c960910ddde426e8 Mon Sep 17 00:00:00 2001 From: surdeus Date: Wed, 17 Jan 2024 16:39:52 +0300 Subject: [PATCH] feat: got rid off runtime panics. --- bot.go | 12 +++++++++--- command.go | 5 ++++- context.go | 51 ++++++++++++++++++++++++++++----------------------- errors.go | 4 ++++ 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/bot.go b/bot.go index e53519d..ea93a16 100644 --- a/bot.go +++ b/bot.go @@ -3,9 +3,6 @@ package tg import ( "errors" "sort" - - //"fmt" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) @@ -66,6 +63,15 @@ func (bot *Bot) Send( return &msg, nil } +func (bot *Bot) Sendf( + sid SessionId, format string, v ...any, +) (*Message, error){ + return bot.Send( + sid, + NewMessage(format, v...), + ) +} + // Send to the session specified its ID raw chattable from the tgbotapi. func (bot *Bot) SendRaw( sid SessionId, v tgbotapi.Chattable, diff --git a/command.go b/command.go index b783327..859a182 100644 --- a/command.go +++ b/command.go @@ -170,7 +170,10 @@ func (compo *CommandCompo) Serve(c *Context) { c.WithUpdate(u).Run(cmd.Action) if cmd.Widget != nil { cmdUpdates.Close() - cmdUpdates = c.WithUpdate(u).RunWidget(cmd.Widget) + cmdUpdates, err = c.WithUpdate(u).RunWidget(cmd.Widget) + if err != nil { + continue + } } continue } diff --git a/context.go b/context.go index 5de40be..8dd4bed 100644 --- a/context.go +++ b/context.go @@ -224,21 +224,14 @@ func (c *Context) History() []Path { } // Changes screen of user to the Id one. -func (c *Context) Go(pth Path, args ...any) { +func (c *Context) Go(pth Path, args ...any) error { + var err error if pth == "" { c.pathHistory = []Path{} - return + return nil } var back bool if pth == "-" { - ln := len(c.pathHistory) - if ln <= 1 { - pth = "/" - } else { - pth = c.pathHistory[ln-2] - c.pathHistory = c.pathHistory[:ln-1] - back = true - } } // Getting the screen and changing to // then executing its widget. @@ -247,7 +240,7 @@ func (c *Context) Go(pth Path, args ...any) { } if !c.PathExist(pth) { - panic(ScreenNotExistErr) + return ScreenNotExistErr } if !back && c.Path() != pth { @@ -258,10 +251,15 @@ func (c *Context) Go(pth Path, args ...any) { screen := c.Bot.behaviour.Screens[pth] c.skippedUpdates.Close() if screen.Widget != nil { - c.skippedUpdates = c.RunWidget(screen.Widget, args...) + c.skippedUpdates, err = c.RunWidget(screen.Widget, args...) + if err != nil { + return err + } } else { - panic("no widget defined for the screen") + return NoWidgetForScreenErr } + + return nil } func (c *Context) PathExist(pth Path) bool { @@ -278,15 +276,15 @@ func (c *Context) makeArg(args []any) any { return arg } -func (c *Context) RunCompo(compo Component, args ...any) *UpdateChan { +func (c *Context) RunCompo(compo Component, args ...any) (*UpdateChan, error) { if compo == nil { - return nil + return nil, nil } s, ok := compo.(Sendable) if ok { msg, err := c.Send(s) if err != nil { - panic("could not send the message") + return nil, err } s.SetMessage(msg) } @@ -300,24 +298,31 @@ func (c *Context) RunCompo(compo Component, args ...any) *UpdateChan { // the channel is closed and close it by themselves. updates.Close() }() - return updates + return updates, nil } // Run widget in background returning the new input channel for it. -func (c *Context) RunWidget(widget Widget, args ...any) *UpdateChan { +func (c *Context) RunWidget(widget Widget, args ...any) (*UpdateChan, error) { + var err error if widget == nil { - return nil + return nil, EmptyWidgetErr } pth := c.Path() compos := widget.Render(c.WithArg(c.makeArg(args))) - // Leave if changed path. + // Leave if changed path or components are empty. if compos == nil || pth != c.Path() { - return nil + return nil, EmptyCompoErr } chns := make([]*UpdateChan, len(compos)) for i, compo := range compos { - chns[i] = c.RunCompo(compo, args...) + chns[i], err = c.RunCompo(compo, args...) + if err != nil { + for _, chn := range chns { + chn.Close() + } + return nil, err + } } ret := NewUpdateChan() @@ -350,7 +355,7 @@ func (c *Context) RunWidget(widget Widget, args ...any) *UpdateChan { } }() - return ret + return ret, nil } // Simple way to read strings for widgets. diff --git a/errors.go b/errors.go index 44a498a..8ed289c 100644 --- a/errors.go +++ b/errors.go @@ -19,6 +19,10 @@ var ( MapCollisionErr = errors.New("map collision occured") ContextNotExistErr = errors.New("the context does not exist") StatusCodeErr = errors.New("not success response status code") + NotSendErr = errors.New("could not send message") + NoWidgetForScreenErr = errors.New("no widget defined for the screen") + EmptyCompoErr = errors.New("empty component") + EmptyWidgetErr = errors.New("empty widget") ) func (wut WrongUpdateType) Error() string {