Совет для писателя бота: обработка каждого поста

:information_source: Примечание: Данное руководство предполагает, что вы запускаете авторизованного бота на форуме Discourse, возможно, используя User API или Admin API Key. Если ваш бот заблокирован администраторами, обсудите с ними назначение бота и не пытайтесь обойти эту блокировку.

:information_source: Не лучше ли было бы запускать вашего бота на сервере? Рассмотрите возможность создания плагина: Developing Discourse Plugins - Part 1 - Create a basic plugin

Введение

В этом руководстве представлен алгоритм для пользователя-бота, позволяющий проверять и обрабатывать каждый пост на форуме Discourse, к которому у пользователя бота есть доступ (за исключением личных сообщений).

Вам потребуется долговременное хранилище для одного целого числа — идентификатора последнего успешно обработанного поста. Например, вы можете записать его в Redis или в текстовый файл. Использование Redis позволит сохранять подписки на шину сообщений после перезапуска процессов на вашей стороне.

Настоятельно рекомендуется создать новую учетную запись пользователя для бота, чтобы её можно было при необходимости добавлять в группы и использовать для личных сообщений. Избегайте использования учетной записи @system.

Нижеприведенный набор алгоритмов написан в стиле спецификаций WHATWG и постепенно приводит к алгоритму непрерывного мониторинга новых постов.

Спецификации алгоритмов

Пусть базовый URL форума будет URL сайта без завершающего слеши — например, https://meta.discourse.org или https://www.contoso.com/forum для установок в подпапке.

Получение следующих недавних постов

Для получения следующих недавних постов при заданном целом числе наивысший просмотренный ID поста и флаге запущено шиной сообщений выполните следующие шаги:

  • Пусть максимальный ID поста в ответе будет результатом сложения пятидесяти (50) с наивысшим просмотренным ID поста.
  • Пусть URI запроса будет конкатенацией базового URL форума, /posts.json, ?before= и максимального ID поста в ответе.
  • Пусть ответ будет результатом :satellite: получения JSON с соблюдением ограничений скорости с использованием URI запроса и учетных данных.
  • Если ответ является ошибкой HTTP, прервите эти шаги с ошибкой.
  • Пусть посты будут JSON-массивом по пути latest_posts внутри ответа.
  • Установите флаг новые посты просмотрены в false (сбросьте).
  • Для каждого JSON-объекта post в постах в обратном порядке выполните следующие шаги:
    • Пусть ID поста будет JSON-числом по пути id внутри post.
    • Установите наивысший просмотренный ID поста равным ID поста.
    • Установите флаг новые посты просмотрены.
    • :white_check_mark: Отправьте post. (:information_source: Иными словами: передайте пост в любую пользовательскую обработку, которую вы хотите выполнить.)
    • Если отправка вернула сигнал обратного давления, прервите этот цикл.
  • :information_source: Приведенный выше цикл выполняется в обратном порядке, чтобы ваш код сначала видел самые старые посты, а затем самые новые.

  • Если флаг новые посты просмотрены установлен:
    • Выполните шаги для :floppy_disk: сохранения состояния в хранилище, передав наивысший просмотренный ID поста.
  • Завершите эти шаги, вернув наивысший просмотренный ID поста.

Проверка высокого существующего ID поста

Для проверки высокого существующего ID поста выполните следующие шаги:

  • Пусть URI последнего запроса проверки будет конкатенацией базового URL форума и /posts.json.
  • Пусть ответ последней проверки будет результатом :satellite: получения JSON с соблюдением ограничений скорости с использованием URI последнего запроса проверки и учетных данных.
  • Если ответ последней проверки является ошибкой HTTP, прервите эти шаги с ошибкой.
  • Пусть посты проверки будут JSON-массивом по пути latest posts внутри ответа последней проверки.
  • Для каждого JSON-объекта post в постах проверки:
    • Пусть ID поста будет JSON-числом по пути id внутри post.
    • Завершите эти шаги, вернув ID поста.
  • Прервите эти шаги с ошибкой.

Заполнение с самого последнего

Для заполнения с самого последнего при заданном необязательном целом числе наивысший просмотренный ID поста выполните следующие шаги:

  • Пусть минимальный ID поста будет наивысшим просмотренным ID поста, если он присутствует, и нулем (0) в противном случае.
  • Пусть высокий существующий ID поста будет результатом проверки высокого существующего ID поста.
  • Если максимальный ID поста является ошибкой, прервите эти шаги с ошибкой.
  • Выполните шаги для заполнения, передав минимальный ID поста и высокий существующий ID поста.

Заполнение

Для заполнения при заданных двух целых числах минимальный ID поста и высокий существующий ID поста:

  • Пусть текущий минимальный ID поста будет равен минимальному ID поста.
  • Повторяйте следующие шаги:
    • Выполните шаги для получения следующих недавних постов, передав текущий минимальный ID поста и флаг запущено шиной сообщений, установленный в false.
    • Если шаги для получения следующих недавних постов не были выполнены успешно:
      • Обновите алгоритм экспоненциальной задержки сигналом неудачи и подождите указанное количество времени.
      • Перейдите к следующей итерации цикла (не обновляя текущий минимальный ID поста).
    • Пусть кандидат на максимальный ID поста в ответе будет результатом сложения пятидесяти (50) с текущим минимальным ID поста.
    • Если кандидат на максимальный ID поста в ответе больше или равен высокому существующему ID поста, :white_check_mark: завершите эти шаги.
    • Установите текущий минимальный ID поста равным кандидату на максимальный ID поста в ответе.

Непрерывный мониторинг новых постов

Для непрерывного мониторинга новых постов выполните следующие шаги:

  • Пусть наивысший просмотренный ID поста будет необязательным целым числом со значением false (не установлено).
  • Установите наивысший просмотренный ID поста равным результату :arrow_forward: восстановления состояния из хранилища.
  • Если наивысший просмотренный ID поста не установлен:
    • Установите начальный ID поста равным результату проверки высокого существующего ID поста.
    • Выполните шаги для :floppy_disk: сохранения состояния в хранилище, передав начальный ID поста.
    • Установите наивысший просмотренный ID поста равным начальному ID поста.
  • Установите уведомления равными результату выполнения шагов для :satellite: подписки на шину сообщений с каналом /latest.
  • Повторяйте следующие шаги:
    • Установите новый наивысший просмотренный ID поста равным результату получения следующих недавних постов, с флагом запущено шиной сообщений, установленным в true, если произошло обновление шины сообщений, и наивысшим просмотренным ID поста.
    • Если шаги для получения следующих недавних постов не были выполнены успешно:
      • Обновите алгоритм экспоненциальной задержки сигналом неудачи и подождите указанное количество времени.
      • Перейдите к следующей итерации цикла.
    • Если новый наивысший просмотренный ID поста отличается от наивысшего просмотренного ID поста:
      • Обновите алгоритм экспоненциальной задержки сигналом успеха.
      • Установите наивысший просмотренный ID поста равным новому наивысшему просмотренному ID поста.
    • Подождите сообщения в уведомлениях или наступления тайм-аута, определенного реализацией. Этот тайм-аут должен быть не менее 10 минут и может разумно достигать 24 часов или немного больше.

Алгоритмы, которые вам необходимо реализовать:

  • :satellite: получение JSON с соблюдением ограничений скорости, принимающее URI запроса и необязательные учетные данные.
    • Это должно автоматически применять экспоненциальную задержку и повторять запросы, используя алгоритм экспоненциальной задержки и/или информацию Retry-After, предоставленную сервером, при получении ошибки 429.
  • :arrow_forward: восстановление состояния из хранилища
  • :floppy_disk: сохранение состояния в хранилище, принимающее целое число
  • :satellite: подписка на шину сообщений

14 лайков