14 KiB
14 KiB
Architecture - Rust kernel (edition 2024, guild 1509503154708811837)
bot-kernel/ # cargo init --edition 2024 --name bot-kernel
├─ Cargo.toml # serenity 0.12.5 + poise 0.7.0 + sqlx 0.9.0 + tokio 1.53 + reqwest 0.13 (cargo add)
├─ .cargo/config.toml / rustfmt.toml / clippy.toml
├─ .env.example # BOT token only; USER token → tools/userbot/.env (isolated)
├─ ROADMAP.md / ARCHITECTURE.md / SETUP.md
├─ staroe/ # архив Java kernel (21→25, build.gradle, src/kernel/loki)
├─ src/ # Rust bot (BOT token, slash + prefix)
│ ├─ main.rs # dotenv → config → pool (WAL/FK) → migration → poise → serenity
│ ├─ config/ # keys.rs, loader.rs (env→BotConfig)
│ ├─ core/ # lifecycle.rs, bot.rs (ReadyHandler + shard), dispatcher.rs, queue.rs, policy.rs
│ ├─ db/ # pool.rs (WAL, FK=ON, busy_timeout 5s), migration.rs (tx idempotent)
│ ├─ feature/ # ≤4 файла/папку, ≤200 строк/файл (см. SOLID)
│ │ ├─ help/command.rs # /help, !help (slash+prefix via poise)
│ │ ├─ info/command.rs # /ping, /serverinfo
│ │ └─ admin/command.rs # /shutdown (owners_only)
│ ├─ util/logger.rs
│ └─ bin/ds_setup.rs # Rust inspector (BOT token) - дублирует JS, но не user-token
└─ tools/userbot/ # ← ОТДЕЛЬНАЯ ПАПКА для юзер-бота (JS, только просмотр)
├─ package.json (dotenv) # node index.js inspect --user-token --guild-id 1509503154708811837
├─ index.js # fetch https://discord.com/api/v10/* с Authorization
├─ .env.example
└─ README.md
Важно: папка
tools/userbot(былаtools/ds-inspector) - изолирована отsrc/. Rust-бот никогда не импортирует user-token. JS-просмотрщик - read-only, не шлёт сообщения.
Guild 1509503154708811837 - Loki Dev (проверено 09.09.2026, целевой - только он)
- Владелец: ты (loki_boba 1414975197269987471), 22.guilds, bot
kernel:1527966600173457408уже в гильдии (permissions 18014398509481983). Не приглашать на другие - как просил. - Каналы 27: INFO (rules, welcome, announcements, releases, github-log, ✅|verify, roles), COMMUNITY (general, ru-chat, en-chat, ideas), SUPPORT (open-ticket, bug-report, ticket-faq), VOICE (work-room-1/2, create-voice, afk), STAFF (staff-chat, mod-logs, bot-commands, ticket-logs).
- Роли 16: dupe
👑 Loki/Staff/Client/Verified/RU/EN/Muted(две копии - надо чистить),kernel(bot),@everyone. - Токены валидны, хранятся в
.env/tools/userbot/.env(gitignore), не коммитим.
Code Style & Quality (English, Javadoc, no dead code, fmt/clippy)
- Language: all docs, comments, commit messages - English only (guild multi-language → EN default, RU via role
i18n.rs). Chat in code = English. - Javadoc-style comments: every
pubitem has///doc comment (like Java/** ... */): purpose, args, returns, example,// SAFETY:for sleeps. No undocumentedpub fn. - Files:
≤200lines,≤4files per folder (feature/<domain>/{mod,command,handler,service}.rs). Split if >150. - Dead code forbidden:
#[allow(dead_code)]/#[allow(unused)]forbidden - delete unused code, don't hide it. CI fails ondead_code/unused. Usecargo fix, notallow. - Formatting mandatory:
cargo fmt --checkmust pass.rustfmt.toml: edition 2024, max_width 100. Runcargo fmtbefore commit. - Clippy mandatory:
cargo clippy -- -D warningsmust pass.clippy.toml: disallowed-methods = ["std::thread::sleep"]. Fix allclippy::pedantic/nurserywarnings, no#[allow(clippy::...)]without// SAFETY:+ issue link. - CI:
cargo fmt --check && cargo clippy -- -D warnings && cargo test && cargo check- blocked on failure.
SOLID / KISS / DRY (≤200 строк/файл, ≤4 файла/папку)
Lifecycletrait - ISP, каждая фичаimpl Lifecycle.BotConfigSRP (только env),SqlitePoolDIP (инжект черезfeature::Data).RateLimiter+JobQueueDRY - не копипастим cooldown как в старомD2(7 команд копировалиgetDeterministicValue).≤200строк -clippy::too_many_lines+rustfmt max_width 100,≤4файла →feature/<domain>/{mod,command,service,repository}.
Команды - slash + prefix (poise 0.7)
- Сейчас:
help,ping,serverinfo,shutdown. Все#[poise::command(slash_command, prefix_command)]. - План блога:
/verify(кнопка → Verified),/blog <url>(RSS→embed),/ticket(кнопка),/post- все slash-first, prefix как fallback. - Регистрация:
register_in_guild(GUILD_ID=1509503154708811837)в dev (мгновенно),register_globallyв проде (до 1ч). Не используй Global Sync при итерации (антипаттерн).
Очередь / мультиядерность / анти-задержки (POLICY)
Запрещено: tokio::time::sleep, std::thread::sleep, std::thread::park внутри feature/*/command.rs без комментария // SAFETY: <причина + длительность + jitter>.
- Почему: блокировка gateway →
Missed heartbeat, 429, CloudFlare ban. Старый бот падал наHealthHttpServer single thread(A07),TrackSchedulerутечках,M!play sleep 4с(M2). - Как правильно:
ctx.defer().await?→ ответThinking..., затем тяжёлая работа вtokio::spawn/JobQueue.core/queue.rs- boundedtokio::sync::Semaphore(100)+mpsc::channel(256)(аналогMaxHandlerConcurrency=100из go антипаттерна). Burst не спавнит unbounded tasks.RateLimiterper-user + global token bucket (429Retry-After+ jitter, не хардкодsleep(1000)).sqlxasync,reqwestсtimeout 10s + context::withTimeout- неcontext.Background()бесконечно.poise::FrameworkError::CommandPanic- ловим панику handler'а, не крашим весь процесс.
- Проверка:
clippy.tomldisallowed-methods = ["std::thread::sleep"], CIgrep -R 'sleep' src/feature --include='*.rs' | grep -v 'SAFETY:' && exit 1.
src/core/queue.rs - BoundedJobQueue (Semaphore 100, channel 256, backpressure)
src/core/policy.rs - документация запрета задержек
src/core/dispatcher.rs - RateLimiter (check per user → Option<Duration>)
Верификация и тикеты - как правильно (нагуглено 09.09.2026)
Верификация (требование: embed + реакция ✅, чат заблокирован)
- Канал
#✅|verify(1509503655487737916): только чтения для всех. Overwrites:@everyone→VIEW_CHANNEL ✅,READ_MESSAGE_HISTORY ✅,ADD_REACTIONS ✅,SEND_MESSAGES ❌,ADD_REACTIONS(add new) ✅. Остальные каналы скрыты пока нет✅ Verified. - Embed: бот
/verify-setup(admin only) постит embedTitle: Проверка • Description: Нажми ✅ чтобы получить доступ+msg.react('✅'). Хранимmessage_idвguild_config.verify_message_id. - Событие:
on_raw_reaction_add(GUILD_MESSAGE_REACTIONSintent +partials: MESSAGE/CHANNEL/REACTION). Проверяемpayload.message_id == verify_message_id && emoji == ✅ && !bot. Даём роль✅ Verified (1509503250997448754 / 1509503647480811610)черезmember.add_roles. Роль бота выше Verified в иерархии, иначе 403 (частая ошибка StackOverflow). - Безопасность:
Verification Levelв Guild Settings →Medium(email +5min) илиHigh(+10min) +@everyoneбезSEND_MESSAGESв остальных каналах. Альтернатива кнопке -Button(components V2) современнее, но ты просил реакцию - делаем реакцию (Discord не рекомендует для новых, но работает). - Ошибки: бот должен иметь
MANAGE_ROLES, роль выше Verified, partials включены, неreaction.emoji.idдля unicode.
Тикет-система (SUPPORT)
- Панель: embed в
#🎫|open-ticketс кнопками (General,Bug,Support) - современный способ (не реакции). Старый🎫реакция - легаси, кнопки лучше (нет лимита 20 reactions, не надоADD_REACTIONS). - Создание:
on_interaction_create(button) →guild.create_text_channel(name=ticket-username-001, parent=SUPPORT, overwrites={@everyone: deny VIEW, user: allow VIEW+SEND, Staff: allow})в одну операциюoverwrites(неset_permissionsпо очереди - медленно, антипаттерн SO). - Варианты:
channel(до 500 каналов, видно в списке) vsthread(до 1000, не в лимит, авто-архив). Для Loki Dev -channelок, для хайлоада -thread. - Управление:
/close,/add,/remove, claim, transcript (fetch messages → Hastebin/file), лог в#🧾|ticket-logs+ DM юзеру. Чёрный список per-guild. - Best practices: категории по типам, claim чтобы не дублировать ответы, транскрипты для сокращения FAQ.
Анти-принципы (что НЕ делать) - нагуглено 09.09.2026
Собрано из discord.go/anti-patterns, discords.ai (wiki 2026), Rank.top (rate limits), discord.js, discord.py issues:
1. Токены и секреты
- Коммитить токены/
.env→ бан, скам. Фикс:dotenvy,.gitignore+DISCORD_BOT_TOKENиз env,Reset Tokenпри утечке (у тебя оба токена уже утекли - регенерируй!). - Hardcode webhook URL → спам.
2. Блокировка gateway / задержки
- Blocking event handler (sleep, тяжёлый CPU/DB/HTTP в handler) → dispatch pipeline стоп,
Missed 2 heartbeats. Фикс:defer + tokio::spawn(см. policy выше). sleepбез объяснения → запрещено (policy). Нужен jitter/backoff, неsleep(200ms)в цикле.- Sync Blocking Loops (тяжёлые вычисления в async loop) → фриз всех юзеров. Фикс:
spawn_blocking. - Not Setting MaxHandlerConcurrency → unbounded goroutines/tasks при burst. Фикс: semaphore 100.
3. Rate limits (429, CloudFlare)
- Игнор 429 / хардкод таймер → каскадный фейл, IP-бан (10k invalid /10min → CloudFlare). Фикс: парсить
X-RateLimit-Remaining/Reset-After/Retry-After, глобальная очередь,exponential backoff + jitter(full/decorrelated). Неget 429 then retryбез queue. - Global REST ~50 req/s, Gateway 1 Identify/5s, 120 events/60s per WS → шарить
max_concurrency, sharding при росте. - Channel rename 2/10min, message edit 5/5s → queue, не
msg.edit()10 раз подряд.
4. Slash vs prefix
- Глобальный sync при разработке → ждать 1ч. Фикс:
GuildCommandSync(GUILD_ID)для Loki Dev. - Второй initial response после Defer → Discord reject. Фикс: после
deferтолькоfollowup. - Reply "invalid command" на несуществующие → спам при коллизии префиксов. Фикс: silent fail, только
invalid args.
5. Интенты и кэш
- Все интеты
Intents::all()→ OOM, верификация. Фикс:GUILD_MESSAGES|MESSAGE_CONTENT|GUILDS|GUILD_MEMBERSтолько нужные (у тебя уже так). - Неиспользуемые привилегированные
MESSAGE_CONTENT,Presence→ доп. верификация.
6. Прочее
- Invite scraping (бот джойнит все сервера по инвайтам) → бан.
- Greedy prefixes (
!,$,.) → коллизии, используй уникальный (!ок, но можно!loki). - Overuse mentions / @everyone → бот-лупы, мьют.
- Unbounded listeners / cooldown=0 → спам тяжёлых DB. Фикс:
CooldownManager+RateLimiter. - Игнор паник → краш всего бота. Фикс:
poise::builtins::on_error+HandlerPanicError. - Embeds в Components V2 → reject, используй text components.
- Not handling Promise rejections / unhandled Result → молчаливый краш.
От старого бота - что уже пофикшено
- Нет
God Module/PrefixCommandRegistrar 22 param→ per-featureModule + Registrar. - Нет блокирующего
JDBCна gateway →sqlx::SqlitePoolasync. WAL + FK=ON + busy_timeout 5sчерезSqliteConnectOptions(фиксC6), миграции транзакционно (фиксC5),UndeclaredThrowableExceptionанврап не нужен (Rustanyhow).RateLimiter+JobQueueвместоCachedThreadPool(A05) иM2/M3 sleep 4sна gateway.