Request Flow
This document details how Telegram updates flow through Alita Robot, from reception to response.
Update Processing Pipeline
Section titled “Update Processing Pipeline”+-------------+ +----------------+ +------------+ +----------+| Telegram | --> | HTTP/Polling | --> | Dispatcher | --> | Handlers || Bot API | | Receiver | | (Router) | | (Modules)|+-------------+ +----------------+ +------------+ +----------+ | | | v | +------+------+ | | Permission | | | Checks | | +------+------+ | | | v | +------+------+ | | Database | | | / Cache | | +------+------+ | | v v +----------+ +----------+ | Error | | Response | | Handler | | to User | +----------+ +----------+Initialization Sequence
Section titled “Initialization Sequence”When the bot starts (main.go), it performs these steps in order:
1. Health Check Mode (Optional)
Section titled “1. Health Check Mode (Optional)”if os.Args[1] == "--health" { // HTTP GET to /health, exit with status code os.Exit(0)}2. Panic Recovery Setup
Section titled “2. Panic Recovery Setup”defer func() { if r := recover(); r != nil { log.Errorf("[Main] Panic recovered: %v", r) os.Exit(1) }}()3. Locale Manager Initialization
Section titled “3. Locale Manager Initialization”localeManager := i18n.GetManager()localeManager.Initialize(&Locales, "locales", i18n.DefaultManagerConfig())4. Sentry Initialization (If Enabled)
Section titled “4. Sentry Initialization (If Enabled)”if config.AppConfig.EnableSentry { sentry.Init(sentry.ClientOptions{ Dsn: config.AppConfig.SentryDSN, Environment: config.AppConfig.SentryEnvironment, // ... })}5. HTTP Transport Configuration
Section titled “5. HTTP Transport Configuration”httpTransport := &http.Transport{ MaxIdleConns: config.AppConfig.HTTPMaxIdleConns, MaxIdleConnsPerHost: config.AppConfig.HTTPMaxIdleConnsPerHost, IdleConnTimeout: 120 * time.Second, ForceAttemptHTTP2: true,}6. Bot Client Creation
Section titled “6. Bot Client Creation”b, err := gotgbot.NewBot(config.AppConfig.BotToken, &gotgbot.BotOpts{ BotClient: &gotgbot.BaseBotClient{ Client: http.Client{Transport: transport, Timeout: 30 * time.Second}, },})7. Connection Pre-warming
Section titled “7. Connection Pre-warming”go func() { for i := 0; i < 3; i++ { b.GetMe(nil) // Establish connection pool time.Sleep(100 * time.Millisecond) }}()8. Initial Checks
Section titled “8. Initial Checks”alita.InitialChecks(b) // Validates config, initializes cache9. Async Processor (If Enabled)
Section titled “9. Async Processor (If Enabled)”if config.AppConfig.EnableAsyncProcessing { async.InitializeAsyncProcessor()}10. Dispatcher Creation
Section titled “10. Dispatcher Creation”dispatcher := ext.NewDispatcher(&ext.DispatcherOpts{ Error: errorHandler, MaxRoutines: config.AppConfig.DispatcherMaxRoutines,})11. Monitoring Systems
Section titled “11. Monitoring Systems”statsCollector = monitoring.NewBackgroundStatsCollector()autoRemediation = monitoring.NewAutoRemediationManager(statsCollector)activityMonitor = monitoring.NewActivityMonitor()12. HTTP Server & Mode Selection
Section titled “12. HTTP Server & Mode Selection”httpServer := httpserver.New(config.AppConfig.HTTPPort)httpServer.RegisterHealth()httpServer.RegisterMetrics()
if config.AppConfig.UseWebhooks { httpServer.RegisterWebhook(b, dispatcher, secret, domain)} else { updater.StartPolling(b, pollingOpts)}Module Loading Order
Section titled “Module Loading Order”After dispatcher creation, modules are loaded via alita/main.go:
func LoadModules(dispatcher *ext.Dispatcher) { // Initialize help system first modules.HelpModule.AbleMap.Init()
// Load help LAST (deferred) to collect all commands defer modules.LoadHelp(dispatcher)
// Core modules (order matters for handler priority) modules.LoadBotUpdates(dispatcher) // Bot status tracking modules.LoadAntispam(dispatcher) // Spam protection modules.LoadLanguage(dispatcher) // Language settings modules.LoadAdmin(dispatcher) // Admin commands modules.LoadPin(dispatcher) // Pin management modules.LoadMisc(dispatcher) // Misc utilities modules.LoadBans(dispatcher) // Ban/kick commands modules.LoadMutes(dispatcher) // Mute commands modules.LoadPurges(dispatcher) // Message purging modules.LoadUsers(dispatcher) // User tracking modules.LoadReports(dispatcher) // Report system modules.LoadDev(dispatcher) // Developer tools modules.LoadLocks(dispatcher) // Chat locks modules.LoadFilters(dispatcher) // Message filters modules.LoadAntiflood(dispatcher) // Flood protection modules.LoadNotes(dispatcher) // Notes system modules.LoadConnections(dispatcher) // Chat connections modules.LoadDisabling(dispatcher) // Command disabling modules.LoadRules(dispatcher) // Rules management modules.LoadWarns(dispatcher) // Warning system modules.LoadGreetings(dispatcher) // Welcome messages modules.LoadCaptcha(dispatcher) // CAPTCHA verification modules.LoadBlacklists(dispatcher) // Blacklist system modules.LoadMkdCmd(dispatcher) // Markdown commands}Handler Registration Pattern
Section titled “Handler Registration Pattern”Each module registers handlers using gotgbot’s handler system:
func LoadBans(dispatcher *ext.Dispatcher) { // Register module in help system HelpModule.AbleMap.Store(bansModule.moduleName, true)
// Command handlers dispatcher.AddHandler(handlers.NewCommand("ban", bansModule.ban)) dispatcher.AddHandler(handlers.NewCommand("kick", bansModule.kick)) dispatcher.AddHandler(handlers.NewCommand("unban", bansModule.unban))
// Callback query handlers dispatcher.AddHandler(handlers.NewCallback( callbackquery.Prefix("restrict."), bansModule.restrictButtonHandler, ))}Handler Types
Section titled “Handler Types”| Type | Registration | Trigger |
|---|---|---|
| Command | handlers.NewCommand("cmd", fn) | /cmd messages |
| Callback | handlers.NewCallback(filter, fn) | Button presses |
| Message | handlers.NewMessage(filter, fn) | Text messages |
| ChatMember | handlers.NewChatMemberUpdated(filter, fn) | Member updates |
Handler Groups
Section titled “Handler Groups”Handlers can be assigned to groups for priority control:
// Negative group = higher priority (runs first)dispatcher.AddHandlerToGroup(handler, -10)
// Group 0 = defaultdispatcher.AddHandler(handler) // Same as group 0
// Positive group = lower prioritydispatcher.AddHandlerToGroup(handler, 10)Permission Check Flow
Section titled “Permission Check Flow”Most admin commands follow this permission checking pattern:
func (m moduleStruct) ban(b *gotgbot.Bot, ctx *ext.Context) error { chat := ctx.EffectiveChat user := ctx.EffectiveSender.User msg := ctx.EffectiveMessage
// 1. Require group chat (not private) if !chat_status.RequireGroup(b, ctx, nil, false) { return ext.EndGroups }
// 2. Require user to be admin if !chat_status.RequireUserAdmin(b, ctx, nil, user.Id, false) { return ext.EndGroups }
// 3. Require bot to be admin if !chat_status.RequireBotAdmin(b, ctx, nil, false) { return ext.EndGroups }
// 4. Check specific permission (restrict members) if !chat_status.CanUserRestrict(b, ctx, nil, user.Id, false) { return ext.EndGroups }
// 5. Check bot has same permission if !chat_status.CanBotRestrict(b, ctx, nil, false) { return ext.EndGroups }
// Proceed with ban logic...}Permission Functions Reference
Section titled “Permission Functions Reference”| Function | Purpose | When to Use |
|---|---|---|
RequireGroup | Ensures chat is group/supergroup | Group-only commands |
RequirePrivate | Ensures chat is private | PM-only commands |
RequireUserAdmin | User must be admin | Admin commands |
RequireBotAdmin | Bot must be admin | Commands needing bot admin |
RequireUserOwner | User must be creator | Owner-only commands |
CanUserRestrict | User can ban/mute | Ban/mute commands |
CanBotRestrict | Bot can ban/mute | Ban/mute commands |
CanUserDelete | User can delete messages | Purge commands |
CanBotDelete | Bot can delete messages | Purge commands |
CanUserPin | User can pin messages | Pin commands |
CanBotPin | Bot can pin messages | Pin commands |
CanUserPromote | User can promote/demote | Admin management |
CanBotPromote | Bot can promote/demote | Admin management |
IsUserAdmin | Check if user is admin | Conditional logic |
IsUserInChat | Check if user is member | User validation |
IsUserBanProtected | Check if user is protected | Before ban/kick |
Response Patterns
Section titled “Response Patterns”Handler Return Values
Section titled “Handler Return Values”// Stop processing, no more handlers runreturn ext.EndGroups
// Continue to next handler in same groupreturn ext.ContinueGroups
// Error propagates to dispatcher error handlerreturn errResponse Actions
Section titled “Response Actions”// Reply to the triggering messagemsg.Reply(b, "Response text", &gotgbot.SendMessageOpts{ ParseMode: helpers.HTML,})
// Send new message to chatb.SendMessage(chat.Id, "Message text", nil)
// Edit existing messagemsg.EditText(b, "New text", nil)
// Delete messagemsg.Delete(b, nil)
// Answer callback queryquery.Answer(b, &gotgbot.AnswerCallbackQueryOpts{ Text: "Notification text",})Async Processing
Section titled “Async Processing”Non-critical operations can be processed asynchronously:
// Fire and forget (with panic recovery)go func() { defer func() { if r := recover(); r != nil { log.Error("Panic in async operation") } }()
// Async work here}()
// With timeout protectiongo func() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel()
select { case <-time.After(2 * time.Second): // Do delayed work case <-ctx.Done(): log.Warn("Operation timed out") }}()Error Handling in Request Flow
Section titled “Error Handling in Request Flow”Dispatcher Error Handler
Section titled “Dispatcher Error Handler”Error: func(b *gotgbot.Bot, ctx *ext.Context, err error) ext.DispatcherAction { // 1. Recover from panics defer error_handling.RecoverFromPanic("DispatcherErrorHandler", "Main")
// 2. Extract context for logging logFields := log.Fields{ "update_id": ctx.UpdateId, "error_type": fmt.Sprintf("%T", err), }
// 3. Check for expected/suppressible errors if helpers.ShouldSuppressFromSentry(err) { log.WithFields(logFields).Warn("Expected error (suppressed)") return ext.DispatcherActionNoop }
// 4. Log and report to Sentry log.WithFields(logFields).Error("Handler error") sentry.CaptureException(err)
// 5. Continue processing other updates return ext.DispatcherActionNoop}Common Error Patterns
Section titled “Common Error Patterns”// Log and return error (propagates to dispatcher)if err != nil { log.Error(err) return err}
// Log but continue (non-fatal)if err != nil { log.Warn("Non-fatal error:", err)}
// Silent failure for expected cases_, _ = msg.Delete(b, nil) // Ignore delete errorsNext Steps
Section titled “Next Steps”- Module Pattern - Creating new feature modules
- Caching - Redis cache integration
- Project Structure - File organization