200 lines
5.8 KiB
JavaScript
200 lines
5.8 KiB
JavaScript
const axios = require('axios');
|
||
const config = require('../config');
|
||
const { log, logError } = require('../middleware/logger');
|
||
const User = require('../models/User');
|
||
|
||
const BOT_TOKEN = config.telegramBotToken;
|
||
const TELEGRAM_API = BOT_TOKEN ? `https://api.telegram.org/bot${BOT_TOKEN}` : null;
|
||
|
||
let isPolling = false;
|
||
let offset = 0;
|
||
|
||
const sendMessage = async (chatId, text, options = {}) => {
|
||
if (!TELEGRAM_API) {
|
||
log('warn', 'TELEGRAM_BOT_TOKEN не установлен, отправка сообщения невозможна');
|
||
return null;
|
||
}
|
||
|
||
try {
|
||
const response = await axios.post(`${TELEGRAM_API}/sendMessage`, {
|
||
chat_id: chatId,
|
||
text,
|
||
parse_mode: 'HTML',
|
||
...options
|
||
});
|
||
return response.data;
|
||
} catch (error) {
|
||
logError('Ошибка отправки сообщения', error, { chatId, text: text.substring(0, 50) });
|
||
return null;
|
||
}
|
||
};
|
||
|
||
const sendMessageToAllUsers = async (messageText) => {
|
||
if (!TELEGRAM_API) {
|
||
throw new Error('TELEGRAM_BOT_TOKEN не установлен');
|
||
}
|
||
|
||
try {
|
||
const users = await User.find({ banned: { $ne: true } }).select('telegramId');
|
||
let sent = 0;
|
||
let failed = 0;
|
||
|
||
for (const user of users) {
|
||
try {
|
||
await sendMessage(user.telegramId, messageText);
|
||
sent++;
|
||
// Небольшая задержка, чтобы не превысить лимиты API
|
||
await new Promise(resolve => setTimeout(resolve, 50));
|
||
} catch (error) {
|
||
failed++;
|
||
logError('Ошибка отправки сообщения пользователю', error, { telegramId: user.telegramId });
|
||
}
|
||
}
|
||
|
||
return { sent, failed, total: users.length };
|
||
} catch (error) {
|
||
logError('Ошибка массовой отправки сообщений', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
const getStartMessage = () => {
|
||
return `👋 <b>Добро пожаловать в Nakama!</b>
|
||
|
||
📱 <b>Nakama</b> — социальная сеть для фурри и аниме сообщества.
|
||
|
||
<b>Основные возможности:</b>
|
||
• Создание постов с текстом и изображениями
|
||
• Поиск контента через e621 и Gelbooru
|
||
• Комментарии и лайки
|
||
• Подписки на пользователей
|
||
• Система уведомлений
|
||
• Фильтры и теги
|
||
|
||
<b>Как начать:</b>
|
||
1. Нажмите кнопку "Войти" ниже, чтобы запустить приложение
|
||
2. Создайте свой первый пост
|
||
3. Подписывайтесь на интересных пользователей
|
||
|
||
<b>Поддержка:</b>
|
||
Если возникли проблемы, напишите @NakamaReportbot
|
||
|
||
Приятного использования!`;
|
||
};
|
||
|
||
const handleCommand = async (message) => {
|
||
const chatId = message.chat.id;
|
||
const text = (message.text || '').trim();
|
||
const args = text.split(/\s+/);
|
||
const command = args[0].toLowerCase();
|
||
|
||
if (command === '/start') {
|
||
const startParam = message.text.split(' ')[1] || '';
|
||
|
||
// Если есть start_param (например, post_12345 или ref_ABC123)
|
||
// Это обрабатывается при открытии миниаппа, здесь просто показываем инструкцию
|
||
const startMessage = getStartMessage();
|
||
|
||
// Добавить кнопку для открытия миниаппа
|
||
let botUsername = 'NakamaSpaceBot';
|
||
if (config.telegramBotToken) {
|
||
try {
|
||
const botInfo = await axios.get(`${TELEGRAM_API}/getMe`);
|
||
botUsername = botInfo.data.result.username || 'NakamaSpaceBot';
|
||
} catch (error) {
|
||
log('warn', 'Не удалось получить имя бота', { error: error.message });
|
||
}
|
||
}
|
||
|
||
await sendMessage(chatId, startMessage, {
|
||
reply_markup: {
|
||
inline_keyboard: [[
|
||
{
|
||
text: '🚀 Открыть Nakama',
|
||
web_app: {
|
||
url: `https://t.me/${botUsername}`
|
||
}
|
||
}
|
||
]]
|
||
}
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Игнорируем неизвестные команды
|
||
};
|
||
|
||
const processUpdate = async (update) => {
|
||
const message = update.message || update.edited_message;
|
||
if (!message || !message.text) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await handleCommand(message);
|
||
} catch (error) {
|
||
logError('Ошибка обработки команды основного бота', error, {
|
||
chatId: message.chat.id,
|
||
text: message.text?.substring(0, 50)
|
||
});
|
||
}
|
||
};
|
||
|
||
const pollUpdates = async () => {
|
||
if (!TELEGRAM_API) {
|
||
log('warn', 'Основной бот не запущен: TELEGRAM_BOT_TOKEN не установлен');
|
||
return;
|
||
}
|
||
|
||
if (isPolling) {
|
||
return;
|
||
}
|
||
|
||
isPolling = true;
|
||
log('info', 'Основной бот запущен, опрос обновлений...');
|
||
|
||
const poll = async () => {
|
||
try {
|
||
const response = await axios.get(`${TELEGRAM_API}/getUpdates`, {
|
||
params: {
|
||
offset,
|
||
timeout: 30,
|
||
allowed_updates: ['message']
|
||
}
|
||
});
|
||
|
||
const updates = response.data.result || [];
|
||
|
||
for (const update of updates) {
|
||
offset = update.update_id + 1;
|
||
await processUpdate(update);
|
||
}
|
||
|
||
// Продолжить опрос
|
||
setTimeout(poll, 1000);
|
||
} catch (error) {
|
||
logError('Ошибка опроса Telegram для основного бота', error);
|
||
// Переподключиться через 5 секунд
|
||
setTimeout(poll, 5000);
|
||
}
|
||
};
|
||
|
||
poll();
|
||
};
|
||
|
||
const startMainBot = () => {
|
||
if (!BOT_TOKEN) {
|
||
log('warn', 'Основной бот не запущен: TELEGRAM_BOT_TOKEN не установлен');
|
||
return;
|
||
}
|
||
|
||
pollUpdates();
|
||
};
|
||
|
||
module.exports = {
|
||
startMainBot,
|
||
sendMessageToAllUsers,
|
||
sendMessage
|
||
};
|
||
|