Перевести проект на Telegram Business (без хранения сессии)
Смена архитектуры с MTProto-юзербота (GramJS + строка сессии) на официальное бизнес-подключение Telegram (Bot API). Проект больше НЕ хранит сессию — работает только через бота с включённым Business Mode, подключённого в Настройках → Telegram для бизнеса → Чат-боты. Это соответствует ToS. Изменения: - удалено: scripts/login.js, src/userbot/client.js, модуль onetime - src/userbot/ → src/business/: events.js подписывает business_message / edited / deleted / connection и нормализует сообщение; context.js даёт ctx.api = bot.api - core/media.js: скачивание через getFile + fetch вместо GramJS - core/db.js: составной ключ PRIMARY KEY (chat_id, msg_id) — в Bot API message_id уникален только внутри чата - bot/panel.js: барьер владельца пропускает бизнес-апдейты (у них ctx.from это собеседник); убран UI одноразовых - index.js: сборка только на grammY, явный allowed_updates с бизнес-типами - config.js: убраны API_ID/API_HASH/SESSION, проверки на старте почищены - package.json: убраны зависимости telegram и input, скрипт login - README и .env.example переписаны под бизнес-подключение Границы: onetime невозможен через Business API (сервер отбрасывает self-destruct до доставки боту), медиа >~20 МБ не выгружаются (лимит getFile), перехват — только личные 1-на-1 чаты. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+27
-24
@@ -4,9 +4,18 @@ 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';
|
||||
import { createContext } from './business/context.js';
|
||||
import { wireBusiness } from './business/events.js';
|
||||
|
||||
// Бизнес-апдейты Telegram по умолчанию не приходят — их нужно запросить явно.
|
||||
const ALLOWED_UPDATES = [
|
||||
'message',
|
||||
'callback_query',
|
||||
'business_connection',
|
||||
'business_message',
|
||||
'edited_business_message',
|
||||
'deleted_business_messages',
|
||||
];
|
||||
|
||||
// 1. Конфиг и БД — падаем понятной ошибкой, если что-то не задано.
|
||||
try {
|
||||
@@ -17,32 +26,27 @@ try {
|
||||
}
|
||||
openDb();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 3. Компаньон-бот (единственный UI) — запускаем в фоне.
|
||||
// 2. Бот (единственный UI и приёмник бизнес-апдейтов) — запускаем в фоне.
|
||||
const bot = createBot();
|
||||
bot.start({ onStart: ({ username }) => logger.info(`Панель поднята: @${username}`) }).catch((err) => {
|
||||
logger.error('Компаньон-бот не запустился (проверьте BOT_TOKEN):', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
bot
|
||||
.start({
|
||||
allowed_updates: ALLOWED_UPDATES,
|
||||
onStart: ({ username }) => logger.info(`Панель поднята: @${username}`),
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error('Бот не запустился (проверьте BOT_TOKEN):', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// 4. Модули: грузим и раздаём им события юзербота.
|
||||
// 3. Модули: грузим и раздаём им бизнес-апдейты через хуки.
|
||||
const registry = await loadModules();
|
||||
const ctx = createContext({ client, bot, me, registry });
|
||||
const ctx = createContext({ bot, registry });
|
||||
await runHook(registry, 'setup', undefined, ctx);
|
||||
wireEvents(client, registry, ctx);
|
||||
wireBusiness(bot, registry, ctx);
|
||||
|
||||
logger.info(`Готово. Активных модулей: ${registry.list().map((m) => m.name).join(', ')}`);
|
||||
|
||||
// 5. Периодическая чистка по сроку хранения.
|
||||
// 4. Периодическая чистка по сроку хранения.
|
||||
if (config.retentionDays > 0) {
|
||||
const timer = setInterval(() => {
|
||||
const { messages, captures } = purgeOld();
|
||||
@@ -51,12 +55,11 @@ if (config.retentionDays > 0) {
|
||||
timer.unref();
|
||||
}
|
||||
|
||||
// 6. Аккуратная остановка.
|
||||
// 5. Аккуратная остановка.
|
||||
for (const signal of ['SIGINT', 'SIGTERM']) {
|
||||
process.once(signal, async () => {
|
||||
logger.info('Останавливаюсь…');
|
||||
await bot.stop().catch(() => {});
|
||||
await client.disconnect().catch(() => {});
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user