diff --git a/backend/api/whatsapp-webhook.php b/backend/api/whatsapp-webhook.php index 2d0a547..b473463 100644 --- a/backend/api/whatsapp-webhook.php +++ b/backend/api/whatsapp-webhook.php @@ -1,6 +1,6 @@ set("whatsapp:status", $state); + $sessionKey = $input['session_key']; + + $redis->set("whatsapp:{$sessionKey}:status", $state); if ($state === 'waiting_qr' && isset($input['qr_code'])) { - // Store QR code for 60 seconds - $redis->setex("whatsapp:qr", 60, $input['qr_code']); + $redis->setex("whatsapp:{$sessionKey}:qr", 60, $input['qr_code']); } elseif ($state === 'connected') { - $redis->del("whatsapp:qr"); + $redis->del("whatsapp:{$sessionKey}:qr"); if (isset($input['phone'])) { - $redis->set("whatsapp:phone", $input['phone']); + $redis->set("whatsapp:{$sessionKey}:phone", $input['phone']); } } elseif ($state === 'disconnected') { - $redis->del("whatsapp:qr"); - $redis->del("whatsapp:phone"); + $redis->del("whatsapp:{$sessionKey}:qr"); + $redis->del("whatsapp:{$sessionKey}:phone"); } } @@ -43,10 +43,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { exit; } -// Handle GET requests (Human Web Interface to scan QR code) -$status = $redis->get("whatsapp:status") ?: 'disconnected'; -$qrCode = $redis->get("whatsapp:qr"); -$phone = $redis->get("whatsapp:phone"); +// Prepare slots data for UI +$slots = []; +for ($i = 1; $i <= 6; $i++) { + $sk = "slot-{$i}"; + $slots[$sk] = [ + 'status' => $redis->get("whatsapp:{$sk}:status") ?: 'disconnected', + 'qr' => $redis->get("whatsapp:{$sk}:qr"), + 'phone' => $redis->get("whatsapp:{$sk}:phone") + ]; +} ?> @@ -61,25 +67,32 @@ $phone = $redis->get("whatsapp:phone"); font-family: 'Cairo', sans-serif; background-color: #f0f4f8; color: #333; - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; margin: 0; + padding: 20px; } - .container { - background: #fff; - padding: 30px; - border-radius: 12px; - box-shadow: 0 4px 20px rgba(0,0,0,0.08); + .header { text-align: center; - max-width: 400px; - width: 100%; + margin-bottom: 30px; } - h1 { - font-size: 22px; - margin-bottom: 20px; - color: #111; + .grid-container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 20px; + max-width: 1200px; + margin: 0 auto; + } + .card { + background: #fff; + padding: 25px; + border-radius: 12px; + box-shadow: 0 4px 15px rgba(0,0,0,0.05); + text-align: center; + } + .slot-title { + font-size: 18px; + font-weight: 700; + margin-bottom: 15px; + color: #2c3e50; } .status-badge { display: inline-block; @@ -87,83 +100,45 @@ $phone = $redis->get("whatsapp:phone"); border-radius: 20px; font-weight: 600; font-size: 14px; - margin-bottom: 25px; + margin-bottom: 15px; } - .status-connected { - background-color: #d1e7dd; - color: #0f5132; - } - .status-waiting_qr { - background-color: #fff3cd; - color: #664d03; - } - .status-disconnected { - background-color: #f8d7da; - color: #842029; - } - #qrcode { + .status-connected { background-color: #d1e7dd; color: #0f5132; } + .status-waiting_qr { background-color: #fff3cd; color: #664d03; } + .status-disconnected { background-color: #f8d7da; color: #842029; } + + .qrcode-container { display: flex; justify-content: center; - margin: 20px 0; - padding: 15px; + margin: 15px 0; + padding: 10px; background: #fff; border: 1px solid #eee; border-radius: 8px; - } - .instructions { - font-size: 14px; - color: #666; - line-height: 1.6; - margin-top: 20px; + min-height: 200px; + align-items: center; } .refresh-btn { background-color: #0d6efd; color: white; border: none; - padding: 10px 20px; + padding: 8px 16px; border-radius: 6px; cursor: pointer; font-family: 'Cairo', sans-serif; font-weight: 600; - margin-top: 15px; + margin-top: 10px; + transition: 0.2s; } - .refresh-btn:hover { - background-color: #0b5ed7; + .refresh-btn:hover { background-color: #0b5ed7; } + .global-refresh { + display: block; + margin: 20px auto; + font-size: 16px; + padding: 12px 24px; } -
-

ربط بوابة الواتساب بالخدمة

- - -
متصل بنجاح ✅
-

البوابة نشطة حالياً ومتصلة بالرقم: +

-

يمكنك البدء بإرسال الرسائل الآن!

- -
بانتظار المسح (QR) 📲
-

افتح الواتساب على هاتفك -> الأجهزة المرتبطة -> ربط جهاز، ثم امسح الكود أدناه:

- -
- - - - -
غير متصل ❌
-

- الرجاء تشغيل الجلسة أولاً عن طريق إرسال طلب البدء للبوابة من بوستمان أو سكريبت التشغيل. -

- - - -
-

حالة النظام الحالية:

diff --git a/backend/includes/WhatsApp.php b/backend/includes/WhatsApp.php index 2ddbe3f..e34151b 100644 --- a/backend/includes/WhatsApp.php +++ b/backend/includes/WhatsApp.php @@ -28,7 +28,7 @@ class WhatsAppClient { $cleanPhone = preg_replace('/[^\d]/', '', $phone); // Strip '+' and other non-digits $payload = json_encode([ - 'session_key' => self::$sessionKey, + 'session_key' => 'auto', 'phone' => $cleanPhone ]); @@ -68,7 +68,7 @@ class WhatsAppClient { $cleanPhone = preg_replace('/[^\d]/', '', $phone); $payloadData = [ - 'session_key' => self::$sessionKey, + 'session_key' => 'auto', 'phone' => $cleanPhone, 'message' => $message ]; diff --git a/whatsapp-gateway/puppeteer-client.js b/whatsapp-gateway/puppeteer-client.js index 050b9df..af3eb81 100644 --- a/whatsapp-gateway/puppeteer-client.js +++ b/whatsapp-gateway/puppeteer-client.js @@ -67,11 +67,7 @@ async function startSession(session_key, webhook_url) { clientId: session_key, dataPath: SESSIONS_DIR }), - puppeteer: puppeteerConfig, - webVersionCache: { - type: 'remote', - remotePath: 'https://raw.githubusercontent.com/wppconnect-team/wa-version/main/html/2.2412.54.html', - } + puppeteer: puppeteerConfig }); sessions.set(session_key, client); @@ -217,10 +213,16 @@ function getActiveSessions() { return Array.from(sessions.keys()); } +function isSessionReady(session_key) { + const client = sessions.get(session_key); + return !!(client && client.info && client.info.wid); +} + module.exports = { startSession, disconnectSession, sendMessage, getActiveSessions, - checkContact + checkContact, + isSessionReady }; diff --git a/whatsapp-gateway/server.js b/whatsapp-gateway/server.js index 20b07ba..7cdf79b 100644 --- a/whatsapp-gateway/server.js +++ b/whatsapp-gateway/server.js @@ -20,7 +20,7 @@ for (const p of envPaths) { const express = require('express'); const cors = require('cors'); -const { startSession, disconnectSession, sendMessage, getActiveSessions, checkContact } = require('./puppeteer-client'); +const { startSession, disconnectSession, sendMessage, getActiveSessions, checkContact, isSessionReady } = require('./puppeteer-client'); const app = express(); app.use(cors()); @@ -84,12 +84,25 @@ app.get('/api/sessions/active', (req, res) => { // Check if contact is on WhatsApp app.post('/api/contacts/check', async (req, res) => { - const { session_key, phone } = req.body; + let { session_key, phone } = req.body; if (!session_key || !phone) { return res.status(400).json({ error: 'Missing session_key or phone' }); } + if (session_key === 'auto') { + const activeSlots = []; + for (let i = 1; i <= 6; i++) { + if (isSessionReady(`slot-${i}`)) { + activeSlots.push(`slot-${i}`); + } + } + if (activeSlots.length === 0) { + return res.status(503).json({ error: 'No WhatsApp slots are ready' }); + } + session_key = activeSlots[0]; // Just use the first available slot for checking + } + try { const result = await checkContact(session_key, phone); res.json({ status: 'success', data: result }); @@ -100,8 +113,10 @@ app.post('/api/contacts/check', async (req, res) => { }); // Send outbound message +let currentSlotIndex = 1; + app.post('/api/messages/send', async (req, res) => { - const { session_key, phone, message, media_url, audio, mimetype, image } = req.body; + let { session_key, phone, message, media_url, audio, mimetype, image } = req.body; if (!session_key || !phone) { return res.status(400).json({ error: 'Missing session_key or phone' }); @@ -112,6 +127,24 @@ app.post('/api/messages/send', async (req, res) => { } try { + if (session_key === 'auto') { + const activeSlots = []; + for (let i = 1; i <= 6; i++) { + if (isSessionReady(`slot-${i}`)) { + activeSlots.push(`slot-${i}`); + } + } + + if (activeSlots.length === 0) { + return res.status(503).json({ error: 'No WhatsApp slots are currently ready to send messages' }); + } + + // Round-robin selection + session_key = activeSlots[currentSlotIndex % activeSlots.length]; + currentSlotIndex++; + console.log(`[RoundRobin] Selected ${session_key} out of ${activeSlots.length} active slots.`); + } + const result = await sendMessage(session_key, phone, message, media_url, audio, mimetype, image); res.json({ status: 'success', data: result }); } catch (err) { @@ -120,10 +153,12 @@ app.post('/api/messages/send', async (req, res) => { } }); -// Auto-start default session +// Auto-start default sessions (6 slots) setTimeout(() => { - console.log('🔄 Auto-starting default session: flash_call_otp'); - startSession('flash_call_otp', 'https://otp.intaleqapp.com/api/whatsapp-webhook.php').catch(console.error); + console.log('🔄 Auto-starting 6 WhatsApp slots...'); + for (let i = 1; i <= 6; i++) { + startSession(`slot-${i}`, 'https://otp.intaleqapp.com/api/whatsapp-webhook.php').catch(console.error); + } }, 2000); app.listen(PORT, () => {