Conversation
Telegram and Discord rate bots
unemployed
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
ОбзорРеализована система хуков для событий действий (action hooks) с добавлением типа Изменения
Диаграмма последовательностиsequenceDiagram
participant Client
participant AC as ActionController
participant DB as Database
participant Nitro
participant Discord
participant Telegram
Client->>AC: Запрос действия (например, рейтинг)
AC->>DB: Вставка действия
DB-->>AC: Подтверждение
rect rgb(240, 248, 255)
Note over AC,Nitro: Диспетчеризация хуков (новое)
AC->>Nitro: dispatch("action:registered", ActionHookPayload)
alt action === "level_rate"
AC->>Nitro: dispatch("action:level_rate", ActionHookPayload)
end
end
par Уведомления
Nitro->>Discord: Отправка вебхука с информацией о рейтинге
Discord-->>Nitro: OK
and
Nitro->>Telegram: Отправка сообщения в чат
Telegram-->>Nitro: OK
end
AC-->>Client: Ответ
Оценка трудозатрат на рецензию🎯 3 (Средний) | ⏱️ ~25 минут Области, требующие повышенного внимания:
Возможно связанные PR
Рекомендуемые рецензенты
Поэма
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
types.d.ts (1)
2-26: Расширение NitroRuntimeHooks типизировано корректно, есть замечание поexport defaultПодключение
ActionHookPayloadв декларацииnitropackдаёт хорошую связку типов между контроллером действий и нитро‑хуками, сами сигнатуры"action:registered"/"action:level_rate"выглядят корректно. Единственное, в конце файла в.d.tsобычно безопаснее использоватьexport {}вместоexport default {}, чтобы не объявлять фиктивный default‑экспорт модуля и оставить файл исключительно как носитель деклараций.controller/LevelFilter.ts (1)
173-181: Новый фильтр для режимаsentсемантически корректен, стоит лишь проверить план запросаПереход на сырой SQL‑фильтр
levels.id IN (SELECT rateQueue.levelId FROM rateQueue)даёт тот же результат, что и
EXISTS‑подзапрос, с учётом того, чтоrateQueueTable.levelIdможет содержать дубликаты (они не меняют семантикуIN). Код выглядит корректно и хорошо вписывается в существующий пайплайнfilters. На больших объёмах данных имеет смысл посмотретьEXPLAIN/EXPLAIN ANALYZE, чтобы убедиться, что план запроса не стал хуже относительно предыдущего варианта.Also applies to: 387-388
controller/ActionController.ts (2)
121-152: Интеграция Nitro‑хуков выглядит аккуратно, проверьте влияние на рантайм иstructuredCloneБлок с
useNitroAppи защитой черезtypeof useNitroApp === "function"+ безопасный вызовuseEvent()хорошо позволяет использовать контроллер и вне контекста Nitro (тесты, скрипты). Отдельно плюс заstructuredClone(data)перед отправкой в хук — это защищает логированное действие от побочных мутаций в плагинах. При этом:
structuredCloneзависит от реализации рантайма (Node/Bun); если где‑то ещё используется более старый Node/Bun, лучше явно брать его изnode:utilили предусмотреть фоллбек, иначе при отсутствии глобальной функции этот участок упадёт раньше, чем дойдёт доuseLogger().warn(...).- Вызовы
nitroApp.hooks.callHook(...)сейчас ожидаются (await), поэтому сетевые операции в плагинах (Discord/Telegram rate‑bot) напрямую увеличат время выполненияregisterAction. Если латентность маршрутов критична, можно в будущем подумать о fire‑and‑forget/очереди для внешних уведомлений, оставив хук максимально лёгким.
36-38: Уточните семантикуisModActionвActionHookPayload— сейчас она привязана кtargetIdПоле
isModActionзаполняется изisMod = user.$.roleId > 0, гдеuserберётся черезgetOneUser({ uid: targetId }). При этом вActionHookPayloadэто поле может восприниматься подписчиками как «действие совершено модератором (инициатором)». Если в вызывателяхregisterActionпараметрuid— это именно инициатор, аtargetId— объект действия (уровень, лист, пользователь и т.п.), то сейчасisModActionфактически отражает статус целевого пользователя/объекта, а не инициатора. Это может путать будущие плагины, потребляющиеActionHookPayload. Имеет смысл пересмотреть логику и, при необходимости, вычислять мод‑флаг поuid, чтобы контракт хука был однозначным.Also applies to: 111-119, 199-210
server/plugins/plugin-discord-ratebot.ts (1)
1-233: Discord rate‑bot плагин выглядит продуманно, с хорошей защитой и логированием; есть мелкие идеи по доработкеНравится, что вы: фильтруете только
Rate:*события, раннимreturnотбрасывая нерелевантные/reset; аккуратно вытаскиваетеsrvidи конфиг (с fallback наuseServerConfig), проверяете включённость модуля и обязательный абсолютныйwebhookUrl; оборачиваете сетевые вызовы$fetchвtry/catchс логированием черезuseLogger(). ХелперыresolveDifficulty/resolveDemon/resolveEpic/formatCoins/translateActionтоже выглядят консистентно и дают понятный embed. Из необязательных улучшений: можно логировать что‑нибудь на debug‑уровне при отключённом модуле/отсутствии уровня, чтобы проще было диагностировать «молчание» бота, и, при желании, либо перестать отфильтровыватьRate:reset(у вас уже есть перевод вtranslateAction), либо удалить этот кейс из маппинга, чтобы не поддерживать мёртвый код.server/plugins/plugin-telegram-ratebot.ts (1)
29-56: Обработка payload и конфигурации в целом удачная, но есть пара мест, где стоит чуть усилить защиту
Фильтрация по
Rate:иRate:reset
Логика сactionType.startsWith("Rate:")иsuffix === "reset"достаточно прозрачна и даёт ранний выход для нерелейтивантных действий — это плюс.Разбор
srvidи работа без HTTP‑контекста
СвязкаtryGetEvent()+ приоритетpayload.srvid+ fallback кgetRouterParamиuseServerConfig(srvid)выглядит надёжно и хорошо документирует приоритеты источников serverId; аккуратныйtry/catchвtryGetEventпозволяет безопасно жить в non‑request контексте.Доступ к
config.ServerConfig
Сейчас вы предполагаете, чтоconfig.ServerConfigвсегда существует, и сразу обращаетесь к вложенным полям:if (!config.ServerConfig.EnableModules?.["telegram_ratebot"]) return const moduleConfig = config.ServerConfig.ModuleConfig?.["telegram_ratebot"] as MaybeUndefined<TelegramRateBotConfig>Если когда‑то в хранилище окажется частично битый конфиг (или структура эволюционирует), это место превратится в
TypeError: Cannot read properties of undefined (reading 'EnableModules'|'ModuleConfig'). Чтобы сделать код более устойчивым к таким ситуациям, можно добавить optional chaining на уровнеServerConfig:
- if (!config.ServerConfig.EnableModules?.["telegram_ratebot"])
return- const moduleConfig = config.ServerConfig.ModuleConfig?.["telegram_ratebot"] as MaybeUndefined
- if (!config.ServerConfig?.EnableModules?.["telegram_ratebot"])
return- const moduleConfig = config.ServerConfig?.ModuleConfig?.["telegram_ratebot"] as MaybeUndefined
Функциональное поведение не меняется, но вероятность падения на неожиданном формате конфига уменьшается. 4. Тихие early‑return’ы при невалидном moduleConfig При отсутствии `botToken`/`chatId` вы просто делаете `return`. Это безопасно, но отладка может быть неочевидной. Опционально можно добавить `warn` при включённом модуле и битом конфиге (например, логировать один раз при старте или с троттлингом), но это скорее вкусовой момент. 5. Вызов Telegram API Вызов `$fetch` с POST и телом‑объектом вполне ок для Telegram Bot API, ошибки корректно логируются через `useLogger().error`, так что с точки зрения устойчивости всё хорошо. Also applies to: 38-48, 50-55, 57-84, 164-170 </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used**: CodeRabbit UI **Review profile**: CHILL **Plan**: Pro <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 9b80654e28b27b97b0d92035a8e93f099fe4a7f6 and 0ac8888ca6efd29b032ade83b97a2691a6e20506. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `bun.lock` is excluded by `!**/*.lock` </details> <details> <summary>📒 Files selected for processing (6)</summary> * `controller/ActionController.ts` (2 hunks) * `controller/LevelFilter.ts` (2 hunks) * `package.json` (1 hunks) * `server/plugins/plugin-discord-ratebot.ts` (1 hunks) * `server/plugins/plugin-telegram-ratebot.ts` (1 hunks) * `types.d.ts` (2 hunks) </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code graph analysis (5)</summary> <details> <summary>types.d.ts (1)</summary><blockquote> <details> <summary>controller/ActionController.ts (1)</summary> * `ActionHookPayload` (201-210) </details> </blockquote></details> <details> <summary>controller/LevelFilter.ts (2)</summary><blockquote> <details> <summary>drizzle/levels.ts (1)</summary> * `levelsTable` (8-64) </details> <details> <summary>drizzle/rate_queue.ts (1)</summary> * `rateQueueTable` (6-14) </details> </blockquote></details> <details> <summary>controller/ActionController.ts (3)</summary><blockquote> <details> <summary>drizzle/actions.ts (2)</summary> * `ActionData` (55-57) * `ActionVariant` (11-11) </details> <details> <summary>server/utils/useLogger.ts (1)</summary> * `useLogger` (11-11) </details> <details> <summary>server/utils/useDrizzle.ts (1)</summary> * `Database` (67-67) </details> </blockquote></details> <details> <summary>server/plugins/plugin-telegram-ratebot.ts (5)</summary><blockquote> <details> <summary>controller/ActionController.ts (1)</summary> * `ActionHookPayload` (201-210) </details> <details> <summary>server/utils/useLogger.ts (1)</summary> * `useLogger` (11-11) </details> <details> <summary>server/utils/useServerConfig.ts (1)</summary> * `useServerConfig` (5-15) </details> <details> <summary>controller/LevelController.ts (1)</summary> * `LevelController` (9-187) </details> <details> <summary>controller/Level.ts (1)</summary> * `LevelWithUser` (9-11) </details> </blockquote></details> <details> <summary>server/plugins/plugin-discord-ratebot.ts (5)</summary><blockquote> <details> <summary>controller/ActionController.ts (1)</summary> * `ActionHookPayload` (201-210) </details> <details> <summary>server/utils/useLogger.ts (1)</summary> * `useLogger` (11-11) </details> <details> <summary>server/utils/useServerConfig.ts (1)</summary> * `useServerConfig` (5-15) </details> <details> <summary>controller/LevelController.ts (1)</summary> * `LevelController` (9-187) </details> <details> <summary>controller/Level.ts (1)</summary> * `LevelWithUser` (9-11) </details> </blockquote></details> </details> </details> <details> <summary>🔇 Additional comments (2)</summary><blockquote> <details> <summary>package.json (1)</summary><blockquote> `22-48`: **Проверьте совместимость обновлённых версий зависимостей** Вы обновили несколько ключевых пакетов (drizzle-kit / drizzle-orm, nitropack, @vercel/edge-config, testcontainers и т.п.). На уровне `package.json` всё выглядит нормально, но такие апдейты часто тянут мелкие breaking‑changes, поэтому имеет смысл прогнать полный тестовый прогон и миграции на всех целевых окружениях и, при необходимости, свериться с changelog‑ами этих библиотек. </blockquote></details> <details> <summary>server/plugins/plugin-telegram-ratebot.ts (1)</summary><blockquote> `19-27`: **Инициализация Nitro‑плагина и регистрация hook‑а выглядят корректно** Подключение к `action:level_rate` с асинхронным обработчиком и обёрткой в `try/catch` выглядит аккуратно: ошибки внутри нотификаций не «роняют» основной flow, логируются через `useLogger().warn`. Никаких проблем по структуре или семантике здесь не вижу. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
Summary by CodeRabbit
Новое в этом релизе
✏️ Tip: You can customize this high-level summary in your review settings.