Deploy: 2026-05-21 17:35:06
This commit is contained in:
113
whatsapp-gateway/baileys-client.js
Normal file
113
whatsapp-gateway/baileys-client.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
const { default: makeWASocket, useMultiFileAuthState, DisconnectReason } = require('@whiskeysockets/baileys');
|
||||||
|
const pino = require('pino');
|
||||||
|
const axios = require('axios');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const sessions = new Map(); // Store active sockets in memory
|
||||||
|
|
||||||
|
// Local folder for saving auth keys
|
||||||
|
const SESSIONS_DIR = path.join(__dirname, 'sessions');
|
||||||
|
if (!fs.existsSync(SESSIONS_DIR)) {
|
||||||
|
fs.mkdirSync(SESSIONS_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'YOUR_SECRET_KEY_HERE';
|
||||||
|
|
||||||
|
async function sendWebhook(webhook_url, payload) {
|
||||||
|
try {
|
||||||
|
await axios.post(webhook_url, payload, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Webhook-Secret': WEBHOOK_SECRET
|
||||||
|
},
|
||||||
|
timeout: 5000
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Failed to send webhook to ${webhook_url}:`, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startSession(session_key, webhook_url) {
|
||||||
|
// Return existing socket if it's already active
|
||||||
|
if (sessions.has(session_key)) {
|
||||||
|
return sessions.get(session_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sessionFolder = path.join(SESSIONS_DIR, session_key);
|
||||||
|
const { state, saveCreds } = await useMultiFileAuthState(sessionFolder);
|
||||||
|
|
||||||
|
const sock = makeWASocket({
|
||||||
|
auth: state,
|
||||||
|
printQRInTerminal: false,
|
||||||
|
logger: pino({ level: 'silent' }), // Suppress massive terminal output
|
||||||
|
browser: ['Nabeh Gateway', 'Chrome', '1.0.0']
|
||||||
|
});
|
||||||
|
|
||||||
|
sessions.set(session_key, sock);
|
||||||
|
|
||||||
|
sock.ev.on('creds.update', saveCreds);
|
||||||
|
|
||||||
|
sock.ev.on('connection.update', async (update) => {
|
||||||
|
const { connection, lastDisconnect, qr } = update;
|
||||||
|
|
||||||
|
if (qr) {
|
||||||
|
// Forward the raw QR code string to PHP
|
||||||
|
await sendWebhook(webhook_url, {
|
||||||
|
session_key,
|
||||||
|
state: 'waiting_qr',
|
||||||
|
qr_code: qr
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection === 'close') {
|
||||||
|
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
||||||
|
const shouldReconnect = statusCode !== DisconnectReason.loggedOut;
|
||||||
|
console.log(`Session ${session_key} connection closed. Reconnect: ${shouldReconnect}`);
|
||||||
|
|
||||||
|
if (shouldReconnect) {
|
||||||
|
// Try reconnecting after a short delay
|
||||||
|
sessions.delete(session_key);
|
||||||
|
setTimeout(() => startSession(session_key, webhook_url), 3000);
|
||||||
|
} else {
|
||||||
|
// Number was banned or manually logged out from the phone
|
||||||
|
await disconnectSession(session_key);
|
||||||
|
await sendWebhook(webhook_url, {
|
||||||
|
session_key,
|
||||||
|
state: 'disconnected'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (connection === 'open') {
|
||||||
|
console.log(`Session ${session_key} connected successfully!`);
|
||||||
|
// Parse phone number from the JID (e.g. 9665XXXXXXX@s.whatsapp.net)
|
||||||
|
const phone = sock.user.id.split(':')[0];
|
||||||
|
|
||||||
|
await sendWebhook(webhook_url, {
|
||||||
|
session_key,
|
||||||
|
state: 'connected',
|
||||||
|
phone: phone
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disconnectSession(session_key) {
|
||||||
|
const sock = sessions.get(session_key);
|
||||||
|
if (sock) {
|
||||||
|
try { sock.logout(); } catch (e) {} // best effort
|
||||||
|
sessions.delete(session_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Completely wipe the auth directory so a fresh session can be created next time
|
||||||
|
const sessionFolder = path.join(SESSIONS_DIR, session_key);
|
||||||
|
if (fs.existsSync(sessionFolder)) {
|
||||||
|
fs.rmSync(sessionFolder, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
startSession,
|
||||||
|
disconnectSession
|
||||||
|
};
|
||||||
16
whatsapp-gateway/package.json
Normal file
16
whatsapp-gateway/package.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "nabeh-whatsapp-gateway",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "WhatsApp Baileys microservice for Nabeh",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@whiskeysockets/baileys": "^6.7.9",
|
||||||
|
"axios": "^1.7.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"pino": "^9.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
52
whatsapp-gateway/server.js
Normal file
52
whatsapp-gateway/server.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const cors = require('cors');
|
||||||
|
const { startSession, disconnectSession } = require('./baileys-client');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
const PORT = process.env.PORT || 3722;
|
||||||
|
|
||||||
|
// Health check endpoint
|
||||||
|
app.get('/health', (req, res) => {
|
||||||
|
res.json({ status: 'healthy', service: 'Nabeh WhatsApp Gateway' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start or retrieve a session
|
||||||
|
app.post('/api/sessions/start', async (req, res) => {
|
||||||
|
const { session_key, webhook_url } = req.body;
|
||||||
|
|
||||||
|
if (!session_key || !webhook_url) {
|
||||||
|
return res.status(400).json({ error: 'Missing session_key or webhook_url' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await startSession(session_key, webhook_url);
|
||||||
|
res.json({ status: 'success', message: 'Session started or retrieved' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error starting session ${session_key}:`, err);
|
||||||
|
res.status(500).json({ error: 'Failed to start session' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disconnect and remove a session (e.g., when banned or logged out)
|
||||||
|
app.post('/api/sessions/disconnect', async (req, res) => {
|
||||||
|
const { session_key } = req.body;
|
||||||
|
|
||||||
|
if (!session_key) {
|
||||||
|
return res.status(400).json({ error: 'Missing session_key' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await disconnectSession(session_key);
|
||||||
|
res.json({ status: 'success', message: 'Session disconnected and cleaned up' });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error disconnecting session ${session_key}:`, err);
|
||||||
|
res.status(500).json({ error: 'Failed to disconnect session' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`🚀 Nabeh WhatsApp Gateway running on port ${PORT}`);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user