From beee616d9cf2786603bad25468fa8b4779d9f552 Mon Sep 17 00:00:00 2001 From: ScuroNeko Date: Wed, 20 May 2026 13:19:27 +0300 Subject: [PATCH] (doc): MessageContext rename, webhook casing, Runner API, v1.0.0 migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MsgContext → MessageContext across all pages - RunWebHookWithContext → RunWebhookWithContext (and CloseWebhook, BotWebhookOpts) across all pages - Runners.md + Runners-RU.md: replace Onetime/Timeout with Every/Async, rewrite examples - Migration.md: add v1.0.0 migration section covering all breaking changes --- Bot-Lifecycle-RU.md | 12 ++-- Bot-Lifecycle.md | 20 +++---- Commands-and-Plugins-RU.md | 14 ++--- Commands-and-Plugins.md | 20 +++---- Drafts-RU.md | 2 +- Drafts.md | 8 +-- Error-Handling-RU.md | 2 +- Error-Handling.md | 8 +-- Framework-Backlog-RU.md | 44 +++++++-------- Framework-Backlog.md | 44 +++++++-------- Getting-Started-RU.md | 14 ++--- Getting-Started.md | 16 +++--- Home-RU.md | 6 +- Home.md | 2 +- Inline-Keyboards-and-Payloads-RU.md | 2 +- Inline-Keyboards-and-Payloads.md | 8 +-- Localization.md | 10 ++-- Logging.md | 4 +- Middleware-RU.md | 8 +-- Middleware.md | 24 ++++---- Migration.md | 65 ++++++++++++++++++++- MsgContext-RU.md | 18 +++--- MsgContext.md | 32 +++++------ Policies-RU.md | 8 +-- Policies.md | 8 +-- Recipes.md | 18 +++--- Runners-RU.md | 66 ++++++++++++++++------ Runners.md | 88 +++++++++++++---------------- Scenes-RU.md | 12 ++-- Scenes.md | 12 ++-- Testing-Bots-with-Laniakea-RU.md | 6 +- Testing-Bots-with-Laniakea.md | 14 ++--- Update-Routing-Model-RU.md | 14 ++--- Update-Routing-Model.md | 12 ++-- Webhook-Runtime-RU.md | 28 ++++----- Webhook-Runtime.md | 28 ++++----- _Sidebar.md | 2 +- tgapi-Overview-RU.md | 8 +-- tgapi-Overview.md | 12 ++-- 39 files changed, 403 insertions(+), 316 deletions(-) diff --git a/Bot-Lifecycle-RU.md b/Bot-Lifecycle-RU.md index 9a663cb..dda4337 100644 --- a/Bot-Lifecycle-RU.md +++ b/Bot-Lifecycle-RU.md @@ -9,7 +9,7 @@ English version: [[Bot-Lifecycle]] 1. Собрать `BotOpts`. 2. Создать `Bot` через `NewBot[T](opts)`. 3. Полностью настроить бот: плагины, middleware, фоновые задачи, политику данных callback, l10n и app data. -4. Запустить через `Run()`, `RunWithContext(...)` или `RunWebHookWithContext(...)`. +4. Запустить через `Run()`, `RunWithContext(...)` или `RunWebhookWithContext(...)`. 5. Остановить выполнение через завершение runtime или отмену context. 6. Освободить локальные ресурсы через `Close()`. 7. Для следующего запуска создать новый `Bot`. @@ -66,7 +66,7 @@ English version: [[Bot-Lifecycle]] 1. Построение и настройка `Bot` после `NewBot[T](opts)`. 2. Снимок конфигурации плагина в `AddPlugins(...)`. -3. Фиксация bot-level конфигурации после первого `Run()`, `RunWithContext(...)` или `RunWebHookWithContext(...)`. +3. Фиксация bot-level конфигурации после первого `Run()`, `RunWithContext(...)` или `RunWebhookWithContext(...)`. Практически это значит: - структуру плагина нужно закончить до `AddPlugins(...)`; @@ -85,7 +85,7 @@ Laniakea предпочитает предсказуемый no-op вместо - путаницу в том, влияет ли изменение только на будущие update или ещё и на уже принятую работу; - разные ментальные модели для snapshot-поведения плагинов и bot-level состояния. -## `Run()`, `RunWithContext(...)` и `RunWebHookWithContext(...)` +## `Run()`, `RunWithContext(...)` и `RunWebhookWithContext(...)` `Run()` — это короткая форма для простых случаев. @@ -94,11 +94,11 @@ Laniakea предпочитает предсказуемый no-op вместо - ждет завершения queued updates; - корректно дожидается фоновых задач. -`RunWebHookWithContext(...)` — webhook-вариант runtime. Он использует тот же single-use контракт, тот же запуск runners, ту же очередь обновлений и ту же worker-pool обработку. +`RunWebhookWithContext(...)` — webhook-вариант runtime. Он использует тот же single-use контракт, тот же запуск runners, ту же очередь обновлений и ту же worker-pool обработку. Если bot уже был запущен раньше, повторный запуск вернет `ErrBotAlreadyRun`. -Если ты переводишь уже существующий deployment с webhook-доставки на polling, сначала удали текущий webhook через `CloseWebHook()` или низкоуровневый `tgapi.DeleteWebhook(...)`. Пока webhook не удалён, Telegram продолжает доставлять update через него. +Если ты переводишь уже существующий deployment с webhook-доставки на polling, сначала удали текущий webhook через `CloseWebhook()` или низкоуровневый `tgapi.DeleteWebhook(...)`. Пока webhook не удалён, Telegram продолжает доставлять update через него. Для webhook-специфичных опций, транспортного поведения и практических советов смотри [[Webhook-Runtime-RU]]. @@ -131,7 +131,7 @@ Laniakea предпочитает предсказуемый no-op вместо Обычно боту нужен именно `Close()`. -`RunWithContext(...)` и `RunWebHookWithContext(...)` не заменяют `Close()`: локальные ресурсы всё равно нужно закрывать отдельно. +`RunWithContext(...)` и `RunWebhookWithContext(...)` не заменяют `Close()`: локальные ресурсы всё равно нужно закрывать отдельно. ## Частые ошибки diff --git a/Bot-Lifecycle.md b/Bot-Lifecycle.md index 2f0da22..efb4a3a 100644 --- a/Bot-Lifecycle.md +++ b/Bot-Lifecycle.md @@ -7,7 +7,7 @@ This page explains how a `Bot` is created, configured, started, stopped, and ret ## Lifecycle at a glance 1. Build `BotOpts` and call `NewBot`. 2. Configure the bot instance: prefixes, plugins, middleware, runners, localization, payload defaults, and optional app data. -3. Start it with `RunWithContext(ctx)`, `Run()`, or `RunWebHookWithContext(...)`. +3. Start it with `RunWithContext(ctx)`, `Run()`, or `RunWebhookWithContext(...)`. 4. Stop runtime by canceling the context or letting the run method return. 5. Call `Close()` to release local resources. 6. Create a new `Bot` if you need another run. @@ -43,7 +43,7 @@ The normal pattern is to finish all structural configuration before starting the - `SetDraftProvider(...)`, `SetSessionStore(...)`, and `SetSceneScopePriority(...)` replace runtime helpers. - `SetErrorTemplate(...)` adjusts centralized user-facing error text. -For an overview of handlers and plugins, see [[Commands-and-Plugins]]. For context helpers available inside handlers, see [[MsgContext]]. +For an overview of handlers and plugins, see [[Commands-and-Plugins]]. For context helpers available inside handlers, see [[MessageContext]]. ## `AddPlugins(...)` is a configuration commit point @@ -66,7 +66,7 @@ Laniakea has three practical configuration phases: 1. Construction and bot setup after `NewBot[T](opts)`. 2. Plugin snapshotting at `AddPlugins(...)`. -3. Runtime freeze after the first `Run()`, `RunWithContext(...)`, or `RunWebHookWithContext(...)`. +3. Runtime freeze after the first `Run()`, `RunWithContext(...)`, or `RunWebhookWithContext(...)`. That means: - finish plugin structure before `AddPlugins(...)`; @@ -97,7 +97,7 @@ if err != nil { defer bot.Close() plugin := laniakea.NewPlugin[laniakea.NoData]("main") -plugin.NewCommand(func(ctx *laniakea.MsgContext, db laniakea.NoData) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.Answer("pong") return nil }, "ping") @@ -109,7 +109,7 @@ if err := bot.Run(); err != nil { } ``` -## `RunWithContext(...)`, `Run()`, and `RunWebHookWithContext(...)` +## `RunWithContext(...)`, `Run()`, and `RunWebhookWithContext(...)` `RunWithContext(ctx)` is the main polling runtime entry point. @@ -124,16 +124,16 @@ It: `Run()` is only a shorthand for `RunWithContext(context.Background())`. -`RunWebHookWithContext(...)` is the webhook runtime entry point. It shares the same: +`RunWebhookWithContext(...)` is the webhook runtime entry point. It shares the same: - single-use rule; - runner startup behavior; - internal update queue; - worker-pool dispatch model; - graceful shutdown semantics. -Use `RunWithContext(...)` for production services that poll Telegram directly. Use `RunWebHookWithContext(...)` when Telegram should deliver updates through your HTTP endpoint. +Use `RunWithContext(...)` for production services that poll Telegram directly. Use `RunWebhookWithContext(...)` when Telegram should deliver updates through your HTTP endpoint. -If you switch an existing deployment from webhook delivery to polling, remove the current webhook first with `CloseWebHook()` or low-level `tgapi.DeleteWebhook(...)`. Telegram keeps webhook delivery active until the webhook is deleted. +If you switch an existing deployment from webhook delivery to polling, remove the current webhook first with `CloseWebhook()` or low-level `tgapi.DeleteWebhook(...)`. Telegram keeps webhook delivery active until the webhook is deleted. For the webhook-specific option model, transport behavior, and operational guidance, see [[Webhook-Runtime]]. @@ -172,7 +172,7 @@ Canceling the runtime context tells the bot to stop accepting new work and finis - one-time async runners to finish; - background runners to exit after noticing `ctx.Done()`. -`RunWithContext(...)` and `RunWebHookWithContext(...)` do not automatically release API, uploader, or logger resources. You still need to call `Close()`. +`RunWithContext(...)` and `RunWebhookWithContext(...)` do not automatically release API, uploader, or logger resources. You still need to call `Close()`. ## `Close()` versus `CloseRemote()` @@ -192,7 +192,7 @@ Use `CloseRemote(ctx)` only when you specifically need Telegram-side session shu ## Single-use rule -A `Bot` cannot be started twice. After `Run()`, `RunWithContext(...)`, or `RunWebHookWithContext(...)` returns, later start attempts fail with `ErrBotAlreadyRun`. +A `Bot` cannot be started twice. After `Run()`, `RunWithContext(...)`, or `RunWebhookWithContext(...)` returns, later start attempts fail with `ErrBotAlreadyRun`. That means: - do not call a runtime entry point again after a graceful stop; diff --git a/Commands-and-Plugins-RU.md b/Commands-and-Plugins-RU.md index dde43d9..0602ed5 100644 --- a/Commands-and-Plugins-RU.md +++ b/Commands-and-Plugins-RU.md @@ -47,11 +47,11 @@ plugin := laniakea.NewPlugin[laniakea.NoData]("admin") Сигнатура обработчика команды такая: ```go -func(ctx *laniakea.MsgContext, db T) error +func(ctx *laniakea.MessageContext, db T) error ``` Где: -- `ctx` — текущий `MsgContext`; +- `ctx` — текущий `MessageContext`; - `db` — значение generic-параметра `T`, которое ты передал в `Bot`. Возвращай: @@ -61,7 +61,7 @@ func(ctx *laniakea.MsgContext, db T) error Пример: ```go -func start(ctx *laniakea.MsgContext, db *App) error { +func start(ctx *laniakea.MessageContext, db *App) error { ctx.Answer("Welcome") return nil } @@ -125,7 +125,7 @@ plugin.AddCommand( Пример: ```go -func confirmDelete(ctx *laniakea.MsgContext, db *App) error { +func confirmDelete(ctx *laniakea.MessageContext, db *App) error { ctx.EditCallback("Deleted", nil) return nil } @@ -147,7 +147,7 @@ plugin.AddPayload(plugin.NewPayload(confirmDelete, "delete.confirm")) Пример: ```go -plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MsgContext, db *App) error { +plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MessageContext, db *App) error { return nil }) ``` @@ -170,7 +170,7 @@ plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MsgConte Для текстовой команды поток примерно такой: 1. Приходит Telegram update. -2. `Bot` готовит `MsgContext`. +2. `Bot` готовит `MessageContext`. 3. Выполняется middleware бота. 4. Находится подходящий плагин. 5. Выполняется middleware плагина. @@ -258,5 +258,5 @@ return nil - [[Getting-Started-RU]] - [[Bot-Lifecycle-RU]] - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] - [[Inline-Keyboards-and-Payloads]] diff --git a/Commands-and-Plugins.md b/Commands-and-Plugins.md index 0b55bbd..379afe4 100644 --- a/Commands-and-Plugins.md +++ b/Commands-and-Plugins.md @@ -49,7 +49,7 @@ That keeps command registration and middleware ownership clear. The command handler signature is: ```go -func(ctx *laniakea.MsgContext, db T) error +func(ctx *laniakea.MessageContext, db T) error ``` Where: @@ -63,7 +63,7 @@ Return: Example: ```go -func start(ctx *laniakea.MsgContext, db *App) error { +func start(ctx *laniakea.MessageContext, db *App) error { ctx.Answer("Welcome") return nil } @@ -89,7 +89,7 @@ So: ## The easiest command example ```go -func echo(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func echo(ctx *laniakea.MessageContext, db laniakea.NoData) error { if ctx.Text == "" { ctx.Answer("Usage: /echo ") return nil @@ -136,7 +136,7 @@ Payload handlers are for callback data coming from inline keyboard buttons. Register them with `NewPayload(...)` or `AddPayload(...)`: ```go -func confirmDelete(ctx *laniakea.MsgContext, db *App) error { +func confirmDelete(ctx *laniakea.MessageContext, db *App) error { ctx.EditCallback("Deleted", nil) return nil } @@ -158,7 +158,7 @@ Update handlers are for Telegram updates outside the normal command/payload flow Register them with `AddUpdateHandler(...)`: ```go -plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MsgContext, db *App) error { +plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MessageContext, db *App) error { // handle inline query here return nil }) @@ -183,7 +183,7 @@ stay on the command/payload flow and are not meant to be registered through `Add For text commands: 1. Telegram update arrives -2. bot prepares `MsgContext` +2. bot prepares `MessageContext` 3. bot middleware runs 4. matching plugin is found 5. plugin middleware runs @@ -235,7 +235,7 @@ Avoid one giant plugin for the entire bot unless the bot is very small. ```go admin := laniakea.NewPlugin[*App]("admin") -admin.AddMiddleware(laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MsgContext, app *App) bool { +admin.AddMiddleware(laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MessageContext, app *App) bool { if !app.IsAdmin(ctx.FromID) { ctx.Answer("Access denied") return false @@ -243,7 +243,7 @@ admin.AddMiddleware(laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MsgC return true })) -admin.AddCommand(admin.NewCommand(func(ctx *laniakea.MsgContext, app *App) error { +admin.AddCommand(admin.NewCommand(func(ctx *laniakea.MessageContext, app *App) error { ctx.Answer("Banned") return nil }, "ban")) @@ -252,7 +252,7 @@ admin.AddCommand(admin.NewCommand(func(ctx *laniakea.MsgContext, app *App) error ### Example: payload handler for inline keyboard callback ```go -plugin.AddPayload(plugin.NewPayload(func(ctx *laniakea.MsgContext, app *App) error { +plugin.AddPayload(plugin.NewPayload(func(ctx *laniakea.MessageContext, app *App) error { ctx.AnswerCbQueryText("Accepted") ctx.EditCallback("Done", nil) return nil @@ -304,6 +304,6 @@ Use: - command middleware for narrow, local checks ## Where to go next -- Read [[MsgContext]] next to understand what handlers can do once they are triggered. +- Read [[MessageContext]] next to understand what handlers can do once they are triggered. - Read [[Inline-Keyboards-and-Payloads]] if you are starting to use buttons and callback data. - Read [[Middleware]] for execution-order and async details. diff --git a/Drafts-RU.md b/Drafts-RU.md index baad7dc..9e1c0ca 100644 --- a/Drafts-RU.md +++ b/Drafts-RU.md @@ -75,6 +75,6 @@ draft.Flush() ## Что читать дальше -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Bot-Lifecycle-RU]] - [[Drafts]] diff --git a/Drafts.md b/Drafts.md index 1a8c8f1..ca6f7d3 100644 --- a/Drafts.md +++ b/Drafts.md @@ -23,9 +23,9 @@ The draft system has two layers: The provider is safe for concurrent use. Individual drafts are intended for single-goroutine use unless you add your own synchronization. -## The easiest entry point: `MsgContext.NewDraft()` +## The easiest entry point: `MessageContext.NewDraft()` -Inside a handler, the usual entry point is `MsgContext.NewDraft()` or `MsgContext.NewDraftMarkdown()`. +Inside a handler, the usual entry point is `MessageContext.NewDraft()` or `MessageContext.NewDraftMarkdown()`. Those helpers: - create a draft from the bot's configured `DraftProvider`; @@ -35,7 +35,7 @@ Those helpers: Typical usage: ```go -func report(ctx *laniakea.MsgContext, db *App) error { +func report(ctx *laniakea.MessageContext, db *App) error { draft := ctx.NewDraft() if draft == nil { return nil @@ -174,5 +174,5 @@ Prefer direct reply helpers such as `Answer(...)` or `AnswerLong(...)` when: ## Related pages -- [[MsgContext]] for handler-scoped reply and draft helpers +- [[MessageContext]] for handler-scoped reply and draft helpers - [[Bot-Lifecycle]] for draft-provider attachment through the bot diff --git a/Error-Handling-RU.md b/Error-Handling-RU.md index 3cd587d..44debf0 100644 --- a/Error-Handling-RU.md +++ b/Error-Handling-RU.md @@ -25,7 +25,7 @@ English version: [[Error-Handling]] ## Как это выглядит ```go -func ping(ctx *laniakea.MsgContext, db *App) error { +func ping(ctx *laniakea.MessageContext, db *App) error { ctx.Answer("pong") return nil } diff --git a/Error-Handling.md b/Error-Handling.md index 7daa5ad..9b5a8fd 100644 --- a/Error-Handling.md +++ b/Error-Handling.md @@ -16,7 +16,7 @@ That applies to: The basic pattern is: ```go -func ping(ctx *laniakea.MsgContext, db *App) error { +func ping(ctx *laniakea.MessageContext, db *App) error { ctx.Answer("pong") return nil } @@ -183,7 +183,7 @@ Related page: ### Centralized command failure ```go -plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db *App) error { result, err := db.DoWork() if err != nil { return fmt.Errorf("failed to build report: %w", err) @@ -196,7 +196,7 @@ plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { ### Manual denial response ```go -plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db *App) error { if ctx.From == nil || !db.Allowed(ctx.From.ID) { ctx.Answer("Access denied") return nil @@ -208,7 +208,7 @@ plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { ### Callback-specific manual alert ```go -plugin.NewPayload(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewPayload(func(ctx *laniakea.MessageContext, db *App) error { if !ready { ctx.AnswerCbQueryAlert("This action is not available yet") return nil diff --git a/Framework-Backlog-RU.md b/Framework-Backlog-RU.md index b83156b..3c33484 100644 --- a/Framework-Backlog-RU.md +++ b/Framework-Backlog-RU.md @@ -9,7 +9,7 @@ Текущее состояние: - В репозитории уже есть низкоуровневые API для настройки webhook на уровне `tgapi`: `SetWebhook(...)`, `DeleteWebhook(...)`, `GetWebhookInfo(...)`, а также поддержка загрузки сертификата через uploader. -- Во фреймворке теперь есть полноценные bot-level точки входа webhook runtime: `RunWebHookWithContext(...)` и `RunWebHook(...)`. +- Во фреймворке теперь есть полноценные bot-level точки входа webhook runtime: `RunWebhookWithContext(...)` и `RunWebhook(...)`. - Webhook-доставка теперь использует ту же внутреннюю очередь update-ов, тот же worker pool, тот же запуск runners и тот же single-use runtime contract, что и polling. - Поведение webhook runtime, security-модель и правила перехода обратно на polling теперь описаны в основной документации и wiki. @@ -21,12 +21,12 @@ Что теперь есть: -- `BotWebHookOpts`, `NewBotWebHookOpts()` и fluent helper-методы для webhook-конфигурации. -- `RunWebHookWithContext(...)` и `RunWebHook(...)` как bot-owned точки входа runtime. +- `BotWebhookOpts`, `NewBotWebhookOpts()` и fluent helper-методы для webhook-конфигурации. +- `RunWebhookWithContext(...)` и `RunWebhook(...)` как bot-owned точки входа runtime. - Общая queued dispatch-модель, worker-pool обработка, запуск runners и single-use semantics для polling и webhook mode. - Fallback webhook `AllowedUpdates` к bot-level конфигурации типов update. - Валидация webhook path и количества TLS-файлов до remote webhook setup. -- Явное удаление remote webhook через `CloseWebHook()` или низкоуровневый `tgapi.DeleteWebhook(...)` при переходе deployment с webhook-доставки обратно на polling. +- Явное удаление remote webhook через `CloseWebhook()` или низкоуровневый `tgapi.DeleteWebhook(...)` при переходе deployment с webhook-доставки обратно на polling. - Регрессионные тесты на queue delivery, запуск runners, single-use behavior, rejection слишком большого body, path/TLS validation и auth-поведение status endpoint. Практическая цель: @@ -65,7 +65,7 @@ Текущее состояние: -- Во фреймворке теперь есть `Policy[T]` как явная переиспользуемая модель правила доступа, работающая поверх нормализованного `MsgContext` и общих данных приложения. +- Во фреймворке теперь есть `Policy[T]` как явная переиспользуемая модель правила доступа, работающая поверх нормализованного `MessageContext` и общих данных приложения. - Политики интегрируются в уже существующую модель выполнения через `RequirePolicy(...)`, поэтому авторизация остаётся на middleware-пути и не создаёт второй pipeline маршрутизации. - У бота и плагинов появились явные helpers для регистрации политик на уровне конфигурации. @@ -82,7 +82,7 @@ - `Bot.UsePolicy(...)` и `Plugin.UsePolicy(...)` для удобной регистрации. - Встроенные Telegram-aware helpers: `RequirePrivateChat(...)`, `RequireGroupChat(...)`, `RequireSupergroupChat(...)`, `RequireChatAdmin(...)`, `RequireChatCreator(...)`, `RequireBotAdmin(...)` и `RequireCallbackFromUser(...)`. - Комбинаторы `AllPolicies(...)`, `AnyPolicy(...)` и `NotPolicy(...)`. -- Расширенная нормализация `MsgContext` для `Chat` и `ChatID`, а также регрессионные тесты на поведение политик и нормализованного контекста. +- Расширенная нормализация `MessageContext` для `Chat` и `ChatID`, а также регрессионные тесты на поведение политик и нормализованного контекста. Практическая цель: @@ -106,7 +106,7 @@ - `AsUserError(...)` и `AsInternalError(...)` для явной классификации возвращаемых ошибок. - `IsUserError(...)` и `IsInternalError(...)` для проверки этой классификации на стороне фреймворка. -- Обновлённое поведение `MsgContext.Error(...)`: все ошибки по-прежнему логируются, но для внутренних ошибок автоматический ответ пользователю подавляется. +- Обновлённое поведение `MessageContext.Error(...)`: все ошибки по-прежнему логируются, но для внутренних ошибок автоматический ответ пользователю подавляется. - Регрессионные тесты для message и callback потоков. Практическая цель: @@ -117,7 +117,7 @@ Текущее состояние: -- Фреймворк теперь считает конфигурацию бота структурно завершённой после начала первого runtime entry point: `Run()`, `RunWithContext(...)` или `RunWebHookWithContext(...)`. +- Фреймворк теперь считает конфигурацию бота структурно завершённой после начала первого runtime entry point: `Run()`, `RunWithContext(...)` или `RunWebhookWithContext(...)`. - Поздние bot-level попытки мутации больше не применяются частично после старта runtime. - Границы между регистрацией плагинов, стартом runtime и фиксацией конфигурации теперь оформлены как явное поведение фреймворка и закреплены тестами. @@ -141,30 +141,30 @@ Текущее состояние: - Нормализация обновлений уже существовала, но теперь она описана и протестирована как явный контракт уровня фреймворка. -- Категории маршрутизации и гарантии заполнения `MsgContext` теперь рассматриваются как полноценная часть публичной модели. +- Категории маршрутизации и гарантии заполнения `MessageContext` теперь рассматриваются как полноценная часть публичной модели. Почему это важно: -- Код обработчиков должен понимать, на какие поля `MsgContext` можно безопасно опираться в каждом потоке обновлений. +- Код обработчиков должен понимать, на какие поля `MessageContext` можно безопасно опираться в каждом потоке обновлений. - Без явного контракта обработка обновлений остаётся понятной только через чтение реализации. Что теперь есть: - Задокументированная модель маршрутизации для command flow, payload flow и generic update handlers. -- Явные комментарии на полях `MsgContext`, описывающие гарантии для update-backed, callback-backed и message-backed контекстов. +- Явные комментарии на полях `MessageContext`, описывающие гарантии для update-backed, callback-backed и message-backed контекстов. - Table-driven регрессионные тесты для нормализованного update contract, включая callback target semantics и non-command update flows. Практическая цель: -- Сделать маршрутизацию обновлений и гарантии `MsgContext` достаточно явными, чтобы на них можно было опираться как на стабильный контракт `1.0`. +- Сделать маршрутизацию обновлений и гарантии `MessageContext` достаточно явными, чтобы на них можно было опираться как на стабильный контракт `1.0`. ### [1.0.0-rc.12] Conversation / Scene Model Текущее состояние: - Фреймворк хорошо обрабатывает одно обновление через команды, данные callback, middleware и обработчики обновлений. -- В нём уже есть полезные низкоуровневые строительные блоки: `MsgContext`, черновики, маршрутизация данных callback, плагины и обработчики обновлений. -- Теперь в нём уже есть реализованная начальная модель сцен для долгоживущих интерактивных сценариев: сцены можно регистрировать в плагинах, запускать через `MsgContext`, сохранять через `SessionStore` и маршрутизировать раньше обычной обработки команд. +- В нём уже есть полезные низкоуровневые строительные блоки: `MessageContext`, черновики, маршрутизация данных callback, плагины и обработчики обновлений. +- Теперь в нём уже есть реализованная начальная модель сцен для долгоживущих интерактивных сценариев: сцены можно регистрировать в плагинах, запускать через `MessageContext`, сохранять через `SessionStore` и маршрутизировать раньше обычной обработки команд. Почему это важно: @@ -176,7 +176,7 @@ - Маршрутизация активной сцены раньше обычной маршрутизации команд. - Области действия сессии на пользователя, чат и пару пользователь-чат. -- Явный вход и выход через `MsgContext`. +- Явный вход и выход через `MessageContext`. - Обработчики шагов, локальные команды сцены и `OnMessage(...)`. - Встроенное in-memory-хранилище по умолчанию и интерфейс `SessionStore` для собственного постоянного хранения. @@ -190,7 +190,7 @@ - `Scene`, `SceneContext`, `SceneSession` и `SessionStore`. - `Plugin.NewScene(...)` и `Plugin.AddScene(...)`. -- `MsgContext.EnterScene(...)`, `EnterSceneStep(...)` и `ExitScene(...)`. +- `MessageContext.EnterScene(...)`, `EnterSceneStep(...)` и `ExitScene(...)`. - `SceneContext.Stay()`, `Next(...)`, `Exit()`, `Pass()`, `BindData(...)` и `SaveData(...)`. - Состояние на пользователя или чат с хранением в `SessionStore` и чистым интерфейсом для собственного постоянного хранения. @@ -198,7 +198,7 @@ - Это должно быть опциональным и расширяющим текущую модель. - Это не должно заменять плагины, команды или обработчики как обычные точки входа во фреймворк. -- Это должно работать поверх существующих middleware и `MsgContext`, а не вводить вторую несовместимую модель выполнения. +- Это должно работать поверх существующих middleware и `MessageContext`, а не вводить вторую несовместимую модель выполнения. Практическая цель: @@ -240,7 +240,7 @@ type BanInput struct { Reason string } -func ban(ctx *laniakea.MsgContext, db *App) error { +func ban(ctx *laniakea.MessageContext, db *App) error { var input BanInput if err := ctx.BindArgs(&input); err != nil { return err @@ -263,7 +263,7 @@ func ban(ctx *laniakea.MsgContext, db *App) error { Текущее состояние: -- `RunWithContext(...)` и `RunWebHookWithContext(...)` управляют жизненным циклом выполнения бота и корректным завершением. +- `RunWithContext(...)` и `RunWebhookWithContext(...)` управляют жизненным циклом выполнения бота и корректным завершением. - `tgapi` уже поддерживает методы, принимающие `context.Context`. - Обычные обработчики не получают полноценный `context.Context`, привязанный к обработке конкретного запроса. @@ -281,14 +281,14 @@ func ban(ctx *laniakea.MsgContext, db *App) error { Возможное направление API: -- Предпочесть non-breaking подход и выдавать context через `MsgContext`, например `ctx.Context()`. +- Предпочесть non-breaking подход и выдавать context через `MessageContext`, например `ctx.Context()`. - Строить context из жизненного цикла обработки обновления, чтобы он оставался полезным во время корректного завершения. - Сделать естественной передачу этого context в методы базы данных, HTTP-клиенты и `tgapi.WithContext(...)`. Почему это, скорее всего, не должно быть изменением сигнатуры: - Изменение сигнатур обработчиков на прямой `context.Context` было бы публичным ломающим изменением. -- Аксессор на `MsgContext` сохраняет совместимость и при этом даёт обработчикам идиоматичный Go-путь для отмены выполнения. +- Аксессор на `MessageContext` сохраняет совместимость и при этом даёт обработчикам идиоматичный Go-путь для отмены выполнения. Практическая цель: @@ -297,7 +297,7 @@ func ban(ctx *laniakea.MsgContext, db *App) error { Связанные страницы: - [[Scenes]] -- [[MsgContext]] +- [[MessageContext]] - [[Bot-Lifecycle]] - [[Migration]] diff --git a/Framework-Backlog.md b/Framework-Backlog.md index 7f6bda3..9cec661 100644 --- a/Framework-Backlog.md +++ b/Framework-Backlog.md @@ -9,7 +9,7 @@ This page tracks framework-level backlog items that are about missing concepts i Current state: - The repository already exposes low-level Telegram webhook setup APIs through `tgapi`, including `SetWebhook(...)`, `DeleteWebhook(...)`, `GetWebhookInfo(...)`, and uploader-based certificate upload support. -- The framework now exposes first-class bot-level webhook runtime entry points through `RunWebHookWithContext(...)` and `RunWebHook(...)`. +- The framework now exposes first-class bot-level webhook runtime entry points through `RunWebhookWithContext(...)` and `RunWebhook(...)`. - Webhook delivery now uses the same internal update queue, worker pool, runner startup model, and single-use runtime contract as polling. - The webhook runtime behavior, security model, and polling-transition requirements are now documented in the main docs and wiki. @@ -21,12 +21,12 @@ Why this matters: What is now present: -- `BotWebHookOpts`, `NewBotWebHookOpts()`, and fluent helpers for webhook-specific configuration. -- `RunWebHookWithContext(...)` and `RunWebHook(...)` as bot-owned runtime entry points. +- `BotWebhookOpts`, `NewBotWebhookOpts()`, and fluent helpers for webhook-specific configuration. +- `RunWebhookWithContext(...)` and `RunWebhook(...)` as bot-owned runtime entry points. - Shared queued update dispatch, worker-pool delivery, runner startup, and single-use run semantics between polling and webhook modes. - Default fallback from webhook `AllowedUpdates` to the bot-level update type configuration. - Request validation for webhook path shape and TLS file count before remote webhook setup. -- Explicit remote webhook teardown through `CloseWebHook()` or low-level `tgapi.DeleteWebhook(...)` when switching a deployment from webhook delivery back to polling. +- Explicit remote webhook teardown through `CloseWebhook()` or low-level `tgapi.DeleteWebhook(...)` when switching a deployment from webhook delivery back to polling. - Regression coverage for queue delivery, runner startup, single-use behavior, body-size rejection, path and TLS validation, and status-endpoint auth behavior. Practical target: @@ -65,7 +65,7 @@ Practical target: Current state: -- The framework now exposes `Policy[T]` as a first-class reusable authorization rule that runs against the normalized `MsgContext` and injected app data. +- The framework now exposes `Policy[T]` as a first-class reusable authorization rule that runs against the normalized `MessageContext` and injected app data. - Policies integrate with the existing execution model through `RequirePolicy(...)`, so authorization stays on the middleware path instead of introducing a second routing pipeline. - Bot-level and plugin-level registration helpers now make policy usage explicit in configuration. @@ -82,7 +82,7 @@ What is now present: - `Bot.UsePolicy(...)` and `Plugin.UsePolicy(...)` for registration ergonomics. - Built-in Telegram-aware helpers such as `RequirePrivateChat(...)`, `RequireGroupChat(...)`, `RequireSupergroupChat(...)`, `RequireChatAdmin(...)`, `RequireChatCreator(...)`, `RequireBotAdmin(...)`, and `RequireCallbackFromUser(...)`. - Composition helpers `AllPolicies(...)`, `AnyPolicy(...)`, and `NotPolicy(...)`. -- Extended `MsgContext` normalization for `Chat` and `ChatID`, plus regression coverage for policy and normalization behavior. +- Extended `MessageContext` normalization for `Chat` and `ChatID`, plus regression coverage for policy and normalization behavior. Practical target: @@ -106,7 +106,7 @@ What is now present: - `AsUserError(...)` and `AsInternalError(...)` to classify returned handler errors explicitly. - `IsUserError(...)` and `IsInternalError(...)` for framework-side inspection. -- Updated centralized `MsgContext.Error(...)` behavior that still logs all errors but suppresses the automatic user reply for internal-only failures. +- Updated centralized `MessageContext.Error(...)` behavior that still logs all errors but suppresses the automatic user reply for internal-only failures. - Regression coverage for both message and callback flows. Practical target: @@ -117,7 +117,7 @@ Practical target: Current state: -- The framework now treats bot configuration as structurally complete once the first runtime entry point begins: `Run()`, `RunWithContext(...)`, or `RunWebHookWithContext(...)`. +- The framework now treats bot configuration as structurally complete once the first runtime entry point begins: `Run()`, `RunWithContext(...)`, or `RunWebhookWithContext(...)`. - Late bot-level mutation attempts no longer partially apply after runtime startup. - Plugin registration and runtime configuration boundaries are now documented and tested as explicit framework behavior. @@ -141,30 +141,30 @@ Practical target: Current state: - Update normalization already existed, but it is now described and tested as an explicit framework-level contract. -- Routing categories and `MsgContext` population guarantees are now treated as a first-class part of the public model. +- Routing categories and `MessageContext` population guarantees are now treated as a first-class part of the public model. Why this matters: -- Handler code needs to know which `MsgContext` fields are safe to rely on for each update path. +- Handler code needs to know which `MessageContext` fields are safe to rely on for each update path. - Without a formal contract, update handling remains understandable only by reading implementation details. What is now present: - A documented routing model for command flow, payload flow, and generic update handlers. -- Explicit `MsgContext` field comments for update-backed, callback-backed, and message-backed contexts. +- Explicit `MessageContext` field comments for update-backed, callback-backed, and message-backed contexts. - Table-driven regression coverage for the normalized update contract, including callback target semantics and non-command update flows. Practical target: -- Make update routing and `MsgContext` guarantees explicit enough to serve as a stable `1.0` public contract. +- Make update routing and `MessageContext` guarantees explicit enough to serve as a stable `1.0` public contract. ### [1.0.0-rc.12] Conversation / Scene Model Current state: - The framework is strong at handling a single update through commands, payloads, middleware, and update handlers. -- It already has useful lower-level building blocks such as `MsgContext`, drafts, payload routing, plugins, and update handlers. -- It now provides an implemented initial scene model for long-lived user interaction flows: scenes can be registered in plugins, entered through `MsgContext`, persisted through `SessionStore`, and routed before normal command handling. +- It already has useful lower-level building blocks such as `MessageContext`, drafts, payload routing, plugins, and update handlers. +- It now provides an implemented initial scene model for long-lived user interaction flows: scenes can be registered in plugins, entered through `MessageContext`, persisted through `SessionStore`, and routed before normal command handling. Why this matters: @@ -176,7 +176,7 @@ What is already present: - Active-scene routing before normal command flow. - Per-user, per-chat, and per-user-chat session scopes. -- Explicit scene entry and exit through `MsgContext`. +- Explicit scene entry and exit through `MessageContext`. - Step handlers, scene-local commands, and `OnMessage(...)`. - In-memory session storage by default, plus the `SessionStore` interface for custom persistence. @@ -190,7 +190,7 @@ Current API direction: - `Scene`, `SceneContext`, `SceneSession`, and `SessionStore`. - `Plugin.NewScene(...)` and `Plugin.AddScene(...)`. -- `MsgContext.EnterScene(...)`, `EnterSceneStep(...)`, and `ExitScene(...)`. +- `MessageContext.EnterScene(...)`, `EnterSceneStep(...)`, and `ExitScene(...)`. - `SceneContext.Stay()`, `Next(...)`, `Exit()`, `Pass()`, `BindData(...)`, and `SaveData(...)`. - Storage-backed per-user or per-chat state with a clean interface for custom persistence. @@ -198,7 +198,7 @@ Important design constraints: - This should be additive and optional. - It should not replace plugins, commands, or handlers as the normal framework entry points. -- It should work with existing middleware and `MsgContext` instead of introducing a second incompatible execution model. +- It should work with existing middleware and `MessageContext` instead of introducing a second incompatible execution model. Practical target: @@ -240,7 +240,7 @@ type BanInput struct { Reason string } -func ban(ctx *laniakea.MsgContext, db *App) error { +func ban(ctx *laniakea.MessageContext, db *App) error { var input BanInput if err := ctx.BindArgs(&input); err != nil { return err @@ -263,7 +263,7 @@ Practical target: Current state: -- `RunWithContext(...)` and `RunWebHookWithContext(...)` control bot runtime lifecycle and graceful shutdown. +- `RunWithContext(...)` and `RunWebhookWithContext(...)` control bot runtime lifecycle and graceful shutdown. - `tgapi` already supports context-aware methods. - Regular handlers do not receive a first-class request-scoped `context.Context`. @@ -281,14 +281,14 @@ What is missing: Possible API direction: -- Prefer a non-breaking approach by exposing context through `MsgContext`, for example `ctx.Context()`. +- Prefer a non-breaking approach by exposing context through `MessageContext`, for example `ctx.Context()`. - Build the context from the update-processing lifecycle so it is meaningful during graceful shutdown. - Make it natural to pass that context into database methods, HTTP clients, and `tgapi.WithContext(...)` calls. Why this should probably not be a signature change: - Changing handler signatures to accept `context.Context` directly would be a public breaking change. -- A `MsgContext` accessor would preserve compatibility while still giving handlers an idiomatic Go cancellation path. +- A `MessageContext` accessor would preserve compatibility while still giving handlers an idiomatic Go cancellation path. Practical target: @@ -297,7 +297,7 @@ Practical target: Related pages: - [[Scenes]] -- [[MsgContext]] +- [[MessageContext]] - [[Bot-Lifecycle]] - [[Migration]] diff --git a/Getting-Started-RU.md b/Getting-Started-RU.md index 306c0d3..3c7c848 100644 --- a/Getting-Started-RU.md +++ b/Getting-Started-RU.md @@ -33,7 +33,7 @@ import ( "git.scuroneko.dev/scuroneko/laniakea" ) -func ping(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func ping(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.Answer("Pong") return nil } @@ -111,7 +111,7 @@ bot.AddPlugins(plugin) Сигнатура хендлера: ```go -func(ctx *laniakea.MsgContext, db T) error +func(ctx *laniakea.MessageContext, db T) error ``` То есть: @@ -121,7 +121,7 @@ func(ctx *laniakea.MsgContext, db T) error Пример: ```go -func profile(ctx *laniakea.MsgContext, db *App) error { +func profile(ctx *laniakea.MessageContext, db *App) error { user, err := db.LoadUser(ctx.FromID) if err != nil { return err @@ -136,7 +136,7 @@ func profile(ctx *laniakea.MsgContext, db *App) error { ### 4. `Bot` single-use -После `Run()`, `RunWithContext(...)` или `RunWebHookWithContext(...)` нельзя снова запускать тот же экземпляр `Bot`. +После `Run()`, `RunWithContext(...)` или `RunWebhookWithContext(...)` нельзя снова запускать тот же экземпляр `Bot`. Правильная модель: - создать bot @@ -151,7 +151,7 @@ func profile(ctx *laniakea.MsgContext, db *App) error { ### 5. `Close()` все равно нужен -Даже если ты используешь `Run()`, `RunWithContext(...)` или `RunWebHookWithContext(...)`, ресурсы нужно закрывать явно: +Даже если ты используешь `Run()`, `RunWithContext(...)` или `RunWebhookWithContext(...)`, ресурсы нужно закрывать явно: ```go defer bot.Close() @@ -168,7 +168,7 @@ defer bot.Close() 5. Добавить команды, payloads и middleware в плагины 6. Зарегистрировать плагины через `AddPlugins(...)` 7. При необходимости вызвать `AutoGenerateCommands()` -8. Вызвать `Run()`, `RunWithContext(...)` или `RunWebHookWithContext(...)` +8. Вызвать `Run()`, `RunWithContext(...)` или `RunWebhookWithContext(...)` 9. Закрыть bot через `Close()` ## Частые ошибки на старте @@ -199,4 +199,4 @@ defer bot.Close() - [[Bot-Lifecycle-RU]] - [[Getting-Started]] - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] diff --git a/Getting-Started.md b/Getting-Started.md index 4602768..79c6153 100644 --- a/Getting-Started.md +++ b/Getting-Started.md @@ -34,7 +34,7 @@ import ( "git.scuroneko.dev/scuroneko/laniakea" ) -func ping(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func ping(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.Answer("Pong") return nil } @@ -113,7 +113,7 @@ See [[Commands-and-Plugins]] for the full model. The command handler signature is: ```go -func(ctx *laniakea.MsgContext, db T) error +func(ctx *laniakea.MessageContext, db T) error ``` This means: @@ -124,7 +124,7 @@ This means: Example: ```go -func profile(ctx *laniakea.MsgContext, db *App) error { +func profile(ctx *laniakea.MessageContext, db *App) error { user, err := db.LoadUser(ctx.FromID) if err != nil { return err @@ -139,7 +139,7 @@ func profile(ctx *laniakea.MsgContext, db *App) error { A `Bot` instance is single-use. -After `Run()`, `RunWithContext(...)`, or `RunWebHookWithContext(...)` returns: +After `Run()`, `RunWithContext(...)`, or `RunWebhookWithContext(...)` returns: - do not call a runtime entry point again on the same bot - create a new bot instance for the next run @@ -149,7 +149,7 @@ See [[Bot-Lifecycle]] for details. ### 5. Always close the bot -`Run()`, `RunWithContext(...)`, and `RunWebHookWithContext(...)` do not replace `Close()`. +`Run()`, `RunWithContext(...)`, and `RunWebhookWithContext(...)` do not replace `Close()`. You should still release bot-owned resources explicitly: @@ -168,7 +168,7 @@ For most bots, this order is the least surprising: 5. Add commands, payloads, and middleware to plugins 6. Register plugins with `AddPlugins(...)` 7. Optionally call `AutoGenerateCommands()` -8. Call `Run()`, `RunWithContext(...)`, or `RunWebHookWithContext(...)` +8. Call `Run()`, `RunWithContext(...)`, or `RunWebhookWithContext(...)` 9. Call `Close()` when done ## A slightly more realistic example @@ -184,7 +184,7 @@ import ( type App struct{} -func echo(ctx *laniakea.MsgContext, app *App) error { +func echo(ctx *laniakea.MessageContext, app *App) error { if ctx.Text == "" { ctx.Answer("Send some text after the command.") return nil @@ -259,5 +259,5 @@ Prefer pointer types unless you have a strong reason not to. ## Where to go next - Read [[Commands-and-Plugins]] next if you want to build the handler layer correctly. -- Read [[MsgContext]] next if you want to understand reply, edit, callback, and draft helpers. +- Read [[MessageContext]] next if you want to understand reply, edit, callback, and draft helpers. - Read [[Bot-Lifecycle]] if you need shutdown, worker, or startup details. diff --git a/Home-RU.md b/Home-RU.md index d910d13..ba66efc 100644 --- a/Home-RU.md +++ b/Home-RU.md @@ -9,7 +9,7 @@ English version: [[Home]] - [[Getting-Started-RU]] - [[Bot-Options-and-Configuration-RU]] - [[Commands-and-Plugins-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] ## Выполнение и архитектура @@ -50,7 +50,7 @@ English version: [[Home]] - [[Getting-Started]] - [[Bot-Options-and-Configuration]] - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] - [[Bot-Lifecycle]] - [[Inline-Keyboards-and-Payloads]] - [[tgapi-Overview]] @@ -60,7 +60,7 @@ English version: [[Home]] Рекомендуемый маршрут для русскоязычного пользователя: 1. Прочитать [[Getting-Started-RU]]. -2. Прочитать [[Commands-and-Plugins-RU]] и [[MsgContext-RU]]. +2. Прочитать [[Commands-and-Plugins-RU]] и [[MessageContext-RU]]. 3. Перейти в страницы про выполнение и поведение во время работы, например [[Bot-Lifecycle-RU]] и [[Middleware-RU]]. 4. При необходимости открыть специализированные страницы вроде [[Drafts-RU]], [[Rate-Limiting-RU]] или [[tgapi-Overview-RU]]. 5. Для максимальной точности переходить в соответствующую англоязычную страницу. diff --git a/Home.md b/Home.md index 92cea37..ea95b6b 100644 --- a/Home.md +++ b/Home.md @@ -15,7 +15,7 @@ Use this wiki as the structured companion to the README: start with setup, then - [[Getting-Started]] - [[Bot-Options-and-Configuration]] - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] ## Bot Runtime - [[Bot-Lifecycle]] diff --git a/Inline-Keyboards-and-Payloads-RU.md b/Inline-Keyboards-and-Payloads-RU.md index 09460c1..8498267 100644 --- a/Inline-Keyboards-and-Payloads-RU.md +++ b/Inline-Keyboards-and-Payloads-RU.md @@ -99,5 +99,5 @@ kb := ctx.NewInlineKeyboard(2). ## Что читать дальше - [[Commands-and-Plugins-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Inline-Keyboards-and-Payloads]] diff --git a/Inline-Keyboards-and-Payloads.md b/Inline-Keyboards-and-Payloads.md index af65ac6..e73954f 100644 --- a/Inline-Keyboards-and-Payloads.md +++ b/Inline-Keyboards-and-Payloads.md @@ -91,7 +91,7 @@ Inside the payload handler, those values are available through: - `ctx.Args` for the decoded argument list; - the payload command name used to choose the matched handler. -There is no separate `ctx.Payload` object in the current API. Payload handlers receive the same `MsgContext` structure used elsewhere, with `ctx.Args` populated from callback data. +There is no separate `ctx.Payload` object in the current API. Payload handlers receive the same `MessageContext` structure used elsewhere, with `ctx.Args` populated from callback data. ## JSON vs Base64 payloads @@ -126,7 +126,7 @@ The bot has a default callback encoding: bot.SetPayloadType(laniakea.BotPayloadBase64) ``` -That default is copied into `MsgContext`, so `ctx.NewInlineKeyboard(...)` starts with the bot’s current payload type. +That default is copied into `MessageContext`, so `ctx.NewInlineKeyboard(...)` starts with the bot’s current payload type. For a single keyboard, you can override it locally: @@ -247,7 +247,7 @@ Payloads are registered on plugins with: Example: ```go -plugin.NewPayload(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewPayload(func(ctx *laniakea.MessageContext, db *App) error { id := ctx.Args[0] ctx.AnswerCbQueryText("Handled " + id) return nil @@ -275,5 +275,5 @@ Related page: ## Related pages - [[Commands-and-Plugins]] for payload handler registration and routing. -- [[MsgContext]] for reply, edit, and callback helpers. +- [[MessageContext]] for reply, edit, and callback helpers. - [[tgapi-Overview]] for lower-level Telegram method access when keyboard helpers are not enough. diff --git a/Localization.md b/Localization.md index 8e2639b..3b3d6f9 100644 --- a/Localization.md +++ b/Localization.md @@ -77,11 +77,11 @@ bot.SetL10n(l10n) From then on: - `bot.L10n(lang, key)` is available for manual lookups; -- `MsgContext.Translate(key)` becomes the ergonomic handler-level helper. +- `MessageContext.Translate(key)` becomes the ergonomic handler-level helper. If `SetL10n(nil)` is called, the bot logs a warning and keeps the existing localization provider unchanged. -## `MsgContext.Translate` +## `MessageContext.Translate` `ctx.Translate(key)` is the usual choice inside handlers. @@ -93,7 +93,7 @@ It: Example: ```go -func start(ctx *laniakea.MsgContext, db *App) error { +func start(ctx *laniakea.MessageContext, db *App) error { ctx.Answer(ctx.Translate("greeting")) return nil } @@ -111,7 +111,7 @@ Use `bot.L10n(lang, key)` when you need a translation outside handler flow or wh Examples: - preparing background-runner messages; - rendering text for stored user preferences; -- translating outside `MsgContext`. +- translating outside `MessageContext`. ## Concurrency and mutation safety @@ -150,5 +150,5 @@ l10n. ## Related pages - [[Getting-Started]] for basic bot setup -- [[MsgContext]] for handler helpers +- [[MessageContext]] for handler helpers - [[Recipes]] for localized handler examples diff --git a/Logging.md b/Logging.md index ee59cdd..5c5291c 100644 --- a/Logging.md +++ b/Logging.md @@ -55,13 +55,13 @@ Ways plugin loggers are set: - explicitly with `Plugin.SetLogger(...)` before `AddPlugins(...)`; - implicitly by the bot, which creates a default logger if the plugin has none at registration time. -During handler execution, `MsgContext.Logger` is set to: +During handler execution, `MessageContext.Logger` is set to: - the matched plugin logger when one exists; - otherwise the bot logger. That means handler-local logs naturally follow plugin boundaries when possible. -## `MsgContext.Logger` +## `MessageContext.Logger` Inside handlers and middleware, the easiest logger to use is `ctx.Logger`. diff --git a/Middleware-RU.md b/Middleware-RU.md index f9b3e46..7da34d7 100644 --- a/Middleware-RU.md +++ b/Middleware-RU.md @@ -45,7 +45,7 @@ Middleware позволяет запускать логику до обрабо Сигнатура: ```go -func(ctx *laniakea.MsgContext, db T) bool +func(ctx *laniakea.MessageContext, db T) bool ``` Возвращает: @@ -66,7 +66,7 @@ func(ctx *laniakea.MsgContext, db T) bool - middleware идет в goroutine; - выполнение цепочки продолжается сразу; - возвращаемое значение `bool` игнорируется; -- middleware получает копию `MsgContext`. +- middleware получает копию `MessageContext`. Поэтому async middleware подходит только для: - телеметрии; @@ -79,7 +79,7 @@ func(ctx *laniakea.MsgContext, db T) bool - обязательной валидации; - логики, которая должна переписать `ctx` и повлиять на обработчик. -## Почему async middleware получает копию `MsgContext` +## Почему async middleware получает копию `MessageContext` Так библиотека избегает очевидных гонок данных между goroutine middleware и основной цепочкой обработки. @@ -105,5 +105,5 @@ Middleware уровня плагина и команды сохраняют по ## Что читать дальше - [[Commands-and-Plugins-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Middleware]] diff --git a/Middleware.md b/Middleware.md index 95bfa67..52262ca 100644 --- a/Middleware.md +++ b/Middleware.md @@ -11,11 +11,11 @@ Middleware is useful when the same check or side effect should apply in more tha Typical uses: - reject updates from unauthorized users; - log incoming commands and callback payloads; -- attach derived values to `MsgContext`; +- attach derived values to `MessageContext`; - stop processing early when a precondition is not met; - run non-blocking side effects such as analytics or audit logging. -For the handler and plugin model around middleware, see [[Commands-and-Plugins]]. For the fields you can read or update on the context, see [[MsgContext]]. +For the handler and plugin model around middleware, see [[Commands-and-Plugins]]. For the fields you can read or update on the context, see [[MessageContext]]. ## Middleware levels @@ -47,7 +47,7 @@ For non-command update handlers registered through `AddUpdateHandler(...)`, the Important detail: - bot-level middleware runs once per update before routing; -- for non-command update handlers, each matching plugin receives its own cloned `MsgContext`, so one plugin's mutations do not leak into the next plugin's handler chain. +- for non-command update handlers, each matching plugin receives its own cloned `MessageContext`, so one plugin's mutations do not leak into the next plugin's handler chain. ## Synchronous middleware @@ -56,7 +56,7 @@ By default, middleware is synchronous. The executor signature is: ```go -func(ctx *laniakea.MsgContext, db T) bool +func(ctx *laniakea.MessageContext, db T) bool ``` Return values mean: @@ -72,7 +72,7 @@ This makes synchronous middleware the right choice for: Example: ```go -auth := laniakea.NewMiddleware("auth", func(ctx *laniakea.MsgContext, db *App) bool { +auth := laniakea.NewMiddleware("auth", func(ctx *laniakea.MessageContext, db *App) bool { if ctx.From == nil || !db.Allowed(ctx.From.ID) { ctx.Answer("Access denied") return false @@ -86,7 +86,7 @@ auth := laniakea.NewMiddleware("auth", func(ctx *laniakea.MsgContext, db *App) b Middleware can also run asynchronously with `SetAsync(true)`. ```go -audit := laniakea.NewMiddleware("audit", func(ctx *laniakea.MsgContext, db *App) bool { +audit := laniakea.NewMiddleware("audit", func(ctx *laniakea.MessageContext, db *App) bool { db.Audit(ctx.Update.UpdateID, ctx.Text) return true }).SetAsync(true) @@ -96,7 +96,7 @@ Async middleware behaves differently: - it runs in a goroutine; - execution always continues immediately; - its boolean return value is ignored; -- it receives a copied `MsgContext`, not the original pointer. +- it receives a copied `MessageContext`, not the original pointer. That means async middleware is appropriate for: - fire-and-forget logging; @@ -112,7 +112,7 @@ It is not appropriate for: ## Why async middleware gets a copied context -When middleware is async, the library copies `MsgContext` before starting the goroutine. This prevents obvious data races against the handler path. +When middleware is async, the library copies `MessageContext` before starting the goroutine. This prevents obvious data races against the handler path. Practical consequence: - changes you make to the copied `ctx` inside async middleware are local to that goroutine; @@ -121,7 +121,7 @@ Practical consequence: So this pattern does not work: ```go -bad := laniakea.NewMiddleware("bad", func(ctx *laniakea.MsgContext, db *App) bool { +bad := laniakea.NewMiddleware("bad", func(ctx *laniakea.MessageContext, db *App) bool { ctx.Text = "rewritten" return false }).SetAsync(true) @@ -177,7 +177,7 @@ This usually means: ```go bot.AddMiddleware( - laniakea.NewMiddleware("private-only", func(ctx *laniakea.MsgContext, db *App) bool { + laniakea.NewMiddleware("private-only", func(ctx *laniakea.MessageContext, db *App) bool { if ctx.Chat == nil || ctx.Chat.Type != "private" { return false } @@ -191,7 +191,7 @@ bot.AddMiddleware( ```go admin := laniakea.NewPlugin[*App]("admin") admin.AddMiddleware( - laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MsgContext, db *App) bool { + laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MessageContext, db *App) bool { return ctx.From != nil && db.IsAdmin(ctx.From.ID) }), ) @@ -201,7 +201,7 @@ admin.AddMiddleware( ```go ban := admin.NewCommand(banUser, "ban") -ban.Use(laniakea.NewMiddleware("require-reply", func(ctx *laniakea.MsgContext, db *App) bool { +ban.Use(laniakea.NewMiddleware("require-reply", func(ctx *laniakea.MessageContext, db *App) bool { if ctx.Msg == nil || ctx.Msg.ReplyToMessage == nil { ctx.Answer("Reply to a user message first") return false diff --git a/Migration.md b/Migration.md index 986ddfe..9d41d48 100644 --- a/Migration.md +++ b/Migration.md @@ -25,7 +25,70 @@ When jumping across multiple RC versions: 5. Revisit any direct `tgapi` calls and renamed types. 6. Run tests against realistic update payloads and callback data. -The largest migration points in the current history are `rc.4`, `rc.7`, `rc.10`, and `rc.12`. +The largest migration points in the current history are `rc.4`, `rc.7`, `rc.10`, `rc.12`, and the `v1.0.0` stable release. + +## `v1.0.0` + +`v1.0.0` is a public-API hygiene release. Most changes are renames and type-system tightenings that cause compile errors and are easy to fix mechanically. + +### Handler type rename: `MsgContext` → `MessageContext` + +Every handler signature and every explicit type reference to `MsgContext` must be renamed to `MessageContext`. + +```go +// before +func ping(ctx *laniakea.MsgContext, db *App) error { ... } + +// after +func ping(ctx *laniakea.MessageContext, db *App) error { ... } +``` + +This includes `CommandExecutor`, `MiddlewareExecutor`, `SceneContext.MessageContext`, and any local variable type annotations. + +### Runner builder change: `Onetime` and `Timeout` removed + +The `Onetime(bool)` and `Timeout(duration)` builder methods have been replaced by `Every(duration)` and `Async(bool)`. + +```go +// before — one-time sync +runner.Onetime(true).Async(false) + +// after — one-time sync +runner.Async(false) + +// before — periodic +runner.Timeout(5 * time.Minute) + +// after — periodic +runner.Every(5 * time.Minute) +``` + +The default remains async one-shot (`Every(0).Async(true)`), so runners without a builder call are unaffected. + +### Observer method renames + +If you implement the `Observer` interface directly, rename the two affected methods: + +| Before | After | +|---|---| +| `OnReceiveUpdate(UpdateReceivedEvent)` | `OnUpdateReceived(UpdateReceivedEvent)` | +| `OnHandledUpdate(UpdateHandledEvent)` | `OnUpdateHandled(UpdateHandledEvent)` | + +### `Scene.PluginName` unexported + +`Scene.PluginName` was a mutable public field. It is now unexported. Remove any reads or writes to this field; the framework assigns it during `AddPlugins(...)` registration. + +### `SceneSession.Data` unexported + +`SceneSession.Data []byte` was a public field. It is now unexported. Use the accessor helpers: `HasData()`, `BindData(...)`, `SaveData(...)`, `ClearData()`. + +### `BotPayloadType*` constants are now `const` + +`BotPayloadTypeJSON`, `BotPayloadTypeBase64`, `BotPayloadTypeCompact`, and `BotPayloadTypeCompactBase64` were `var`. They are now `const`. Any code assigning to them will fail to compile. + +### Webhook error sentinels + +Inline `errors.New(...)` error values returned from webhook startup have been replaced by exported sentinels. If you were comparing webhook startup errors with `==`, switch to `errors.Is(...)`. ## `v1.0.0-rc.12` diff --git a/MsgContext-RU.md b/MsgContext-RU.md index 13a2e4c..7b232a6 100644 --- a/MsgContext-RU.md +++ b/MsgContext-RU.md @@ -1,12 +1,12 @@ -# MsgContext RU +# MessageContext RU -English version: [[MsgContext]] +English version: [[MessageContext]] -Это краткая русскоязычная версия страницы про `MsgContext`. Полная и наиболее актуальная страница: [[MsgContext]]. +Это краткая русскоязычная версия страницы про `MessageContext`. Полная и наиболее актуальная страница: [[MessageContext]]. -## Что такое `MsgContext` +## Что такое `MessageContext` -`MsgContext` — это объект времени выполнения, который приходит в: +`MessageContext` — это объект времени выполнения, который приходит в: - обработчики команд; - обработчики данных callback; - middleware; @@ -18,7 +18,7 @@ English version: [[MsgContext]] - разобранные аргументы команд и callback; - вспомогательные методы для reply, edit, delete, callback, drafts и localization. -Полную матрицу маршрутизации и гарантий по полям `MsgContext` для разных update types смотри в [[Update-Routing-Model-RU]]. +Полную матрицу маршрутизации и гарантий по полям `MessageContext` для разных update types смотри в [[Update-Routing-Model-RU]]. ## Поля, которые используются чаще всего @@ -107,12 +107,12 @@ English version: [[MsgContext]] ## Drafts и localization -У `MsgContext` есть: +У `MessageContext` есть: - `NewDraft()` - `NewDraftMarkdown()` - `Translate(key)` -Это делает `MsgContext` основной удобной точкой доступа почти для всего кода обработчиков. +Это делает `MessageContext` основной удобной точкой доступа почти для всего кода обработчиков. ## `NewInlineKeyboard(...)` @@ -130,4 +130,4 @@ kb := ctx.NewInlineKeyboard(2) - [[Inline-Keyboards-and-Payloads-RU]] - [[Drafts-RU]] - [[Localization-RU]] -- [[MsgContext]] +- [[MessageContext]] diff --git a/MsgContext.md b/MsgContext.md index 469fc02..f111dee 100644 --- a/MsgContext.md +++ b/MsgContext.md @@ -1,8 +1,8 @@ -# MsgContext +# MessageContext -Russian version: [[MsgContext-RU]] +Russian version: [[MessageContext-RU]] -`MsgContext` is the runtime object passed into command handlers, payload handlers, middleware, and update handlers. +`MessageContext` is the runtime object passed into command handlers, payload handlers, middleware, and update handlers. It gives you access to: - the incoming update @@ -10,7 +10,7 @@ It gives you access to: - parsed command or payload arguments - reply, edit, delete, callback, draft, and localization helpers -If you write handlers, `MsgContext` is the API surface you will use most often. +If you write handlers, `MessageContext` is the API surface you will use most often. For the full routing and field-guarantee matrix by update kind, see [[Update-Routing-Model]]. @@ -63,7 +63,7 @@ Use `FromID` when you only need the identifier and do not want to keep checking Use `Answer(...)` for the normal “reply with text” case. ```go -func start(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func start(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.Answer("Welcome") return nil } @@ -76,7 +76,7 @@ This is the default high-level reply helper for plain text. Use `AnswerLong(...)` when plain text may exceed Telegram’s message limit. ```go -func help(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func help(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.AnswerLong(buildLargeHelpText()) return nil } @@ -92,7 +92,7 @@ Important: Use `Keyboard(...)` when you want to send a message with an inline keyboard. ```go -func menu(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func menu(ctx *laniakea.MessageContext, db laniakea.NoData) error { kb := ctx.NewInlineKeyboard(2). AddCallbackButton("Profile", "profile.open"). AddCallbackButton("Settings", "settings.open") @@ -127,7 +127,7 @@ Use `laniakea.EscapeMarkdownV2(...)` for this. Example: ```go -func whoami(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func whoami(ctx *laniakea.MessageContext, db laniakea.NoData) error { name := laniakea.EscapeMarkdownV2(ctx.From.FirstName) ctx.AnswerMarkdown("*User:* " + name) return nil @@ -141,7 +141,7 @@ Once you already have an `AnswerMessage`, you can edit or delete it. Example: ```go -func slowTask(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func slowTask(ctx *laniakea.MessageContext, db laniakea.NoData) error { msg := ctx.Answer("Working...") if msg == nil { return nil @@ -173,7 +173,7 @@ When handling inline button callbacks, these helpers are especially useful. Edits the callback-linked message. ```go -func approve(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func approve(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.EditCallback("Approved", nil) return nil } @@ -192,7 +192,7 @@ Use: Example: ```go -func approve(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func approve(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.AnswerCbQueryText("Saved") ctx.EditCallback("Saved", nil) return nil @@ -220,7 +220,7 @@ Caption rules differ from normal message text: ## Drafts -`MsgContext` also exposes draft creation helpers: +`MessageContext` also exposes draft creation helpers: - `NewDraft()` - `NewDraftMarkdown()` @@ -246,7 +246,7 @@ This looks up text using the current user’s language when available and falls Example: ```go -func ping(ctx *laniakea.MsgContext, db laniakea.NoData) error { +func ping(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.Answer(ctx.Translate("ping.answer")) return nil } @@ -275,7 +275,7 @@ Use `SendAction(...)` to show activity like typing or uploading. Example: ```go -func report(ctx *laniakea.MsgContext, db *App) error { +func report(ctx *laniakea.MessageContext, db *App) error { ctx.SendAction(tgapi.ChatActionTyping) text, err := db.BuildReport(ctx.FromID) if err != nil { @@ -293,7 +293,7 @@ This is especially useful for slower handlers. A common pattern is: ```go -func profile(ctx *laniakea.MsgContext, db *App) error { +func profile(ctx *laniakea.MessageContext, db *App) error { user, err := db.LoadUser(ctx.FromID) if err != nil { return err @@ -338,7 +338,7 @@ Methods like `EditCallback(...)` and `AnswerCbQueryText(...)` depend on callback ## A practical example ```go -func settings(ctx *laniakea.MsgContext, db *App) error { +func settings(ctx *laniakea.MessageContext, db *App) error { kb := ctx.NewInlineKeyboard(1). AddCallbackButton("Enable notifications", "settings.notifications.enable"). AddCallbackButton("Disable notifications", "settings.notifications.disable") diff --git a/Policies-RU.md b/Policies-RU.md index 8ba8361..f2c5908 100644 --- a/Policies-RU.md +++ b/Policies-RU.md @@ -1,6 +1,6 @@ # Policies -Policies — это полноценная модель правил авторизации в Laniakea. Политика работает поверх нормализованного `MsgContext` и переданных `AppData`, возвращает `nil`, если доступ разрешён, и возвращает ошибку, если действие нужно запретить или сама проверка не смогла корректно выполниться. +Policies — это полноценная модель правил авторизации в Laniakea. Политика работает поверх нормализованного `MessageContext` и переданных `AppData`, возвращает `nil`, если доступ разрешён, и возвращает ошибку, если действие нужно запретить или сама проверка не смогла корректно выполниться. Policies не вводят вторую модель выполнения. Они встраиваются в уже существующий middleware pipeline через `RequirePolicy(...)`, поэтому авторизация остаётся на том же пути маршрутизации, что и остальной фреймворк. @@ -15,7 +15,7 @@ Policies не вводят вторую модель выполнения. Он ## Основной API ```go -type Policy[T laniakea.AppData] func(ctx *laniakea.MsgContext, data T) error +type Policy[T laniakea.AppData] func(ctx *laniakea.MessageContext, data T) error func RequirePolicy[T laniakea.AppData](name string, p Policy[T]) Middleware[T] @@ -62,7 +62,7 @@ plugin.UsePolicy( - `RequireBotAdmin(...)` - `RequireCallbackFromUser(...)` -Эти helpers используют нормализованные данные `MsgContext`. В частности, chat-aware политики опираются на `Chat` и `ChatID`, которые теперь заполняются не только для message-backed обновлений. +Эти helpers используют нормализованные данные `MessageContext`. В частности, chat-aware политики опираются на `Chat` и `ChatID`, которые теперь заполняются не только для message-backed обновлений. ## Композиция @@ -133,6 +133,6 @@ policy := laniakea.NotPolicy(laniakea.RequirePrivateChat()) Связанные страницы: - [[Middleware-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Commands-and-Plugins-RU]] - [[Framework-Backlog-RU]] diff --git a/Policies.md b/Policies.md index 7ae0cd6..48dc014 100644 --- a/Policies.md +++ b/Policies.md @@ -1,6 +1,6 @@ # Policies -Policies are Laniakea's first-class authorization rules. A policy runs against the normalized `MsgContext` and injected `AppData`, returns `nil` when access is allowed, and returns an error when access should be denied or when the check itself fails. +Policies are Laniakea's first-class authorization rules. A policy runs against the normalized `MessageContext` and injected `AppData`, returns `nil` when access is allowed, and returns an error when access should be denied or when the check itself fails. Policies do not introduce a second execution model. They plug into the existing middleware pipeline through `RequirePolicy(...)`, so authorization stays on the same routing path as the rest of the framework. @@ -15,7 +15,7 @@ Policies do not introduce a second execution model. They plug into the existing ## Core API ```go -type Policy[T laniakea.AppData] func(ctx *laniakea.MsgContext, data T) error +type Policy[T laniakea.AppData] func(ctx *laniakea.MessageContext, data T) error func RequirePolicy[T laniakea.AppData](name string, p Policy[T]) Middleware[T] @@ -62,7 +62,7 @@ The current built-in helpers focus on common Telegram-specific access checks: - `RequireBotAdmin(...)` - `RequireCallbackFromUser(...)` -These helpers use normalized `MsgContext` data. In particular, chat-aware policies rely on `Chat` and `ChatID`, which are now populated for more update kinds than only message-backed ones. +These helpers use normalized `MessageContext` data. In particular, chat-aware policies rely on `Chat` and `ChatID`, which are now populated for more update kinds than only message-backed ones. ## Composition @@ -133,6 +133,6 @@ Those features can be added later if the existing `Policy[T]` model proves too s Related pages: - [[Middleware]] -- [[MsgContext]] +- [[MessageContext]] - [[Commands-and-Plugins]] - [[Framework-Backlog]] diff --git a/Recipes.md b/Recipes.md index 27cf2b4..35a9dbe 100644 --- a/Recipes.md +++ b/Recipes.md @@ -14,11 +14,11 @@ type App struct{} func (a *App) IsAdmin(userID int64) bool { return userID == 42 } admin := laniakea.NewPlugin[*App]("admin") -admin.AddMiddleware(laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MsgContext, app *App) bool { +admin.AddMiddleware(laniakea.NewMiddleware("admin-only", func(ctx *laniakea.MessageContext, app *App) bool { return ctx.From != nil && app.IsAdmin(ctx.From.ID) })) -admin.NewCommand(func(ctx *laniakea.MsgContext, app *App) error { +admin.NewCommand(func(ctx *laniakea.MessageContext, app *App) error { ctx.Answer("Admin command executed") return nil }, "reload") @@ -31,14 +31,14 @@ Use a payload handler for inline keyboard callbacks. ```go menu := laniakea.NewPlugin[laniakea.NoData]("menu") -menu.NewCommand(func(ctx *laniakea.MsgContext, db laniakea.NoData) error { +menu.NewCommand(func(ctx *laniakea.MessageContext, db laniakea.NoData) error { kb := ctx.NewInlineKeyboard(1) kb.AddCallbackButton("Open settings", "settings") ctx.Keyboard("Choose an action", kb) return nil }, "menu") -menu.NewPayload(func(ctx *laniakea.MsgContext, db laniakea.NoData) error { +menu.NewPayload(func(ctx *laniakea.MessageContext, db laniakea.NoData) error { ctx.EditCallback("Settings screen", nil) return nil }, "settings") @@ -49,7 +49,7 @@ menu.NewPayload(func(ctx *laniakea.MsgContext, db laniakea.NoData) error { Use `AnswerLong(...)` when you want explicit splitting into multiple safe Telegram messages. ```go -plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db *App) error { report := buildLargePlainTextReport() ctx.AnswerLong(report) return nil @@ -71,7 +71,7 @@ l10n := laniakea.NewL10n("en"). bot.SetL10n(l10n) -plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db *App) error { ctx.Answer(ctx.Translate("greeting")) return nil }, "start") @@ -82,7 +82,7 @@ plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { Use `AddUpdateHandler(...)` for Telegram update types that are outside the command and payload flow. ```go -plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MsgContext, db *App) error { +plugin.AddUpdateHandler(tgapi.UpdateTypeInlineQuery, func(ctx *laniakea.MessageContext, db *App) error { if ctx.From != nil { ctx.Logger.Infoln("inline query from", ctx.From.ID) } @@ -97,7 +97,7 @@ This is usually cleaner than forcing non-command traffic through a command parse Use drafts when you want to build a reply progressively and publish it once at the end. ```go -plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db *App) error { draft := ctx.NewDraft() if draft == nil { return nil @@ -119,7 +119,7 @@ plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { Use the higher-level handler flow for routing, but drop down to `tgapi` uploader methods when you need multipart upload behavior. ```go -plugin.NewCommand(func(ctx *laniakea.MsgContext, db *App) error { +plugin.NewCommand(func(ctx *laniakea.MessageContext, db *App) error { uploader := tgapi.NewUploader(ctx.Api) defer uploader.Close() diff --git a/Runners-RU.md b/Runners-RU.md index f63d092..1e8c8bf 100644 --- a/Runners-RU.md +++ b/Runners-RU.md @@ -22,43 +22,59 @@ Runner — это фоновая или одноразовая задача, к runner := laniakea.NewRunner("cleanup", fn) ``` -Потом конфигурируются методы builder: -- `Onetime(bool)` -- `Async(bool)` -- `Timeout(duration)` +Методы builder: +- `Every(time.Duration)` — интервал повторного запуска. Ноль (по умолчанию) означает одноразовый запуск; положительное значение — периодический. +- `Async(bool)` — если `true` (по умолчанию), запускается в goroutine; если `false`, блокирует запуск runtime. ## Основные режимы -### Одноразовый sync +### Одноразовый async (по умолчанию) -- выполняется один раз; -- блокирует запуск; -- полезен для работы, критичной на старте. - -### Одноразовый async +```go +runner := laniakea.NewRunner("prefetch", fn) +``` - выполняется один раз; - стартует в goroutine; - не блокирует запуск. +### Одноразовый sync + +```go +runner := laniakea.NewRunner("warmup", fn).Async(false) +``` + +- выполняется один раз; +- блокирует запуск до завершения; +- полезен для работы, критичной на старте. + ### Повторяющийся async -- работает циклически; +```go +runner := laniakea.NewRunner("cleanup", fn).Every(time.Minute) +``` + +- работает циклически с заданным интервалом; - использует ticker; - живет до `ctx.Done()`. ## Невалидная конфигурация -Повторяющийся synchronous runner считается невалидным и пропускается с предупреждением. - -Также повторяющийся async runner без `Timeout(...)` пропускается. +Повторяющийся synchronous runner (`Every(d > 0).Async(false)`) считается невалидным и пропускается с предупреждением — блокировать запуск бесконечно никогда не имеет смысла. ## Когда стартуют фоновые задачи -Фоновые задачи стартуют из `RunWithContext(...)` или `RunWebHookWithContext(...)`, а не из `NewBot(...)`. +Фоновые задачи стартуют из `RunWithContext(...)` или `RunWebhookWithContext(...)`, а не из `NewBot(...)`. Это часть фазы выполнения, а не фазы сборки конфигурации. +## Обработка ошибок + +Если runner возвращает ошибку: +- бот логирует предупреждение; +- через observer отправляется `ErrorEvent`; +- бот продолжает работу. + ## Семантика остановки При корректной остановке бот: @@ -67,9 +83,27 @@ runner := laniakea.NewRunner("cleanup", fn) Поэтому код runner должен завершаться достаточно быстро. +## Практические примеры + +### Периодическая очистка + +```go +cleanup := laniakea.NewRunner("cleanup", func(bot *laniakea.Bot[*App]) error { + return bot.GetAppData().CleanupExpired() +}).Every(5 * time.Minute) +``` + +### Блокирующий запуск при старте + +```go +warmup := laniakea.NewRunner("warmup", func(bot *laniakea.Bot[*App]) error { + return bot.GetAppData().WarmCaches() +}).Async(false) +``` + ## Рекомендации -- Для периодических задач используй повторяющийся async runner с timeout. +- Для периодических задач используй повторяющийся async runner с `Every(...)`. - Для критичной стартовой работы используй одноразовый sync runner. - Не держи сложную бизнес-логику внутри runner; лучше делегируй ее в обычные сервисы приложения. diff --git a/Runners.md b/Runners.md index 10b97ef..9e62b35 100644 --- a/Runners.md +++ b/Runners.md @@ -13,10 +13,9 @@ Each runner is built from: - a function `func(*Bot[T]) error`; - execution flags configured through builder methods. -Main builder methods: -- `Onetime(bool)` -- `Async(bool)` -- `Timeout(duration)` +Builder methods: +- `Every(time.Duration)` — sets the repeat interval. Zero (default) means run once; positive means repeat. +- `Async(bool)` — if `true` (default), the runner runs in a goroutine; if `false`, it blocks runtime startup. ## Creating a runner @@ -29,36 +28,21 @@ cleanup := laniakea.NewRunner("cleanup", func(bot *laniakea.Bot[*App]) error { ``` By default, a new runner is: -- asynchronous; -- not one-time; -- configured with zero timeout. +- asynchronous (`Async(true)`); +- one-shot (`Every(0)`). -That default means you almost always want to finish configuration before adding it to the bot. +That default fires the runner once in a goroutine when the bot starts. ## Runner execution modes There are three meaningful configurations. -### One-time synchronous +### One-time asynchronous (default) ```go -runner := laniakea.NewRunner("warmup", fn). - Onetime(true). - Async(false) -``` - -Behavior: -- runs once; -- blocks startup until it finishes; -- logs a warning if it takes longer than two seconds. - -Use this for startup work that must complete before the bot is considered ready. - -### One-time asynchronous - -```go -runner := laniakea.NewRunner("prefetch", fn). - Onetime(true) +runner := laniakea.NewRunner("prefetch", fn) +// or explicitly: +runner := laniakea.NewRunner("prefetch", fn).Every(0).Async(true) ``` Behavior: @@ -68,31 +52,37 @@ Behavior: Use this for fire-and-forget startup work that is useful but not required before handling updates. -### Repeating asynchronous +### One-time synchronous ```go -runner := laniakea.NewRunner("cleanup", fn). - Timeout(time.Minute) +runner := laniakea.NewRunner("warmup", fn).Async(false) ``` Behavior: -- runs on a ticker; +- runs once; +- blocks startup until it finishes; +- logs a warning if it takes longer than two seconds. + +Use this for startup work that must complete before the bot is considered ready. + +### Repeating asynchronous + +```go +runner := laniakea.NewRunner("cleanup", fn).Every(time.Minute) +``` + +Behavior: +- runs on a ticker with the configured interval; - keeps running until `ctx.Done()` from the bot runtime context; - is awaited during graceful shutdown. Use this for recurring background jobs. -## Invalid configuration +## Invalid configurations -One configuration is intentionally treated as invalid: +One configuration is intentionally treated as invalid and skipped with a warning: -- `Onetime(false).Async(false)` - -That means: -- synchronous repeating runners are skipped; -- the bot logs a warning instead of trying to run them inline forever. - -Also, repeating async runners with `Timeout(0)` are skipped with a warning. +- `Every(d > 0).Async(false)` — a periodic sync runner blocks startup indefinitely, which is never correct. ## Registration @@ -106,7 +96,7 @@ Runners with an empty name are skipped with a warning, so always give them a sta ## Lifecycle -Runners are not started by `NewBot(...)`. They start from `RunWithContext(...)` or `RunWebHookWithContext(...)`, right before the bot begins polling or webhook ingestion. +Runners are not started by `NewBot(...)`. They start from `RunWithContext(...)` or `RunWebhookWithContext(...)`, right before the bot begins polling or webhook ingestion. That means runner execution belongs to the bot's runtime lifecycle, not to its configuration phase. @@ -125,6 +115,7 @@ Runner functions return `error`. When a runner returns a non-nil error: - the bot logs a warning; +- an `ErrorEvent` is emitted through the observer; - the process continues; - the bot does not crash automatically. @@ -134,7 +125,7 @@ If a runner must be fatal for startup, make it one-time synchronous and return a ## Shutdown behavior -`RunWithContext(...)` and `RunWebHookWithContext(...)` wait for runner completion in two groups: +`RunWithContext(...)` and `RunWebhookWithContext(...)` wait for runner completion in two groups: - one-time async runners; - background repeating runners. @@ -149,15 +140,15 @@ This means graceful shutdown includes runner shutdown, but only if your runner f ```go cleanup := laniakea.NewRunner("cleanup", func(bot *laniakea.Bot[*App]) error { return bot.GetAppData().CleanupExpired() -}).Timeout(5 * time.Minute) +}).Every(5 * time.Minute) ``` -### Startup warmup +### Startup warmup (blocking) ```go warmup := laniakea.NewRunner("warmup", func(bot *laniakea.Bot[*App]) error { return bot.GetAppData().WarmCaches() -}).Onetime(true).Async(false) +}).Async(false) ``` ### Background metrics push @@ -165,25 +156,24 @@ warmup := laniakea.NewRunner("warmup", func(bot *laniakea.Bot[*App]) error { ```go metrics := laniakea.NewRunner("metrics", func(bot *laniakea.Bot[*App]) error { return pushMetrics(bot.GetAppData()) -}).Timeout(30 * time.Second) +}).Every(30 * time.Second) ``` ## Recommendations - Use one-time sync runners only for short startup-critical work. - Use repeating async runners for periodic jobs. -- Always set `Timeout(...)` on repeating runners. +- Always set `Every(...)` on repeating runners. - Keep runner bodies small and delegate complex work to regular application services. - Treat runner names as operational identifiers that should make sense in logs. ## Caveats - Runners do not receive `context.Context` directly; they receive `*Bot[T]`. -- Repeating sync runners are skipped. -- Repeating async runners without timeout are skipped. +- Periodic sync runners are skipped with a warning. - Slow one-time sync runners delay bot startup. ## Related pages - [[Bot-Lifecycle]] -- [[Testing-Bots-with-Laniakea]] +- [[Testing-Bots-with-Laniakea]] \ No newline at end of file diff --git a/Scenes-RU.md b/Scenes-RU.md index 04c3528..a787159 100644 --- a/Scenes-RU.md +++ b/Scenes-RU.md @@ -1,11 +1,11 @@ # Scenes -Scenes — это слой маршрутизации Laniakea с сохранением состояния для многошаговых и модальных диалогов. Сцена регистрируется внутри плагина, запускается через `MsgContext`, хранится через `SessionStore` и получает обновления раньше обычной маршрутизации команд, пока её сессия активна. +Scenes — это слой маршрутизации Laniakea с сохранением состояния для многошаговых и модальных диалогов. Сцена регистрируется внутри плагина, запускается через `MessageContext`, хранится через `SessionStore` и получает обновления раньше обычной маршрутизации команд, пока её сессия активна. ## Что дают сцены - Регистрацию через `Plugin.NewScene(...)` и `Plugin.AddScene(...)`. -- Явный вход и выход через `MsgContext.EnterScene(...)`, `EnterSceneStep(...)` и `ExitScene()`. +- Явный вход и выход через `MessageContext.EnterScene(...)`, `EnterSceneStep(...)` и `ExitScene()`. - Области действия сессии на пользователя, чат или пару пользователь-чат. - Обработчики шагов, локальные команды сцены и резервный обработчик сообщений на уровне сцены. - JSON-состояние сцены через `SceneContext.BindData(...)` и `SaveData(...)`. @@ -67,13 +67,13 @@ plugin.NewScene("signup"). ## Модель обработчиков -Обычные команды используют `*MsgContext`. Обработчики сцен используют `*SceneContext`. +Обычные команды используют `*MessageContext`. Обработчики сцен используют `*SceneContext`. ```go type SceneHandler[T any] func(ctx *SceneContext, db T) (SceneResult, error) ``` -`SceneContext` встраивает `*MsgContext` и добавляет вспомогательные методы для сцен: +`SceneContext` встраивает `*MessageContext` и добавляет вспомогательные методы для сцен: - `ctx.Stay()` - `ctx.Next(step)` @@ -137,7 +137,7 @@ func askName(ctx *laniakea.SceneContext, db *App) (laniakea.SceneResult, error) Точка входа из команды: ```go -func startSignup(ctx *laniakea.MsgContext, db *App) error { +func startSignup(ctx *laniakea.MessageContext, db *App) error { return ctx.EnterScene("signup") } ``` @@ -174,6 +174,6 @@ func cancelSignup(ctx *laniakea.SceneContext, db *App) (laniakea.SceneResult, er Связанные страницы: - [[Commands-and-Plugins-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Middleware-RU]] - [[Bot-Lifecycle-RU]] diff --git a/Scenes.md b/Scenes.md index d3698d4..adf3523 100644 --- a/Scenes.md +++ b/Scenes.md @@ -1,11 +1,11 @@ # Scenes -Scenes are Laniakea's stateful routing layer for multi-step and modal bot flows. A scene is registered inside a plugin, entered through `MsgContext`, stored through `SessionStore`, and routed before normal command handling while the session is active. +Scenes are Laniakea's stateful routing layer for multi-step and modal bot flows. A scene is registered inside a plugin, entered through `MessageContext`, stored through `SessionStore`, and routed before normal command handling while the session is active. ## What scenes give you - Scene registration through `Plugin.NewScene(...)` and `Plugin.AddScene(...)`. -- Explicit entry and exit through `MsgContext.EnterScene(...)`, `EnterSceneStep(...)`, and `ExitScene()`. +- Explicit entry and exit through `MessageContext.EnterScene(...)`, `EnterSceneStep(...)`, and `ExitScene()`. - Per-user, per-chat, or per-user-chat session scopes. - Step handlers, scene-local commands, and a scene-level message fallback. - JSON-backed scene state through `SceneContext.BindData(...)` and `SaveData(...)`. @@ -67,13 +67,13 @@ plugin.NewScene("signup"). ## Handler model -Normal commands use `*MsgContext`. Scene handlers use `*SceneContext`. +Normal commands use `*MessageContext`. Scene handlers use `*SceneContext`. ```go type SceneHandler[T any] func(ctx *SceneContext, db T) (SceneResult, error) ``` -`SceneContext` embeds `*MsgContext` and adds scene helpers: +`SceneContext` embeds `*MessageContext` and adds scene helpers: - `ctx.Stay()` - `ctx.Next(step)` @@ -137,7 +137,7 @@ The store contract stays intentionally small because `Data []byte` is storage-ag Command entry: ```go -func startSignup(ctx *laniakea.MsgContext, db *App) error { +func startSignup(ctx *laniakea.MessageContext, db *App) error { return ctx.EnterScene("signup") } ``` @@ -174,6 +174,6 @@ func cancelSignup(ctx *laniakea.SceneContext, db *App) (laniakea.SceneResult, er Related pages: - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] - [[Middleware]] - [[Bot-Lifecycle]] diff --git a/Testing-Bots-with-Laniakea-RU.md b/Testing-Bots-with-Laniakea-RU.md index 79e633b..ce4af97 100644 --- a/Testing-Bots-with-Laniakea-RU.md +++ b/Testing-Bots-with-Laniakea-RU.md @@ -10,7 +10,7 @@ Laniakea хорошо тестируется обычными Go unit tests. В репозитории уже используются паттерны вроде: - fake HTTP transport для `tgapi`; -- прямые тесты для вспомогательных методов `MsgContext`; +- прямые тесты для вспомогательных методов `MessageContext`; - routing tests для commands и payloads; - runner tests. @@ -35,7 +35,7 @@ Laniakea хорошо тестируется обычными Go unit tests. ## Тесты для логики обработчиков Для тестов уровня обработчика обычно полезно: -- собрать `MsgContext`; +- собрать `MessageContext`; - вызвать обработчик напрямую; - проверить побочные эффекты и ответы. @@ -63,5 +63,5 @@ Laniakea хорошо тестируется обычными Go unit tests. ## Что читать дальше - [[Runners-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Testing-Bots-with-Laniakea]] diff --git a/Testing-Bots-with-Laniakea.md b/Testing-Bots-with-Laniakea.md index 1286c8d..29fdbbf 100644 --- a/Testing-Bots-with-Laniakea.md +++ b/Testing-Bots-with-Laniakea.md @@ -21,15 +21,15 @@ Good test targets include: The most practical approach is: 1. isolate one behavior; -2. create a small bot, plugin, or `MsgContext`; +2. create a small bot, plugin, or `MessageContext`; 3. use a fake HTTP client when you need to inspect Telegram requests; 4. assert the outgoing request shape or returned behavior directly. This keeps tests fast and independent from real Telegram infrastructure. -## Testing `MsgContext` helpers +## Testing `MessageContext` helpers -Many helper methods can be tested by constructing a `MsgContext` directly. +Many helper methods can be tested by constructing a `MessageContext` directly. Common ingredients: - a fake `tgapi.API` with a custom `http.Client`; @@ -39,7 +39,7 @@ Common ingredients: Example pattern: ```go -ctx := &laniakea.MsgContext{ +ctx := &laniakea.MessageContext{ Api: api, Msg: &tgapi.Message{Chat: &tgapi.Chat{ID: 42, Type: string(tgapi.ChatTypePrivate)}}, Logger: slog.CreateLogger(), @@ -64,7 +64,7 @@ This is especially useful for: - split long-message requests; - keyboard attachment behavior. -The repository already uses this pattern extensively for `MsgContext` helper tests. +The repository already uses this pattern extensively for `MessageContext` helper tests. ## Testing long replies @@ -96,7 +96,7 @@ For routing tests, create a small bot with: Then call the bot's handling path in a focused test and assert: - which handler was called; -- what `MsgContext` fields were populated; +- what `MessageContext` fields were populated; - whether context mutations leaked across plugins. This is particularly useful for: @@ -184,4 +184,4 @@ When you fix a bug, consider adding a test for: - [[Commands-and-Plugins]] - [[Error-Handling]] - [[Runners]] -- [[MsgContext]] +- [[MessageContext]] diff --git a/Update-Routing-Model-RU.md b/Update-Routing-Model-RU.md index f297047..2383ed4 100644 --- a/Update-Routing-Model-RU.md +++ b/Update-Routing-Model-RU.md @@ -2,9 +2,9 @@ English version: [[Update-Routing-Model]] -Эта страница фиксирует текущий контракт маршрутизации обновлений в Laniakea: какие Telegram update types идут через команды, какие через данные callback, какие через generic update handlers, и какие гарантии по `MsgContext` существуют в каждом потоке. +Эта страница фиксирует текущий контракт маршрутизации обновлений в Laniakea: какие Telegram update types идут через команды, какие через данные callback, какие через generic update handlers, и какие гарантии по `MessageContext` существуют в каждом потоке. -Это описание текущего поведения фреймворка, а не отдельная новая API-поверхность. Цель страницы — сделать уже существующую маршрутизацию и нормализацию `MsgContext` явной и тестируемой. +Это описание текущего поведения фреймворка, а не отдельная новая API-поверхность. Цель страницы — сделать уже существующую маршрутизацию и нормализацию `MessageContext` явной и тестируемой. ## Верхнеуровневая маршрутизация @@ -23,7 +23,7 @@ English version: [[Update-Routing-Model]] ## Что делает `prepareUpdateCtx(...)` -До маршрутизации обработчиков Laniakea нормализует `MsgContext` из входящего Telegram update. +До маршрутизации обработчиков Laniakea нормализует `MessageContext` из входящего Telegram update. Эта нормализация намеренно шире, чем command и payload routing: - некоторые update types заполняют `ctx.Msg` @@ -101,12 +101,12 @@ Generic update handlers регистрируются через `Plugin.AddUpdat - `ctx.Text` не нормализуется - `ctx.Args` не нормализуется - `ctx.Prefix` не нормализуется -- каждый plugin update handler получает свою копию `MsgContext` struct +- каждый plugin update handler получает свою копию `MessageContext` struct Важное ограничение: -- копируется сам `MsgContext`, но не обещается глубокая копия всех вложенных Telegram-структур +- копируется сам `MessageContext`, но не обещается глубокая копия всех вложенных Telegram-структур -## Нормализованные поля `MsgContext` по видам update +## Нормализованные поля `MessageContext` по видам update ### Update types, которые несут message @@ -176,6 +176,6 @@ Generic update handlers регистрируются через `Plugin.AddUpdat ## Связанные страницы - [[Commands-and-Plugins-RU]] -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Scenes-RU]] - [[Bot-Lifecycle-RU]] diff --git a/Update-Routing-Model.md b/Update-Routing-Model.md index c66a2d0..c0fa2ac 100644 --- a/Update-Routing-Model.md +++ b/Update-Routing-Model.md @@ -2,9 +2,9 @@ Russian version: [[Update-Routing-Model-RU]] -This page defines the current update-routing contract in Laniakea: which Telegram update kinds go through command routing, which go through payload routing, which go through generic update handlers, and what `MsgContext` guarantees exist in each path. +This page defines the current update-routing contract in Laniakea: which Telegram update kinds go through command routing, which go through payload routing, which go through generic update handlers, and what `MessageContext` guarantees exist in each path. -This is a model of current framework behavior, not a second API surface. The goal is to make the existing routing and `MsgContext` normalization explicit and testable. +This is a model of current framework behavior, not a second API surface. The goal is to make the existing routing and `MessageContext` normalization explicit and testable. ## Top-level routing @@ -23,7 +23,7 @@ Important: ## What `prepareUpdateCtx(...)` does -Before handler routing, Laniakea normalizes a `MsgContext` from the incoming Telegram update. +Before handler routing, Laniakea normalizes a `MessageContext` from the incoming Telegram update. That normalization is intentionally broader than command and payload routing: - some update kinds populate `ctx.Msg` @@ -101,12 +101,12 @@ General guarantees: - `ctx.Text` is not normalized - `ctx.Args` is not normalized - `ctx.Prefix` is not normalized -- each plugin update handler receives its own copied `MsgContext` struct +- each plugin update handler receives its own copied `MessageContext` struct Important limitation: - the copied context is an isolated struct copy, not a deep copy of all nested Telegram payload objects -## Normalized `MsgContext` fields by update kind +## Normalized `MessageContext` fields by update kind ### Message-backed update kinds @@ -176,6 +176,6 @@ Important: ## Related pages - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] - [[Scenes]] - [[Bot-Lifecycle]] diff --git a/Webhook-Runtime-RU.md b/Webhook-Runtime-RU.md index 5cd534e..150e890 100644 --- a/Webhook-Runtime-RU.md +++ b/Webhook-Runtime-RU.md @@ -2,10 +2,10 @@ English version: [[Webhook-Runtime]] -Эта страница объясняет bot-level webhook runtime в Laniakea: как работает `RunWebHookWithContext(...)`, чем он отличается от низкоуровневых webhook-вызовов в `tgapi` и какие runtime-гарантии он делит с polling-режимом. +Эта страница объясняет bot-level webhook runtime в Laniakea: как работает `RunWebhookWithContext(...)`, чем он отличается от низкоуровневых webhook-вызовов в `tgapi` и какие runtime-гарантии он делит с polling-режимом. Важно про naming: -- текущий публичный API использует историческое написание `WebHook` в идентификаторах вроде `RunWebHookWithContext(...)`, `RunWebHook(...)` и `BotWebHookOpts`; +- текущий публичный API использует историческое написание `WebHook` в идентификаторах вроде `RunWebhookWithContext(...)`, `RunWebhook(...)` и `BotWebhookOpts`; - в тексте страницы используется обычное слово "webhook", но в примерах остаются реальные имена Go API. ## Когда использовать webhook runtime @@ -25,11 +25,11 @@ English version: [[Webhook-Runtime]] ## Точки входа Главные bot-level точки входа такие: -- `RunWebHookWithContext(ctx, opts, tlsFiles...)` -- `RunWebHook(opts, tlsFiles...)` -- `NewBotWebHookOpts()` +- `RunWebhookWithContext(ctx, opts, tlsFiles...)` +- `RunWebhook(opts, tlsFiles...)` +- `NewBotWebhookOpts()` -`RunWebHook(...)` — это просто короткая форма для `RunWebHookWithContext(context.Background(), ...)`. +`RunWebhook(...)` — это просто короткая форма для `RunWebhookWithContext(context.Background(), ...)`. Обычный шаблон выглядит так: @@ -46,20 +46,20 @@ defer bot.Close() bot.SetAppData(app) bot.AddPlugins(plugin) -webhookOpts := laniakea.NewBotWebHookOpts(). +webhookOpts := laniakea.NewBotWebhookOpts(). SetURL("https://bot.example.com"). SetPath("/telegram"). SetLocalPort(8080). SetSecretToken("shared-secret") -if err := bot.RunWebHookWithContext(ctx, webhookOpts); err != nil { +if err := bot.RunWebhookWithContext(ctx, webhookOpts); err != nil { return err } ``` ## Что именно берет на себя bot-level runtime -`RunWebHookWithContext(...)` — это не просто обертка над Telegram `setWebhook`. +`RunWebhookWithContext(...)` — это не просто обертка над Telegram `setWebhook`. Он: - валидирует bot-level условия старта, например prefixes и наличие зарегистрированных plugins; @@ -86,7 +86,7 @@ Webhook runtime использует те же основные гарантии ## Основные webhook options -`BotWebHookOpts` управляет и регистрацией webhook у Telegram, и локальным HTTP server. +`BotWebhookOpts` управляет и регистрацией webhook у Telegram, и локальным HTTP server. Поля, которые важны в первую очередь: @@ -167,12 +167,12 @@ Webhook runtime использует те же основные гарантии ## Поведение HTTP и TLS -По умолчанию `RunWebHookWithContext(...)` поднимает обычный HTTP server на `LocalPort`. +По умолчанию `RunWebhookWithContext(...)` поднимает обычный HTTP server на `LocalPort`. Если передать два TLS-файла, локально стартует HTTPS. Важно: -- текущий публичный API ожидает существующий порядок аргументов `key, cert` при вызове `RunWebHookWithContext(...)`; +- текущий публичный API ожидает существующий порядок аргументов `key, cert` при вызове `RunWebhookWithContext(...)`; - это отличается от более привычной ментальной модели `cert, key`, которую многие Go-разработчики ожидают от `ListenAndServeTLS`. Поэтому в реальном setup лучше писать этот вызов максимально явно. @@ -202,7 +202,7 @@ Webhook runtime использует те же основные гарантии - `URL` — это то, что видит Telegram; - `Path` и `LocalPort` — это то, что реально обслуживает твой бот; - в production эти значения часто относятся к разным слоям инфраструктуры. -- если ты переводишь работающий deployment с webhook-режима на polling, сначала удали webhook через `CloseWebHook()` или `tgapi.DeleteWebhook(...)`; Telegram не прекращает webhook-доставку автоматически. +- если ты переводишь работающий deployment с webhook-режима на polling, сначала удали webhook через `CloseWebhook()` или `tgapi.DeleteWebhook(...)`; Telegram не прекращает webhook-доставку автоматически. ## Связь с webhook methods в `tgapi` @@ -221,7 +221,7 @@ Webhook runtime использует те же основные гарантии когда тебе нужна собственная инфраструктура вокруг webhook path и ты не хочешь, чтобы сам бот владел HTTP server. То есть: -- `RunWebHookWithContext(...)` — это framework runtime API; +- `RunWebhookWithContext(...)` — это framework runtime API; - webhook methods из `tgapi` — это низкоуровневые transport primitives. ## Частые ошибки diff --git a/Webhook-Runtime.md b/Webhook-Runtime.md index 9b168f0..e41acc1 100644 --- a/Webhook-Runtime.md +++ b/Webhook-Runtime.md @@ -2,10 +2,10 @@ Russian version: [[Webhook-Runtime-RU]] -This page explains the bot-level webhook runtime in Laniakea: how `RunWebHookWithContext(...)` works, what it owns, how it differs from low-level `tgapi` webhook calls, and what runtime guarantees it shares with polling mode. +This page explains the bot-level webhook runtime in Laniakea: how `RunWebhookWithContext(...)` works, what it owns, how it differs from low-level `tgapi` webhook calls, and what runtime guarantees it shares with polling mode. Important naming note: -- the current public API uses the historical `WebHook` spelling in identifiers such as `RunWebHookWithContext(...)`, `RunWebHook(...)`, and `BotWebHookOpts`; +- the current public API uses the historical `WebHook` spelling in identifiers such as `RunWebhookWithContext(...)`, `RunWebhook(...)`, and `BotWebhookOpts`; - this page uses the more common English term "webhook" for readability, but examples keep the actual Go API names. ## When to use webhook runtime @@ -25,11 +25,11 @@ Use polling when: ## Entry points The main bot-level entry points are: -- `RunWebHookWithContext(ctx, opts, tlsFiles...)` -- `RunWebHook(opts, tlsFiles...)` -- `NewBotWebHookOpts()` +- `RunWebhookWithContext(ctx, opts, tlsFiles...)` +- `RunWebhook(opts, tlsFiles...)` +- `NewBotWebhookOpts()` -`RunWebHook(...)` is only a shorthand for `RunWebHookWithContext(context.Background(), ...)`. +`RunWebhook(...)` is only a shorthand for `RunWebhookWithContext(context.Background(), ...)`. The usual pattern looks like: @@ -46,20 +46,20 @@ defer bot.Close() bot.SetAppData(app) bot.AddPlugins(plugin) -webhookOpts := laniakea.NewBotWebHookOpts(). +webhookOpts := laniakea.NewBotWebhookOpts(). SetURL("https://bot.example.com"). SetPath("/telegram"). SetLocalPort(8080). SetSecretToken("shared-secret") -if err := bot.RunWebHookWithContext(ctx, webhookOpts); err != nil { +if err := bot.RunWebhookWithContext(ctx, webhookOpts); err != nil { return err } ``` ## What the bot-level runtime owns -`RunWebHookWithContext(...)` is more than a wrapper around Telegram's `setWebhook`. +`RunWebhookWithContext(...)` is more than a wrapper around Telegram's `setWebhook`. It: - validates bot startup preconditions such as prefixes and registered plugins; @@ -86,7 +86,7 @@ If you already understand [[Bot-Lifecycle]], the webhook mode should feel like a ## Main webhook options -`BotWebHookOpts` controls both Telegram webhook registration and the local server behavior. +`BotWebhookOpts` controls both Telegram webhook registration and the local server behavior. Fields you will care about first: @@ -167,12 +167,12 @@ Use this only when you specifically need Telegram's `ip_address` webhook option. ## HTTP and TLS behavior -By default, `RunWebHookWithContext(...)` starts a plain HTTP server on `LocalPort`. +By default, `RunWebhookWithContext(...)` starts a plain HTTP server on `LocalPort`. If you pass two TLS files, it starts HTTPS locally instead. Important: -- the current public API expects the existing key-then-cert argument order when calling `RunWebHookWithContext(...)`; +- the current public API expects the existing key-then-cert argument order when calling `RunWebhookWithContext(...)`; - that differs from the more common `cert, key` mental model many Go developers expect from `ListenAndServeTLS`. Be explicit in your own setup code so this does not become a deployment footgun. @@ -202,7 +202,7 @@ Also keep in mind: - `URL` is what Telegram sees; - `Path` and `LocalPort` are what your bot actually serves; - these are often not the same thing in production. -- if you switch a running deployment from webhook mode to polling, delete the webhook first with `CloseWebHook()` or `tgapi.DeleteWebhook(...)`; Telegram does not stop webhook delivery automatically. +- if you switch a running deployment from webhook mode to polling, delete the webhook first with `CloseWebhook()` or `tgapi.DeleteWebhook(...)`; Telegram does not stop webhook delivery automatically. ## Relation to `tgapi` webhook methods @@ -221,7 +221,7 @@ Use lower-level `tgapi` calls such as: when you need custom infrastructure around the webhook path and do not want the bot to own the HTTP server itself. In other words: -- `RunWebHookWithContext(...)` is the framework runtime API; +- `RunWebhookWithContext(...)` is the framework runtime API; - `tgapi` webhook methods are the lower-level transport primitives. ## Common mistakes diff --git a/_Sidebar.md b/_Sidebar.md index 9608207..cabdde5 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -6,7 +6,7 @@ - [[Getting-Started]] - [[Bot-Options-and-Configuration]] - [[Commands-and-Plugins]] -- [[MsgContext]] +- [[MessageContext]] ## Runtime and Architecture - [[Bot-Lifecycle]] diff --git a/tgapi-Overview-RU.md b/tgapi-Overview-RU.md index ea3f897..db530ac 100644 --- a/tgapi-Overview-RU.md +++ b/tgapi-Overview-RU.md @@ -21,14 +21,14 @@ English version: [[tgapi-Overview]] Это разделение специально сделано, чтобы JSON methods и file upload methods не смешивались в одну слишком размытую abstraction. -## Когда использовать `MsgContext`, а когда `tgapi` +## Когда использовать `MessageContext`, а когда `tgapi` -Используй `MsgContext`, когда: +Используй `MessageContext`, когда: - ты уже внутри handler'а; - нужен обычный поток reply/edit/delete/callback. Используй `tgapi`, когда: -- у `MsgContext` нет нужного вспомогательного метода; +- у `MessageContext` нет нужного вспомогательного метода; - ты работаешь вне потока обработчика; - нужен более низкоуровневый контроль; - нужно работать с uploads/downloads напрямую. @@ -100,7 +100,7 @@ _, err := uploader.SendPhoto(tgapi.UploadPhoto{ ## Что читать дальше -- [[MsgContext-RU]] +- [[MessageContext-RU]] - [[Inline-Keyboards-and-Payloads-RU]] - [[Rate-Limiting-RU]] - [[tgapi-Overview]] diff --git a/tgapi-Overview.md b/tgapi-Overview.md index 4a6009a..50f7735 100644 --- a/tgapi-Overview.md +++ b/tgapi-Overview.md @@ -2,7 +2,7 @@ Russian version: [[tgapi-Overview-RU]] -`tgapi` is the low-level Telegram Bot API layer used under Laniakea’s higher-level bot runtime. Use it when you need direct access to Telegram methods, explicit parameter structs, upload control, or raw request building that sits below plugins and `MsgContext` helpers. +`tgapi` is the low-level Telegram Bot API layer used under Laniakea’s higher-level bot runtime. Use it when you need direct access to Telegram methods, explicit parameter structs, upload control, or raw request building that sits below plugins and `MessageContext` helpers. ## The important split first @@ -20,7 +20,7 @@ If you stay on the typed method surface, you usually do not need to think about ## The normal layering In practice, Laniakea has three levels: -- high-level handler helpers on `MsgContext`; +- high-level handler helpers on `MessageContext`; - runtime structure on `Bot`, plugins, and middleware; - low-level Telegram access in `tgapi`. @@ -29,7 +29,7 @@ In practice, Laniakea has three levels: ## When to use `tgapi` directly Use `tgapi` directly when: -- a `MsgContext` helper does not expose the Telegram feature you need; +- a `MessageContext` helper does not expose the Telegram feature you need; - you need a Telegram method outside the high-level command/payload flow; - you want explicit control over params, parse modes, message edits, or uploads; - you are writing infrastructure code rather than command logic. @@ -43,7 +43,7 @@ Typical examples where `tgapi` is the better tool: - setting bot metadata or command scopes directly; - file downloads and streaming; - multipart uploads; -- one-off Telegram methods that do not have a `MsgContext` wrapper. +- one-off Telegram methods that do not have a `MessageContext` wrapper. ## Typed methods first @@ -244,7 +244,7 @@ Related page: As a rule of thumb: -- use `MsgContext` when responding to the current update; +- use `MessageContext` when responding to the current update; - use `Bot` and plugins when structuring runtime behavior; - use `tgapi` when you need direct Telegram method control; - use raw `NewRequest` or `NewUploaderRequest` only as the final fallback. @@ -254,7 +254,7 @@ That boundary keeps normal bot code ergonomic without hiding Telegram-specific c ## Related pages - [[Getting-Started]] for the normal high-level bot setup path. -- [[MsgContext]] for handler-time reply helpers. +- [[MessageContext]] for handler-time reply helpers. - [[Inline-Keyboards-and-Payloads]] for callback button construction. - [[Bot-Lifecycle]] for runtime startup and shutdown responsibilities around `Bot`, `API`, and `Uploader`. - [[Rate-Limiting]] for limiter and `retry_after` behavior.