const express = require('express'); const axios = require('axios'); const app = express(); const port = process.env.PORT || 3001; const agentUrl = process.env.LLM_AGENT_URL; const openWaUrl = process.env.OPEN_WA_URL; const config = { API_URL: openWaUrl, MAX_ATTEMPTS: parseInt(process.env.MAX_ATTEMPTS || '100', 100), RETRY_MS: parseInt(process.env.RETRY_MS || '2000', 10) }; function log(level, ...args) { console[level] ? console[level](...args) : console.log(...args); } async function waitForGateway() { for (let i = 1; i <= config.MAX_ATTEMPTS; i++) { try { await axios.get(`${config.API_URL}/api-docs`); log('info', '🟢 nucleo-whatsapp ready'); return; } catch { log('warn', `Gateway not responding (attempt ${i}/${config.MAX_ATTEMPTS})…`); await new Promise(r => setTimeout(r, config.RETRY_MS)); } } throw new Error('nucleo-whatsapp did not respond in time'); } async function clearWebhooks() { try { const { data } = await axios.post(`${config.API_URL}/listWebhooks`); const hooks = data?.response || []; if (!hooks.length) { log('info', 'No existing webhooks to remove'); return; } log('info', `Removing ${hooks.length} webhooks…`); const results = await Promise.allSettled( hooks.map(h => axios.post(`${config.API_URL}/removeWebhook`, { args: { webhookId: h.id } })) ); results.forEach((r, i) => { const id = hooks[i].id; if (r.status === 'fulfilled' && r.value?.data?.response === true) { log('debug', `✔️ Removed webhook ${id}`); } else { log('warn', `⚠️ Failed to remove webhook ${id}`); } }); const ok = results.filter(r => r.status === 'fulfilled' && r.value?.data?.response === true).length; log('info', `Cleanup OK (${ok}/${hooks.length} removed)`); } catch (e) { log('error', 'Failed cleaning webhooks:', e.response?.data || e.message); } } async function registerWebhook() { const url = `http://whatsapp-router:${port}/webhook`; const eventConfig = { onAck: false, onAddedToGroup: true, onAnyMessage: true, onBattery: true, onBroadcast: true, onButton: true, onCallState: false, onChatDeleted: true, onChatOpened: true, onChatState: true, onContactAdded: true, onGlobalParticipantsChanged: true, onGroupApprovalRequest: true, onGroupChange: true, onIncomingCall: false, onLabel: true, onLogout: true, onMessage: false, onMessageDeleted: true, onNewProduct: true, onOrder: true, onPlugged: false, onPollVote: true, onReaction: true, onRemovedFromGroup: false, onStateChanged: false, onStory: false, }; const events = Object.entries(eventConfig) .filter(([_, enabled]) => enabled) .map(([event]) => event); const { data } = await axios.post(`${config.API_URL}/registerWebhook`, { args: { url, events } }); log('info', '✔️ Webhook registered:', data); } app.use(express.json()); app.post('/webhook', async (req, res) => { const { message, text, from } = req.body; const incoming = message || text; try { if (!incoming) return res.sendStatus(200); const agentRes = await axios.post(agentUrl, { message: incoming }); const reply = agentRes.data.reply || agentRes.data; await axios.post(`${openWaUrl}/send-text`, { to: from, message: reply }); } catch (err) { console.error('Error processing message', err.message); } res.sendStatus(200); }); app.listen(port, async () => { console.log(`WhatsApp router listening on ${port}`); try { await waitForGateway(); await clearWebhooks(); await registerWebhook(); } catch (err) { log('error', 'Webhook setup failed:', err.message); } });