bot-me / src /bots /botManager.ts
Mohammed Foud
all
1c7e8ea
import { Telegraf } from "telegraf";
import { telegrafBots } from "../models";
import { setupCommandHandlers } from "./handlers/commandHandlers";
import { setupCallbackHandlers } from "./handlers/index";
import { BotContext } from "./types/botTypes";
import { supabase } from "../db/supabase";
import { createLogger } from "../utils/logger";
import { messageManager } from "./utils/messageManager";
import { handleLanguageSelection, handleLanguageChange } from "./handlers/languageHandlers";
import { getBotIdFromToken, saveBotTokenMapping, isValidBotToken } from "../utils/botUtils";
import { groupCheckMiddleware } from "./middleware/groupCheckMiddleware";
// import { balanceUpdateService } from "./services/BalanceUpdateService";
const logger = createLogger('BotManager');
export const BotCommands: { command: string; description: string }[] = [
{ command: 'start', description: 'بدء البوت' },
{ command: 'help', description: 'يعرض قائمة المساعدة' },
{ command: 'about', description: 'معلومات عن البوت' },
{ command: 'contact', description: 'تواصل معنا' },
{ command: 'balance', description: 'رصيدي' },
{ command: 'change_language', description: 'تغيير اللغة / Change language' },
];
// Add this interface to match your database schema
export interface BotData {
id: string;
name: string;
user_id: string;
bot_token: string;
is_active: boolean;
currency: string;
profit_type: 'fix' | 'percentage';
profit_value_percentage: number;
profit_value_fix: number;
last_activity: string | null;
version: string;
// API Keys and External Service Configuration
fivesim_api_key: string;
paypal_client_id: string;
paypal_client_secret: string;
crypto_wallet_address: string;
admin_contact: string;
// Group Join Settings
join_group_required: boolean;
group_channel_username: string;
settings: Record<string, any>;
state: Record<string, any>;
suffix_email: string;
created_at: string;
updated_at: string;
}
// Update the initializeBot function to use our utilities
export const initializeBot = async (botToken: string, botData?: BotData) => {
try {
// Validate bot token
if (!isValidBotToken(botToken)) {
throw new Error('Invalid bot token format');
}
const bot = new Telegraf<BotContext>(botToken);
// Extract and save bot ID mapping
const botId = getBotIdFromToken(botToken);
saveBotTokenMapping(botToken, botId);
// Set bot ID and load messages
await messageManager.loadMessages();
// Set language based on bot settings or default to Arabic
messageManager.setLanguage(botData?.settings?.language || 'en');
// Add bot data to context for use in handlers
bot.context.botData = botData || null;
// Setup middleware to track activity
bot.use(async (ctx, next) => {
if (botData?.id) {
// Update last_activity in database
await supabase
.from('bots')
.update({
last_activity: new Date().toISOString()
})
.eq('id', botData.id);
}
return next();
});
// Add group check middleware
bot.use(groupCheckMiddleware);
// Setup command handlers
setupCommandHandlers(bot);
// Setup callback handlers
setupCallbackHandlers(bot);
// Initialize balance update service and ensure it's properly set up
try {
// balanceUpdateService.setBot(bot);
logger.info('Balance update service initialized successfully');
} catch (error: any) {
logger.error(`Failed to initialize balance update service: ${error.message}`);
// Continue initialization even if balance service fails
}
// Set bot commands
try {
await bot.telegram.setMyCommands(BotCommands, {
scope: { type: 'default' }
});
logger.info('Bot commands set successfully');
} catch (error: any) {
logger.error(`Failed to set bot commands: ${error.message}`);
// Continue initialization even if setting commands fails
}
return {
success: true,
message: botData?.name ? `Bot "${botData.name}" initialized successfully` : "Bot initialized successfully",
bot
};
} catch (error: any) {
logger.error(`Failed to initialize bot: ${error.message}`);
return { success: false, message: `Failed to initialize bot: ${error.message}` };
}
};
// Utility function to update bot status in database
const updateBotStatus = async (botId: string, isActive: boolean, error?: string) => {
try {
await supabase
.from('bots')
.update({
is_active: isActive,
last_activity: new Date().toISOString(),
state: {
status: isActive ? 'running' : 'error',
startedAt: isActive ? new Date().toISOString() : undefined,
error: error
}
})
.eq('id', botId);
} catch (error: any) {
logger.error(`Error updating bot status: ${error.message}`);
}
};
export const stopBot = async (botId: string) => {
try {
// Get bot token from database
const { data: botData, error } = await supabase
.from('bots')
.select('bot_token')
.eq('id', botId)
.single();
if (error || !botData) {
await updateBotStatus(botId, false, "Bot not found in database");
return { success: false, message: "Bot not found in database" };
}
const botToken = botData.bot_token;
const bot = telegrafBots.get(botToken);
if (bot) {
await bot.stop();
telegrafBots.delete(botToken);
// Update database
await updateBotStatus(botId, false);
return { success: true, message: "Bot stopped successfully" };
}
// Bot instance not found
await updateBotStatus(botId, false, "Bot instance not found");
return { success: false, message: "Bot instance not found" };
} catch (error: any) {
logger.error(`Error stopping bot: ${error.message}`);
await updateBotStatus(botId, false, error.message);
return { success: false, message: `Failed to stop bot: ${error.message}` };
}
};
// New function to update bot settings
export const updateBotSettings = async (botId: string, settings: Record<string, any>) => {
try {
// Get bot data from database
const { data: botData, error } = await supabase
.from('bots')
.select('bot_token, settings')
.eq('id', botId)
.single();
if (error || !botData) {
return { success: false, message: "Bot not found in database" };
}
// Merge existing settings with new ones
const updatedSettings = { ...(botData.settings || {}), ...settings };
// Update database
await supabase
.from('bots')
.update({
settings: updatedSettings,
updated_at: new Date().toISOString()
})
.eq('id', botId);
// Update running bot if it exists
const bot = telegrafBots.get(botData.bot_token);
if (bot && bot.context) {
bot.context.botData = {
...(bot.context.botData || {}),
settings: updatedSettings
};
}
return { success: true, message: "Bot settings updated successfully" };
} catch (error: any) {
logger.error(`Error updating bot settings: ${error.message}`);
return { success: false, message: `Failed to update bot settings: ${error.message}` };
}
};