2026-08-09 19:16:52 +03:00
|
|
|
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';
|
2026-08-09 16:53:38 +03:00
|
|
|
import { logger } from './core/logger.js';
|
2026-08-09 19:16:52 +03:00
|
|
|
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';
|
2026-08-09 16:53:38 +03:00
|
|
|
|
2026-08-09 19:16:52 +03:00
|
|
|
// 1. Конфиг и БД — падаем понятной ошибкой, если что-то не задано.
|
|
|
|
|
try {
|
|
|
|
|
assertConfig();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
logger.error(err.message);
|
|
|
|
|
process.exit(1);
|
2026-08-09 16:53:38 +03:00
|
|
|
}
|
2026-08-09 19:16:52 +03:00
|
|
|
openDb();
|
2026-08-09 16:53:38 +03:00
|
|
|
|
2026-08-09 19:16:52 +03:00
|
|
|
// 2. Юзербот (MTProto): подключаемся уже готовой сессией.
|
|
|
|
|
const client = createUserbot();
|
|
|
|
|
let me;
|
2026-08-09 16:53:38 +03:00
|
|
|
try {
|
2026-08-09 19:16:52 +03:00
|
|
|
me = await startUserbot(client);
|
2026-08-09 16:53:38 +03:00
|
|
|
} catch (err) {
|
2026-08-09 19:16:52 +03:00
|
|
|
logger.error('Не удалось подключить юзербот. Проверьте SESSION/API_ID/API_HASH.', err.message);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
});
|
|
|
|
|
}
|