Масштабування I: велика кодова база
Як тільки ваш бот стане складнішим, ви зіткнетеся з проблемою структурування кодової бази вашого застосунку. Звісно, ви можете розділити його на файли.
Можливе рішення
grammY ще досить молодий і поки що не надає жодних офіційних інтеграцій з DI-контейнерами. Підпишіться на @grammyjs
_news , щоб отримати сповіщення, як тільки ми надамо підтримку цього.
Ви можете структурувати свій код як завгодно, універсального рішення не існує. З огляду на це, проста і перевірена стратегія структурування вашого коду полягає в наступному.
- Групуйте семантично повʼязані речі в одному файлі або каталозі, в залежності від кількості коду. Кожен із таких блоків має надавати проміжний обробник, який оброблятиме певні повідомлення.
- Створюйте екземпляр бота в єдиному місці, в якому також буде встановлено всі проміжні обробники, які він використовує.
- Необовʼязково. Попередньо фільтруйте оновлення та передавайте їх далі за правильним маршрутом. Для цього рекомендуємо розглянути
bot
(довідка API) або скористатися плагіном для маршрутизації..route
Приклад, який можна запустити і який реалізує описану вище стратегію, можна знайти в репозиторії з прикладами ботів.
Приклад структури
Для дуже простого бота, який керує списком TODO, ви можете уявити собі таку структуру.
src/
├── bot.ts
└── todo/
├── item.ts
└── list.ts
item
просто визначає деякі речі про пункти TODO, і ці частини коду використовуються в list
.
У list
ви можете зробити щось на кшталт цього:
export const lists = new Composer();
// Реєструємо тут якісь обробники, які є звичайними проміжними обробниками.
lists.on("message", async (ctx) => {/* ... */});
2
3
4
Зауважте, що якщо ви використовуєте TypeScript, вам потрібно передати ваш власний тип контексту під час створення екземпляру
Composer
. Наприклад, вам потрібно написатиnew Composer<My
.Context>()
За потреби ви можете використати межу помилок для обробки всіх помилок, що трапляються у вашому модулі.
Тепер в bot
ви можете встановити цей модуль ось так:
import { lists } from "./todo/list";
const bot = new Bot("");
bot.use(lists);
// ... можливо, тут буде більше модулів на кшталт `todo`
bot.start();
2
3
4
5
6
7
8
За потреби ви можете використовувати плагін для маршрутизації або bot
для обʼєднання різних модулів, якщо ви можете заздалегідь визначити, який модуль повинен обробити оновлення.
Однак памʼятайте, що дуже важко сказати, як саме потрібно структурувати бота в загальних рисах. Як зазвичай у програмному забезпеченні, робіть це так, щоб це мало найбільший сенс 😉
Визначення типів для окремого проміжного обробника
Описана вище структура з використанням Composer
працює добре. Однак іноді ви можете опинитися в ситуації, коли ви хочете вилучити обробник у функцію, замість того, щоб створювати новий Composer
і додавати до нього логіку. Це вимагає додавання правильних визначень типів до ваших обробників, оскільки вони більше не можуть бути виведені через Composer
.
grammY експортує визначення типів для всіх звужених типів проміжних обробників, наприклад, для проміжних обробників, які ви можете передати обробникам команд. Крім того, він експортує визначення типів для звужених обʼєктів контексту, які використовуються у таких проміжних обробниках. Обидва типи параметризуються за допомогою вашого власного обʼєкта контексту. Відповідно, обробник команди матиме тип Command
, а обʼєкт контексту матиме тип Command
. Їх можна використовувати наступним чином.
import {
type CallbackQueryMiddleware,
type CommandContext,
type NextFunction,
} from "grammy";
function commandMiddleware(ctx: CommandContext<MyContext>, next: NextFunction) {
// обробка команди
}
const callbackQueryMiddleware: CallbackQueryMiddleware<MyContext> = (ctx) => {
// обробка запитів зворотного виклику
};
bot.command(["start", "help"], commandMiddleware);
bot.callbackQuery("query-data", callbackQueryMiddleware);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {
type CallbackQueryMiddleware,
type CommandContext,
type NextFunction,
} from "https://deno.land/x/grammy@v1.30.0/mod.ts";
function commandMiddleware(ctx: CommandContext<MyContext>, next: NextFunction) {
// обробка команди
}
const callbackQueryMiddleware: CallbackQueryMiddleware<MyContext> = (ctx) => {
// обробка запитів зворотного виклику
};
bot.command(["start", "help"], commandMiddleware);
bot.callbackQuery("query-data", callbackQueryMiddleware);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Перегляньте довідку API щодо псевдонімів типів, щоб ознайомитися з оглядом усіх псевдонімів типів, які експортує grammY.