Переписать проект в личный MTProto-юзербот
Смена архитектуры с бизнес-бота на Bot API (команды со слешем) на личный юзербот на GramJS/MTProto с управлением через компаньон-бота. Возможности: - antidelete — кэш входящих в личке, восстановление удалённых «у всех» - onetime — перехват «просмотр один раз» фото/видео до истечения ссылки - локальное хранилище node:sqlite + шифрование AES-256-GCM, чистка по сроку - компаньон-бот (grammY): инлайн-панель, лента с пагинацией, выдача медиа, доступ только владельцу по OWNER_ID Устройство: - core/ — crypto, db, media, loader, registry, logger - userbot/ — MTProto-клиент из строки сессии, подписка на события - modules/ — фичи как модули с хуками setup/onMessage/onEdited/onDeleted - bot/ — компаньон-бот (единственный UI) - scripts/login.js — генерация строки сессии Удалён старый код Bot API (commands/, handlers/, middlewares/, dispatcher, store). Обновлены README и .env.example. Hcrgram/ (сторонний референс) добавлен в .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+56
-28
@@ -1,34 +1,62 @@
|
||||
import { GrammyError } from 'grammy';
|
||||
|
||||
import { ALLOWED_UPDATES, createBot, shutdown, syncCommands } from './bot.js';
|
||||
import { assertConfig, config } from './config.js';
|
||||
import { createBot } from './bot/panel.js';
|
||||
import { openDb, purgeOld } from './core/db.js';
|
||||
import { loadModules } from './core/loader.js';
|
||||
import { logger } from './core/logger.js';
|
||||
import { runHook } from './core/registry.js';
|
||||
import { createUserbot, startUserbot } from './userbot/client.js';
|
||||
import { createContext } from './userbot/context.js';
|
||||
import { wireEvents } from './userbot/events.js';
|
||||
|
||||
const { bot, registry } = await createBot();
|
||||
// 1. Конфиг и БД — падаем понятной ошибкой, если что-то не задано.
|
||||
try {
|
||||
assertConfig();
|
||||
} catch (err) {
|
||||
logger.error(err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
openDb();
|
||||
|
||||
for (const signal of ['SIGINT', 'SIGTERM']) {
|
||||
process.once(signal, () => {
|
||||
shutdown(bot).then(
|
||||
() => process.exit(0),
|
||||
(err) => {
|
||||
logger.error('Ошибка при остановке', err);
|
||||
process.exit(1);
|
||||
},
|
||||
);
|
||||
});
|
||||
// 2. Юзербот (MTProto): подключаемся уже готовой сессией.
|
||||
const client = createUserbot();
|
||||
let me;
|
||||
try {
|
||||
me = await startUserbot(client);
|
||||
} catch (err) {
|
||||
logger.error('Не удалось подключить юзербот. Проверьте SESSION/API_ID/API_HASH.', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
await bot.start({
|
||||
allowed_updates: ALLOWED_UPDATES,
|
||||
// Первый апдейт приходит уже после getMe, поэтому меню обновляем здесь.
|
||||
onStart: async ({ username }) => {
|
||||
await syncCommands(bot, registry).catch((err) => logger.warn('setMyCommands не прошёл', err));
|
||||
logger.info(`@${username} запущен. Апдейты: ${ALLOWED_UPDATES.join(', ')}`);
|
||||
},
|
||||
// 3. Компаньон-бот (единственный UI) — запускаем в фоне.
|
||||
const bot = createBot();
|
||||
bot.start({ onStart: ({ username }) => logger.info(`Панель поднята: @${username}`) }).catch((err) => {
|
||||
logger.error('Компаньон-бот не запустился (проверьте BOT_TOKEN):', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// 4. Модули: грузим и раздаём им события юзербота.
|
||||
const registry = await loadModules();
|
||||
const ctx = createContext({ client, bot, me, registry });
|
||||
await runHook(registry, 'setup', undefined, ctx);
|
||||
wireEvents(client, registry, ctx);
|
||||
|
||||
logger.info(`Готово. Активных модулей: ${registry.list().map((m) => m.name).join(', ')}`);
|
||||
|
||||
// 5. Периодическая чистка по сроку хранения.
|
||||
if (config.retentionDays > 0) {
|
||||
const timer = setInterval(() => {
|
||||
const { messages, captures } = purgeOld();
|
||||
if (messages || captures) logger.info(`Чистка: удалено сообщений ${messages}, перехватов ${captures}`);
|
||||
}, 6 * 3600 * 1000);
|
||||
timer.unref();
|
||||
}
|
||||
|
||||
// 6. Аккуратная остановка.
|
||||
for (const signal of ['SIGINT', 'SIGTERM']) {
|
||||
process.once(signal, async () => {
|
||||
logger.info('Останавливаюсь…');
|
||||
await bot.stop().catch(() => {});
|
||||
await client.disconnect().catch(() => {});
|
||||
process.exit(0);
|
||||
});
|
||||
} catch (err) {
|
||||
// bot.catch() ловит ошибки апдейтов, но не падения на старте.
|
||||
if (err instanceof GrammyError && err.error_code === 401) {
|
||||
logger.error('Telegram не принял токен (401). Проверьте BOT_TOKEN в .env.');
|
||||
} else {
|
||||
logger.error('Не удалось запустить б�
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user