Stateless-пагинация¶
Большинство систем пагинации хранят текущую страницу где-то на сервере. В Raito это не так: всё состояние живёт в кнопках. Эта страница объясняет, как именно и в чём компромиссы.
Состояние живёт в callback_data¶
Каждая кнопка навигации несёт callback_data, кодирующую всё состояние страницы:
rt_p:<mode>:<name>:<page>:<total>:<limit>
На сервере не хранится записи о том, «на какой странице пользователь X». Когда пользователь жмёт кнопку, Telegram присылает эту строку обратно, и Raito восстанавливает из неё всё нужное.
Круговорот¶
Вы вызываете
paginate()с именем, страницей и лимитом. Raito рисует страницу и кнопки навигации, чьи callback_data кодируют целевую страницу каждой.Пользователь жмёт «вперёд». Telegram доставляет колбэк-запрос с этим закодированным состоянием.
Middleware распаковывает его, пересобирает нужный пагинатор для этого
modeи передаёт в ваш хендлерpaginator,page,limitи вычисленныйoffset = (page - 1) * limit.Ваш хендлер режет свои данные по
offset/limitи вызываетpaginator.answer(...), который редактирует сообщение и перерисовывает навигацию, замыкая круг.
Ваши данные Raito не хранит; вы каждый раз заново режете их оттуда, где они лежат (список, запрос к БД, API).
Чем это хорошо¶
Ни хранилища, ни срока жизни, ни очистки. Кнопки, отправленные на прошлой неделе, всё ещё работают; нет сессии, которую можно потерять.
Тривиально масштабируется. Любой процесс за ботом может обработать любой колбэк, ведь состояние путешествует вместе с запросом.
Простая модель в голове. Страница это чистая функция от
(offset, limit)над вашими данными.
Компромисс: 64 байта¶
Telegram ограничивает callback_data 64 байтами, и туда должно уложиться всё: mode, name, page, total, limit. На практике это бьёт только при длинном name пагинации вместе с большими номерами страниц. Держите имена короткими. Raito проверяет входные данные, но кодировка это жёсткий потолок, поэтому очень длинное имя плюс крупные счётчики могут превысить лимит.
Режимы¶
Поле mode в колбэке выбирает пагинатор: inline (кнопки с контентом), text, list, photo или rich. Так как режим закодирован, middleware может пересобрать нужный тип пагинатора на каждое нажатие без всякого сохранённого контекста. API смотрите в руководстве по пагинации.