|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { |
|
|
default: makeWASocket, |
|
|
useMultiFileAuthState, |
|
|
fetchLatestBaileysVersion, |
|
|
Browsers, |
|
|
delay, |
|
|
DisconnectReason |
|
|
} = require('@whiskeysockets/baileys'); |
|
|
const pino = require('pino'); |
|
|
const path = require('path'); |
|
|
const fs = require('fs'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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('.')}`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.sock = makeWASocket({ |
|
|
version, |
|
|
logger: this.logger, |
|
|
printQRInTerminal: true, |
|
|
auth: this.state, |
|
|
browser: Browsers.ubuntu('Chrome'), |
|
|
|
|
|
|
|
|
agent: HFCorrections ? HFCorrections.createHFAgent() : undefined, |
|
|
socketConfig: HFCorrections ? HFCorrections.createWebSocketOptions() : {}, |
|
|
|
|
|
|
|
|
connectTimeoutMs: 60000, |
|
|
defaultQueryTimeoutMs: 0, |
|
|
keepAliveIntervalMs: 30000, |
|
|
|
|
|
|
|
|
getNextIp: (host) => { |
|
|
const ip = HFCorrections ? HFCorrections.getWhatsAppIP() : undefined; |
|
|
return ip; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
if (CommandHandler) { |
|
|
this.commandHandler = new CommandHandler(this, this.sock); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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!'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getStatus() { |
|
|
return { |
|
|
isConnected: this.isConnected, |
|
|
reconnectAttempts: this.reconnectAttempts, |
|
|
botName: this.config.BOT_NAME || 'Akira Bot' |
|
|
}; |
|
|
} |
|
|
|
|
|
getQRCode() { |
|
|
return this.currentQR; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |