Files
lukaszraczylo 0ee539e991 perf(dispatch): typed Context.Command/CommandArgs/RegexMatch fields
Move the three conventional Values keys ("command", "command_args", "regex_match") to typed fields on Context. Router and group routing write the fields directly; the Values map is allocated lazily via the new Set method and reserved for user-defined custom keys.

Allocation impact (M4 Max, b.Loop()):

  DispatchCommand:   5 allocs/op -> 1, 153ns -> 69ns (-55%)

  DispatchTextRegex: 5 allocs/op -> 2, 181ns -> 107ns (-41%)

  DispatchFilter:    2 allocs/op -> 1, 32ns -> 19ns (-41%)

  NewContext:        5.79ns -> 1.60ns

Trade-off: Context struct grew from ~48B to ~96B (three new fields), so filter-only paths pay ~50B more per dispatch. Command/regex paths save ~320B + 4 allocs each, which dominates for typical bot workloads.

Handlers reading c.Values["command"], c.Values["command_args"], or c.Values["regex_match"] now get nil; the typed fields c.Command, c.CommandArgs, c.RegexMatch are the new accessors. Custom keys still work via c.Set(k, v) and c.Values[k].
2026-05-10 02:35:24 +01:00

76 lines
1.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"fmt"
"strconv"
"github.com/lukaszraczylo/go-telegram/api"
"github.com/lukaszraczylo/go-telegram/client"
"github.com/lukaszraczylo/go-telegram/dispatch"
)
// register wires all handlers onto the router.
func register(r *dispatch.Router) {
r.OnCommand("/start", handleStart)
r.OnCallback(`^count:(-?\d+):(inc|dec)$`, handleCallback)
}
func handleStart(c *dispatch.Context, m *api.Message) error {
return sendMenu(c.Ctx, c.Bot, m.Chat.ID, 0)
}
func handleCallback(c *dispatch.Context, q *api.CallbackQuery) error {
groups := c.RegexMatch
current, _ := strconv.Atoi(groups[1])
if groups[2] == "inc" {
current++
} else {
current--
}
// Acknowledge the callback (removes the loading spinner).
_, _ = api.AnswerCallbackQuery(c.Ctx, c.Bot, &api.AnswerCallbackQueryParams{
CallbackQueryID: q.ID,
Text: fmt.Sprintf("counter is now %d", current),
})
// Edit the message to reflect the new state.
if q.Message == nil {
return nil
}
msg, ok := q.Message.(*api.Message)
if !ok {
return nil
}
chatID := api.ChatIDFromInt(msg.Chat.ID)
mid := msg.MessageID
_, err := api.EditMessageText(c.Ctx, c.Bot, &api.EditMessageTextParams{
ChatID: &chatID,
MessageID: &mid,
Text: fmt.Sprintf("Counter: %d", current),
ReplyMarkup: counterKeyboard(current),
})
return err
}
func sendMenu(ctx context.Context, bot *client.Bot, chatID int64, value int) error {
_, err := api.SendMessage(ctx, bot, &api.SendMessageParams{
ChatID: api.ChatIDFromInt(chatID),
Text: fmt.Sprintf("Counter: %d", value),
ReplyMarkup: counterKeyboard(value),
})
return err
}
func counterKeyboard(value int) *api.InlineKeyboardMarkup {
return &api.InlineKeyboardMarkup{
InlineKeyboard: [][]api.InlineKeyboardButton{
{
{Text: "", CallbackData: fmt.Sprintf("count:%d:dec", value)},
{Text: "+", CallbackData: fmt.Sprintf("count:%d:inc", value)},
},
},
}
}