/** * ═══════════════════════════════════════════════════════════════════════ * CLASSE: BotCore (HF SPACES EDITION - SMART LOAD) * ═══════════════════════════════════════════════════════════════════════ * Núcleo do bot: Baileys wrapper, event handling e orquestração. * ═══════════════════════════════════════════════════════════════════════ */ const { default: makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion, Browsers, delay, DisconnectReason } = require('@whiskeysockets/baileys'); const pino = require('pino'); const path = require('path'); const fs = require('fs'); /** * Função de carregamento inteligente para evitar erros de "Module Not Found" * no ambiente do Hugging Face Spaces. */ function smartRequire(moduleName) { try { return require(`./${moduleName}`); } catch (e) { try { return require(`./modules/${moduleName}`); } catch (e2) { console.error(`❌ [BotCore] Erro ao carregar componente: ${moduleName}`); return null; } } } // Carregamento dos componentes e correções const HFCorrections = smartRequire('HFCorrections'); const ConfigManager = smartRequire('ConfigManager'); const APIClient = smartRequire('APIClient'); const AudioProcessor = smartRequire('AudioProcessor'); const MediaProcessor = smartRequire('MediaProcessor'); const MessageProcessor = smartRequire('MessageProcessor'); const ModerationSystem = smartRequire('ModerationSystem'); const LevelSystem = smartRequire('LevelSystem'); const CommandHandler = smartRequire('CommandHandler'); class BotCore { constructor() { this.config = ConfigManager ? ConfigManager.getInstance() : {}; this.logger = pino({ level: 'silent' }); this.sock = null; this.state = null; this.saveCreds = null; this.currentQR = null; this.isConnected = false; this.reconnectAttempts = 0; this.maxReconnectAttempts = 15; // Aumentado para resiliência no HF // Inicialização de Componentes this.apiClient = APIClient ? new APIClient() : null; this.moderation = ModerationSystem ? new ModerationSystem() : null; this.levels = LevelSystem ? new LevelSystem() : null; this.audioProcessor = AudioProcessor ? new AudioProcessor() : null; this.mediaProcessor = MediaProcessor ? new MediaProcessor() : null; this.commandHandler = null; // Definido após o socket } /** * Prepara o ambiente de arquivos */ async initialize() { console.log('📂 Preparando diretórios de sistema...'); const folders = ['auth_info', 'temp', '/tmp/akira_data']; folders.forEach(f => { if (!fs.existsSync(f)) fs.mkdirSync(f, { recursive: true }); }); return true; } /** * Estabelece conexão com WhatsApp usando DNS Hard-Patch */ async connect() { try { console.log('🔧 Configurando credenciais de autenticação...'); const { state, saveCreds } = await useMultiFileAuthState(path.join(__dirname, 'auth_info')); this.state = state; this.saveCreds = saveCreds; const { version } = await fetchLatestBaileysVersion(); console.log(`📡 Baileys Version: ${version.join('.')}`); // ═══════════════════════════════════════════════════════════════════════ // SOCKET CONFIGURATION (HF SPACES OPTIMIZED) // ═══════════════════════════════════════════════════════════════════════ this.sock = makeWASocket({ version, logger: this.logger, printQRInTerminal: true, auth: this.state, browser: Browsers.ubuntu('Chrome'), // Aplica Agente e Patch de DNS do HFCorrections agent: HFCorrections ? HFCorrections.createHFAgent() : undefined, socketConfig: HFCorrections ? HFCorrections.createWebSocketOptions() : {}, // Configurações de tempo de rede connectTimeoutMs: 60000, defaultQueryTimeoutMs: 0, keepAliveIntervalMs: 30000, // Prioriza IPv4 para evitar erros de rede do container getNextIp: (host) => { const ip = HFCorrections ? HFCorrections.getWhatsAppIP() : undefined; return ip; } }); // Vincula o CommandHandler if (CommandHandler) { this.commandHandler = new CommandHandler(this, this.sock); } // --- EVENTOS DO WHATSAPP --- this.sock.ev.on('creds.update', this.saveCreds); this.sock.ev.on('connection.update', async (update) => { const { connection, lastDisconnect, qr } = update; if (qr) { this.currentQR = qr; console.log('✨ [QR CODE] Novo código disponível na Web UI.'); } if (connection === 'close') { this.isConnected = false; const statusCode = (lastDisconnect?.error)?.output?.statusCode; const shouldReconnect = statusCode !== DisconnectReason.loggedOut; console.log(`⚠️ Conexão encerrada. Motivo: ${lastDisconnect?.error?.message || 'Desconhecido'}`); if (shouldReconnect && this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; const backoff = Math.min(this.reconnectAttempts * 5000, 45000); console.log(`🔄 Tentando reconexão em ${backoff/1000}s...`); setTimeout(() => this.connect(), backoff); } else if (statusCode === DisconnectReason.loggedOut) { console.error('❌ Sessão encerrada permanentemente. Apague a pasta auth_info.'); } } if (connection === 'open') { this.isConnected = true; this.reconnectAttempts = 0; this.currentQR = null; console.log('🚀 AKIRA BOT CONECTADO COM SUCESSO!'); } }); // Listener de Mensagens this.sock.ev.on('messages.upsert', async (chatUpdate) => { try { const m = chatUpdate.messages[0]; if (!m.message || m.key.fromMe) return; if (MessageProcessor) { const processor = new MessageProcessor(this, this.sock); await processor.handle(m); } } catch (err) { console.error('❌ Erro ao processar mensagem recebida:', err.message); } }); } catch (error) { console.error('❌ Falha crítica no BotCore:', error); throw error; } } /** * Status e Acesso para a UI */ getStatus() { return { isConnected: this.isConnected, reconnectAttempts: this.reconnectAttempts, botName: this.config.BOT_NAME || 'Akira Bot' }; } getQRCode() { return this.currentQR; } /** * Envio de mensagem com tratamento global */ async sendMessage(jid, content, options = {}) { try { if (!this.isConnected || !this.sock) return false; return await this.sock.sendMessage(jid, content, options); } catch (err) { console.error(`❌ Falha no envio para ${jid}:`, err.message); return false; } } } module.exports = BotCore;