REPOSITORY / ScuroNeko/Laniakea
Wiki
Add update routing contract pages
Document the current update schema contract in EN and RU Link the new routing model from Home and MsgContext pages
+1
@@ -19,6 +19,7 @@ English version: [[Home]]
|
|||||||
- [[Runners-RU]]
|
- [[Runners-RU]]
|
||||||
- [[Error-Handling-RU]]
|
- [[Error-Handling-RU]]
|
||||||
- [[Logging-RU]]
|
- [[Logging-RU]]
|
||||||
|
- [[Update-Routing-Model-RU]]
|
||||||
- [[Scenes-RU]]
|
- [[Scenes-RU]]
|
||||||
|
|
||||||
## Telegram API и взаимодействие
|
## Telegram API и взаимодействие
|
||||||
|
|||||||
+1
@@ -23,6 +23,7 @@ Use this wiki as the structured companion to the README: start with setup, then
|
|||||||
- [[Runners]]
|
- [[Runners]]
|
||||||
- [[Error-Handling]]
|
- [[Error-Handling]]
|
||||||
- [[Logging]]
|
- [[Logging]]
|
||||||
|
- [[Update-Routing-Model]]
|
||||||
- [[Scenes]]
|
- [[Scenes]]
|
||||||
|
|
||||||
## Telegram API and Interaction
|
## Telegram API and Interaction
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ English version: [[MsgContext]]
|
|||||||
- разобранные аргументы команд и callback;
|
- разобранные аргументы команд и callback;
|
||||||
- вспомогательные методы для reply, edit, delete, callback, drafts и localization.
|
- вспомогательные методы для reply, edit, delete, callback, drafts и localization.
|
||||||
|
|
||||||
|
Полную матрицу маршрутизации и гарантий по полям `MsgContext` для разных update types смотри в [[Update-Routing-Model-RU]].
|
||||||
|
|
||||||
## Поля, которые используются чаще всего
|
## Поля, которые используются чаще всего
|
||||||
|
|
||||||
### `Text`
|
### `Text`
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ It gives you access to:
|
|||||||
|
|
||||||
If you write handlers, `MsgContext` is the API surface you will use most often.
|
If you write handlers, `MsgContext` is the API surface you will use most often.
|
||||||
|
|
||||||
|
For the full routing and field-guarantee matrix by update kind, see [[Update-Routing-Model]].
|
||||||
|
|
||||||
## The fields you will use first
|
## The fields you will use first
|
||||||
|
|
||||||
### `Text`
|
### `Text`
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# Update Routing Model RU
|
||||||
|
|
||||||
|
English version: [[Update-Routing-Model]]
|
||||||
|
|
||||||
|
Эта страница фиксирует текущий контракт маршрутизации обновлений в Laniakea: какие Telegram update types идут через команды, какие через данные callback, какие через generic update handlers, и какие гарантии по `MsgContext` существуют в каждом потоке.
|
||||||
|
|
||||||
|
Это описание текущего поведения фреймворка, а не отдельная новая API-поверхность. Цель страницы — сделать уже существующую маршрутизацию и нормализацию `MsgContext` явной и тестируемой.
|
||||||
|
|
||||||
|
## Верхнеуровневая маршрутизация
|
||||||
|
|
||||||
|
Сейчас Laniakea маршрутизирует обновления так:
|
||||||
|
|
||||||
|
| Update type | Routing path |
|
||||||
|
|---|---|
|
||||||
|
| `message` | command flow |
|
||||||
|
| `channel_post` | command flow |
|
||||||
|
| `callback_query` | payload flow |
|
||||||
|
| всё остальное | `AddUpdateHandler(...)` |
|
||||||
|
|
||||||
|
Важно:
|
||||||
|
- `message`, `channel_post` и `callback_query` зарезервированы и не должны регистрироваться через `AddUpdateHandler(...)`.
|
||||||
|
- сцены проверяются раньше обычной маршрутизации, но текущая модель сцен всё ещё по сути ориентирована на сообщения.
|
||||||
|
|
||||||
|
## Что делает `prepareUpdateCtx(...)`
|
||||||
|
|
||||||
|
До маршрутизации обработчиков Laniakea нормализует `MsgContext` из входящего Telegram update.
|
||||||
|
|
||||||
|
Эта нормализация намеренно шире, чем command и payload routing:
|
||||||
|
- некоторые update types заполняют `ctx.Msg`
|
||||||
|
- некоторые заполняют `ctx.From` и `ctx.FromID`
|
||||||
|
- callback queries могут заполнять callback target поля
|
||||||
|
- `ctx.Text`, `ctx.Args` и `ctx.Prefix` на этом этапе **не** заполняются
|
||||||
|
|
||||||
|
Это важное разделение:
|
||||||
|
- `prepareUpdateCtx(...)` задаёт сырой нормализованный shape контекста
|
||||||
|
- routing потом определяет, какой handler path получит этот контекст
|
||||||
|
|
||||||
|
## Контракт command flow
|
||||||
|
|
||||||
|
Command flow применяется только к:
|
||||||
|
- `message`
|
||||||
|
- `channel_post`
|
||||||
|
|
||||||
|
Когда команда совпала, действуют такие гарантии:
|
||||||
|
- `ctx.Update` всегда заполнен
|
||||||
|
- `ctx.Msg` заполнен
|
||||||
|
- `ctx.Prefix` содержит совпавший префикс команды
|
||||||
|
- `ctx.Text` содержит хвост после имени команды
|
||||||
|
- `ctx.Args` содержит `strings.Fields(ctx.Text)`
|
||||||
|
- `ctx.Logger` переключается на logger совпавшего плагина, если он задан
|
||||||
|
|
||||||
|
Не гарантируется:
|
||||||
|
- `ctx.From`
|
||||||
|
- `ctx.FromID`
|
||||||
|
|
||||||
|
Показательный edge case:
|
||||||
|
- `channel_post`, пришедший через `sender_chat`, всё равно даёт `ctx.Msg`
|
||||||
|
- но `ctx.From` может быть `nil`
|
||||||
|
- а `ctx.FromID` может оставаться `0`
|
||||||
|
|
||||||
|
## Контракт payload flow
|
||||||
|
|
||||||
|
Payload flow применяется только к:
|
||||||
|
- `callback_query`
|
||||||
|
|
||||||
|
Базовые гарантии:
|
||||||
|
- `ctx.Update` всегда заполнен
|
||||||
|
- `ctx.CallbackQueryId` заполнен
|
||||||
|
- `ctx.From` и `ctx.FromID` заполняются, если Telegram прислал user
|
||||||
|
- `ctx.Args` заполняется из декодированных данных callback
|
||||||
|
- `ctx.Logger` переключается на logger совпавшего плагина, если он задан
|
||||||
|
|
||||||
|
Не гарантируется:
|
||||||
|
- `ctx.Text`
|
||||||
|
- `ctx.Prefix`
|
||||||
|
|
||||||
|
У payload flow есть две формы target.
|
||||||
|
|
||||||
|
### Callback query, привязанный к обычному сообщению
|
||||||
|
|
||||||
|
Гарантии:
|
||||||
|
- `ctx.Msg` заполнен
|
||||||
|
- `ctx.CallbackMsgId` заполнен
|
||||||
|
- `ctx.InlineMsgId == ""`
|
||||||
|
|
||||||
|
### Callback query, привязанный к inline message
|
||||||
|
|
||||||
|
Гарантии:
|
||||||
|
- `ctx.Msg == nil`
|
||||||
|
- `ctx.CallbackMsgId == 0`
|
||||||
|
- `ctx.InlineMsgId` заполнен
|
||||||
|
|
||||||
|
## Контракт generic update handlers
|
||||||
|
|
||||||
|
Generic update handlers регистрируются через `Plugin.AddUpdateHandler(...)`.
|
||||||
|
|
||||||
|
Они применяются ко всем update types вне зарезервированного command/payload flow.
|
||||||
|
|
||||||
|
Общие гарантии:
|
||||||
|
- `ctx.Update` всегда заполнен
|
||||||
|
- `ctx.Text` не нормализуется
|
||||||
|
- `ctx.Args` не нормализуется
|
||||||
|
- `ctx.Prefix` не нормализуется
|
||||||
|
- каждый plugin update handler получает свою копию `MsgContext` struct
|
||||||
|
|
||||||
|
Важное ограничение:
|
||||||
|
- копируется сам `MsgContext`, но не обещается глубокая копия всех вложенных Telegram-структур
|
||||||
|
|
||||||
|
## Нормализованные поля `MsgContext` по видам update
|
||||||
|
|
||||||
|
### Update types, которые несут message
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` |
|
||||||
|
|---|---|---|
|
||||||
|
| `message` | да | да, если есть `Msg.From` |
|
||||||
|
| `edited_message` | да | да, если есть `Msg.From` |
|
||||||
|
| `channel_post` | да | только если есть `Msg.From` |
|
||||||
|
| `edited_channel_post` | да | только если есть `Msg.From` |
|
||||||
|
| `business_message` | да | да, если есть `Msg.From` |
|
||||||
|
| `edited_business_message` | да | да, если есть `Msg.From` |
|
||||||
|
|
||||||
|
Важно:
|
||||||
|
- message-backed не означает command-routed
|
||||||
|
- `edited_message`, `edited_channel_post`, `business_message` и `edited_business_message` сейчас автоматически не попадают в command flow
|
||||||
|
|
||||||
|
### Update types с user, но без message
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` |
|
||||||
|
|---|---|---|
|
||||||
|
| `inline_query` | нет | да |
|
||||||
|
| `chosen_inline_result` | нет | да |
|
||||||
|
| `shipping_query` | нет | да |
|
||||||
|
| `pre_checkout_query` | нет | да |
|
||||||
|
| `purchased_paid_media` | нет | да |
|
||||||
|
| `my_chat_member` | нет | да |
|
||||||
|
| `chat_member` | нет | да |
|
||||||
|
| `chat_join_request` | нет | да |
|
||||||
|
| `business_connection` | нет | да |
|
||||||
|
| `poll_answer` | нет | да |
|
||||||
|
| `message_reaction` | нет | да, если Telegram прислал `User` |
|
||||||
|
| `chat_boost` | нет | да |
|
||||||
|
| `removed_chat_boost` | нет | да |
|
||||||
|
|
||||||
|
### Callback-specific update type
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` | Спецполя |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `callback_query` с `Message` | да | да | `CallbackQueryId`, `CallbackMsgId` |
|
||||||
|
| `callback_query` с `InlineMessageID` | нет | да | `CallbackQueryId`, `InlineMsgId` |
|
||||||
|
|
||||||
|
### Update types без нормализованных гарантий по user/message
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` |
|
||||||
|
|---|---|---|
|
||||||
|
| `poll` | нет | нет |
|
||||||
|
| `message_reaction_count` | нет | нет |
|
||||||
|
| `deleted_business_messages` | нет | нет |
|
||||||
|
| `unknown` | нет | нет |
|
||||||
|
|
||||||
|
## Что уже достаточно стабильно
|
||||||
|
|
||||||
|
- `message` и `channel_post` остаются в command flow
|
||||||
|
- `callback_query` остаётся в payload flow
|
||||||
|
- `prepareUpdateCtx(...)` сам по себе не заполняет `Text`, `Args` и `Prefix`
|
||||||
|
- command parsing заполняет `Text`, `Args` и `Prefix`
|
||||||
|
- payload decoding заполняет `Args`, но не `Text`
|
||||||
|
- callback target разделяется на chat-message callbacks и inline-message callbacks
|
||||||
|
- `edited_message` и `edited_channel_post` не входят в command routing
|
||||||
|
|
||||||
|
## Что пока намеренно не закрыто
|
||||||
|
|
||||||
|
- должны ли сцены оставаться только message-driven или получить более широкую update model
|
||||||
|
- должны ли edited/business message-backed updates когда-нибудь получить command-style routing
|
||||||
|
- стоит ли оформлять “message-backed update” как отдельную внутреннюю концепцию фреймворка
|
||||||
|
|
||||||
|
## Связанные страницы
|
||||||
|
|
||||||
|
- [[Commands-and-Plugins-RU]]
|
||||||
|
- [[MsgContext-RU]]
|
||||||
|
- [[Scenes-RU]]
|
||||||
|
- [[Bot-Lifecycle-RU]]
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# Update Routing Model
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
## Top-level routing
|
||||||
|
|
||||||
|
Laniakea currently routes updates like this:
|
||||||
|
|
||||||
|
| Update type | Routing path |
|
||||||
|
|---|---|
|
||||||
|
| `message` | command flow |
|
||||||
|
| `channel_post` | command flow |
|
||||||
|
| `callback_query` | payload flow |
|
||||||
|
| everything else | `AddUpdateHandler(...)` |
|
||||||
|
|
||||||
|
Important:
|
||||||
|
- `message`, `channel_post`, and `callback_query` are reserved from `AddUpdateHandler(...)`.
|
||||||
|
- scenes are checked before normal routing, but the current scene model is still fundamentally message-driven.
|
||||||
|
|
||||||
|
## What `prepareUpdateCtx(...)` does
|
||||||
|
|
||||||
|
Before handler routing, Laniakea normalizes a `MsgContext` from the incoming Telegram update.
|
||||||
|
|
||||||
|
That normalization is intentionally broader than command and payload routing:
|
||||||
|
- some update kinds populate `ctx.Msg`
|
||||||
|
- some populate `ctx.From` and `ctx.FromID`
|
||||||
|
- callback queries may populate callback-target fields
|
||||||
|
- `ctx.Text`, `ctx.Args`, and `ctx.Prefix` are **not** populated by this stage
|
||||||
|
|
||||||
|
This is an important distinction:
|
||||||
|
- `prepareUpdateCtx(...)` defines the raw normalized context shape
|
||||||
|
- routing then decides which handler path receives that context
|
||||||
|
|
||||||
|
## Command flow contract
|
||||||
|
|
||||||
|
Command flow applies only to:
|
||||||
|
- `message`
|
||||||
|
- `channel_post`
|
||||||
|
|
||||||
|
When a command matches, these guarantees apply:
|
||||||
|
- `ctx.Update` is always present
|
||||||
|
- `ctx.Msg` is present
|
||||||
|
- `ctx.Prefix` contains the matched command prefix
|
||||||
|
- `ctx.Text` contains the parsed tail after the command name
|
||||||
|
- `ctx.Args` contains `strings.Fields(ctx.Text)`
|
||||||
|
- `ctx.Logger` switches to the matched plugin logger when one exists
|
||||||
|
|
||||||
|
Not guaranteed:
|
||||||
|
- `ctx.From`
|
||||||
|
- `ctx.FromID`
|
||||||
|
|
||||||
|
Example edge case:
|
||||||
|
- a `channel_post` sent via `sender_chat` still has `ctx.Msg`
|
||||||
|
- but `ctx.From` may be `nil`
|
||||||
|
- and `ctx.FromID` may stay `0`
|
||||||
|
|
||||||
|
## Payload flow contract
|
||||||
|
|
||||||
|
Payload flow applies only to:
|
||||||
|
- `callback_query`
|
||||||
|
|
||||||
|
Base guarantees:
|
||||||
|
- `ctx.Update` is always present
|
||||||
|
- `ctx.CallbackQueryId` is populated
|
||||||
|
- `ctx.From` and `ctx.FromID` are populated when Telegram includes a user
|
||||||
|
- `ctx.Args` is populated from decoded payload args
|
||||||
|
- `ctx.Logger` switches to the matched plugin logger when one exists
|
||||||
|
|
||||||
|
Not guaranteed:
|
||||||
|
- `ctx.Text`
|
||||||
|
- `ctx.Prefix`
|
||||||
|
|
||||||
|
There are two payload target shapes.
|
||||||
|
|
||||||
|
### Callback query targeting a chat message
|
||||||
|
|
||||||
|
Guarantees:
|
||||||
|
- `ctx.Msg` is present
|
||||||
|
- `ctx.CallbackMsgId` is populated
|
||||||
|
- `ctx.InlineMsgId == ""`
|
||||||
|
|
||||||
|
### Callback query targeting an inline message
|
||||||
|
|
||||||
|
Guarantees:
|
||||||
|
- `ctx.Msg == nil`
|
||||||
|
- `ctx.CallbackMsgId == 0`
|
||||||
|
- `ctx.InlineMsgId` is populated
|
||||||
|
|
||||||
|
## Generic update handler contract
|
||||||
|
|
||||||
|
Generic update handlers are registered through `Plugin.AddUpdateHandler(...)`.
|
||||||
|
|
||||||
|
They apply to all update kinds outside the reserved command/payload flow.
|
||||||
|
|
||||||
|
General guarantees:
|
||||||
|
- `ctx.Update` is always present
|
||||||
|
- `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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
### Message-backed update kinds
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` |
|
||||||
|
|---|---|---|
|
||||||
|
| `message` | yes | yes, when `Msg.From` exists |
|
||||||
|
| `edited_message` | yes | yes, when `Msg.From` exists |
|
||||||
|
| `channel_post` | yes | only when `Msg.From` exists |
|
||||||
|
| `edited_channel_post` | yes | only when `Msg.From` exists |
|
||||||
|
| `business_message` | yes | yes, when `Msg.From` exists |
|
||||||
|
| `edited_business_message` | yes | yes, when `Msg.From` exists |
|
||||||
|
|
||||||
|
Important:
|
||||||
|
- message-backed does **not** mean command-routed
|
||||||
|
- `edited_message`, `edited_channel_post`, `business_message`, and `edited_business_message` currently do not enter command flow automatically
|
||||||
|
|
||||||
|
### User-backed but not message-backed update kinds
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` |
|
||||||
|
|---|---|---|
|
||||||
|
| `inline_query` | no | yes |
|
||||||
|
| `chosen_inline_result` | no | yes |
|
||||||
|
| `shipping_query` | no | yes |
|
||||||
|
| `pre_checkout_query` | no | yes |
|
||||||
|
| `purchased_paid_media` | no | yes |
|
||||||
|
| `my_chat_member` | no | yes |
|
||||||
|
| `chat_member` | no | yes |
|
||||||
|
| `chat_join_request` | no | yes |
|
||||||
|
| `business_connection` | no | yes |
|
||||||
|
| `poll_answer` | no | yes |
|
||||||
|
| `message_reaction` | no | yes, when Telegram includes `User` |
|
||||||
|
| `chat_boost` | no | yes |
|
||||||
|
| `removed_chat_boost` | no | yes |
|
||||||
|
|
||||||
|
### Callback-specific update kind
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` | Special fields |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `callback_query` with `Message` | yes | yes | `CallbackQueryId`, `CallbackMsgId` |
|
||||||
|
| `callback_query` with `InlineMessageID` | no | yes | `CallbackQueryId`, `InlineMsgId` |
|
||||||
|
|
||||||
|
### Update kinds without normalized user/message guarantees
|
||||||
|
|
||||||
|
| Update type | `ctx.Msg` | `ctx.From` / `ctx.FromID` |
|
||||||
|
|---|---|---|
|
||||||
|
| `poll` | no | no |
|
||||||
|
| `message_reaction_count` | no | no |
|
||||||
|
| `deleted_business_messages` | no | no |
|
||||||
|
| `unknown` | no | no |
|
||||||
|
|
||||||
|
## What is already stable enough to rely on
|
||||||
|
|
||||||
|
- `message` and `channel_post` stay on command flow
|
||||||
|
- `callback_query` stays on payload flow
|
||||||
|
- `prepareUpdateCtx(...)` itself does not populate `Text`, `Args`, or `Prefix`
|
||||||
|
- command parsing populates `Text`, `Args`, and `Prefix`
|
||||||
|
- payload decoding populates `Args`, not `Text`
|
||||||
|
- callback target shape is split between chat-message callbacks and inline-message callbacks
|
||||||
|
- `edited_message` and `edited_channel_post` stay out of command routing
|
||||||
|
|
||||||
|
## What is still intentionally open
|
||||||
|
|
||||||
|
- whether scenes should remain message-driven only or grow a broader update model
|
||||||
|
- whether message-backed edited/business updates should ever gain command-style routing
|
||||||
|
- whether “message-backed update” should become an explicit documented framework concept
|
||||||
|
|
||||||
|
## Related pages
|
||||||
|
|
||||||
|
- [[Commands-and-Plugins]]
|
||||||
|
- [[MsgContext]]
|
||||||
|
- [[Scenes]]
|
||||||
|
- [[Bot-Lifecycle]]
|
||||||
Reference in New Issue
Block a user