File size: 7,715 Bytes
7226ab4
 
9124c31
7226ab4
9124c31
7226ab4
 
 
 
 
 
 
 
 
9124c31
7226ab4
 
9124c31
 
7226ab4
9124c31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7226ab4
9124c31
 
 
 
 
 
 
 
 
 
7226ab4
9124c31
 
 
 
7226ab4
9124c31
 
7226ab4
 
debc420
9124c31
45cb98b
9124c31
 
 
 
 
 
 
7226ab4
 
 
9124c31
7226ab4
 
9124c31
 
 
 
 
 
9fb3417
 
7226ab4
9124c31
7226ab4
 
 
9124c31
 
 
 
9fb3417
7226ab4
9124c31
7226ab4
9124c31
 
 
 
7226ab4
9124c31
 
 
 
45cb98b
9124c31
 
 
45cb98b
9124c31
 
 
 
45cb98b
9124c31
 
 
 
7226ab4
9124c31
7226ab4
9124c31
 
 
45cb98b
7226ab4
9124c31
7226ab4
9124c31
7226ab4
9124c31
 
7226ab4
9124c31
 
 
7226ab4
 
9124c31
 
 
 
 
 
 
 
 
 
 
 
 
 
7226ab4
 
 
9124c31
 
 
 
 
7226ab4
 
 
9124c31
 
45cb98b
9124c31
 
 
 
 
 
45cb98b
9124c31
 
debc420
9124c31
debc420
45cb98b
9124c31
 
9fb3417
7226ab4
 
 
9124c31
7226ab4
 
 
 
45cb98b
9124c31
7226ab4
 
 
9124c31
 
45cb98b
 
 
9124c31
45cb98b
9124c31
45cb98b
9124c31
 
 
 
 
45cb98b
 
7226ab4
 
9124c31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/**
 * ═══════════════════════════════════════════════════════════════════════
 * 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;