From 899a18b52d2431804c0b54a859859672489035ff Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Mon, 27 Jul 2026 01:26:20 +0300 Subject: [PATCH] =?UTF-8?q?=D8=AD=D8=B1=D8=B3=20=D8=A7=D9=84=D8=B3=D9=88?= =?UTF-8?q?=D9=83=D9=8A=D8=AA=D8=A7=D8=AA=20=D8=A7=D9=84=D9=85=D9=83=D8=B1?= =?UTF-8?q?=D9=91=D8=B1=D8=A9=20=D9=84=D9=84=D8=B3=D8=A7=D8=A6=D9=82=20?= =?UTF-8?q?=E2=80=94=20=D8=B3=D8=A8=D8=A8=20=C2=ABnotified=200/0=C2=BB=20?= =?UTF-8?q?=D9=88=D8=AA=D8=AD=D8=B0=D9=8A=D8=B1=D8=A7=D8=AA=20null?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit في لوج الإنتاج ثلاثة اتصالات متزامنة للسائق نفسه (التطبيق يفتح سوكيتاً من location_controller وآخر من background_service ومحاولات لم تُنظَّف): ✅ Driver Connected: #243ea… (×3) ومعالج disconnect كان ينفّذ unset($connectedDrivers[$driverId]) بلا تحقّق من أيّ سوكيت أُغلق. فإغلاق نسخة واحدة كان يُطفئ السائق فعلياً وهو متصل: 1) dispatch_order يراه offline فيضع الطلب في طابور الانتظار بدل إرساله، ويظهر في اللوج: 🚫 Ride #2569 cancelled — notified 0/0 driver(s). 2) update_location من سوكيت ما زال حياً يجد $driverState[$driverId] محذوفاً، و &$driverState[...] يُنشئ مدخلاً null فتُقرأ منه كل الحسابات: Warning: Trying to access array offset on value of type null (860-872) Warning: Undefined array key "status" (907) الإصلاحان: - نحفظ sid (معرّف السوكيت) مع السجلّ، ولا ننظّف في disconnect إلا إذا كان المُغلَق هو المسجَّل حالياً؛ وإلا نتركه ونسجّل «stale duplicate». - حرس على $driverState في update_location: يُعاد بناؤه إن غاب لأي سبب (إغلاق نسخة أخرى، إعادة تشغيل) بدل القراءة من null. سيرفر فقط — لا يحتاج بناء التطبيقات. يبقى فتح التطبيق لعدة سوكيتات هدراً في الحركة يستحق إصلاحاً في الطرف الآخر لاحقاً. Co-Authored-By: Claude Opus 5 --- loction_server/driver_socket.php | 35 +++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/loction_server/driver_socket.php b/loction_server/driver_socket.php index 86c46d4e..f90acbb6 100755 --- a/loction_server/driver_socket.php +++ b/loction_server/driver_socket.php @@ -743,10 +743,18 @@ $io->on('connection', function ($socket) use ($INTERNAL_KEY) { } $socket->join('driver_' . $driverId); + + // ‏نحفظ معرّف السوكيت مع السجلّ: التطبيق يفتح أكثر من اتصال للسائق نفسه + // ‏(location_controller و background_service ومحاولات لم تُنظَّف)، وحين يُغلق + // ‏أحدها كان معالج disconnect يمحو السائق من السجلّ كاملاً بينما البقية + // ‏متصلة — فيعتبره dispatch_order غير متصل ويضع الطلب في طابور الانتظار، + // ‏ويظهر في اللوج «notified 0/0 driver(s)». + $socketId = $socket->id; $connectedDrivers[$driverId] = [ 'conn' => $socket, 'platform' => $platform, 'token' => $fcmToken, + 'sid' => $socketId, ]; if (!isset($driverState[$driverId])) { @@ -837,6 +845,21 @@ $io->on('connection', function ($socket) use ($INTERNAL_KEY) { if ($lat === null || $lng === null) return; + // ‏حرس: لو حُذفت الحالة (إغلاق سوكيت آخر لنفس السائق، أو إعادة تشغيل) + // ‏فإن ‎&$driverState[$driverId]‎ يُنشئ مدخلاً null فتقرأ كل الأسطر التالية + // ‏من null — وهذا مصدر تحذيرات «array offset on value of type null» في + // ‏الأسطر 860‑872 و«Undefined array key status» في 907. + if (!isset($driverState[$driverId]) || !is_array($driverState[$driverId])) { + $driverState[$driverId] = [ + 'lat' => 0.0, + 'lng' => 0.0, + 'speed' => -999.0, + 'heading' => -999.0, + 'status' => '', + 'expire_ts' => 0, + ]; + } + $state = &$driverState[$driverId]; $now = time(); @@ -996,9 +1019,19 @@ $io->on('connection', function ($socket) use ($INTERNAL_KEY) { ], $INTERNAL_KEY, $busFwdThrottle); }); - $socket->on('disconnect', function () use ($driverId) { + $socket->on('disconnect', function () use ($driverId, $socketId) { global $connectedDrivers, $driverState, $fwdThrottle; + // ‏لا ننظّف إلا إذا كان المُغلَق هو السوكيت المسجَّل حالياً. الجهاز يفتح + // ‏عدة اتصالات للسائق نفسه، وتنظيف السجلّ عند إغلاق نسخة قديمة كان + // ‏يُطفئ السائق فعلياً وهو متصل: التوزيع يراه offline، و update_location + // ‏من السوكيت الحيّ يجد $driverState محذوفاً فتظهر تحذيرات null. + $registeredSid = $connectedDrivers[$driverId]['sid'] ?? null; + if ($registeredSid !== null && $registeredSid !== $socketId) { + logMsg("↩️ Stale duplicate socket closed for #$driverId — registry kept."); + return; + } + unset($connectedDrivers[$driverId]); unset($driverState[$driverId]); unset($fwdThrottle[$driverId]);