diff --git a/docker-compose.yml b/docker-compose.yml index 501dcdf..5fd7bfa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,6 @@ services: image: gitea.interno.com/nucleo000/nucleo-whatsapp:latest container_name: nucleo-whatsapp environment: - - WEBHOOK_URL=http://whatsapp-router:3001/webhook - PORT=8080 ports: - "8080:8080" @@ -19,6 +18,7 @@ services: container_name: whatsapp-router environment: - OPEN_WA_URL=http://openwa:8080 + - LLM_AGENT_URL=http://llm-agent:8000 ports: - "3001:3001" networks: diff --git a/whatsapp-router/index.js b/whatsapp-router/index.js index c889298..6100431 100644 --- a/whatsapp-router/index.js +++ b/whatsapp-router/index.js @@ -6,6 +6,103 @@ 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 || '10', 10), + 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) => { @@ -22,4 +119,13 @@ app.post('/webhook', async (req, res) => { res.sendStatus(200); }); -app.listen(port, () => console.log(`WhatsApp router listening on ${port}`)); +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); + } +});