Fix payment server: remove global conRide to prevent crashing non-ride DB queries
This commit is contained in:
@@ -53,12 +53,6 @@ class Database
|
|||||||
$cfg = self::$map[$name];
|
$cfg = self::$map[$name];
|
||||||
|
|
||||||
$dbname = getenv($cfg['name']);
|
$dbname = getenv($cfg['name']);
|
||||||
|
|
||||||
// 🔥 OVERRIDE: Prevent crash if .env on server still has the old wrong name
|
|
||||||
if ($name === 'ride' && $dbname === 'intaleq-ridesDB') {
|
|
||||||
$dbname = 'rideDB';
|
|
||||||
}
|
|
||||||
|
|
||||||
$host = getenv($cfg['host']) ?: 'localhost';
|
$host = getenv($cfg['host']) ?: 'localhost';
|
||||||
$user = getenv($cfg['user']);
|
$user = getenv($cfg['user']);
|
||||||
$pass = getenv($cfg['pass']);
|
$pass = getenv($cfg['pass']);
|
||||||
|
|||||||
@@ -187,7 +187,13 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
});
|
});
|
||||||
socket!.disconnect();
|
socket!.disconnect();
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// أي تغيّر آخر (متاح ⇄ مشغول) يجب أن يصل السيرفر فوراً: هو الحدث الذي
|
||||||
|
// ينقل الكابتن بين geo:drivers:available و geo:drivers:busy. وبلا هذا
|
||||||
|
// ننتظر أول حدث GPS — وفلتر المسافة قد يؤجّله دقائق إن كان واقفاً.
|
||||||
|
_emitCurrentLocationNow();
|
||||||
});
|
});
|
||||||
|
|
||||||
bool deps = await _awaitDependencies();
|
bool deps = await _awaitDependencies();
|
||||||
@@ -349,10 +355,10 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
if (sid != null || eid != null) {
|
if (sid != null || eid != null) {
|
||||||
isSocketConnected = true;
|
isSocketConnected = true;
|
||||||
|
|
||||||
if (myLocation.latitude != 0) {
|
// هذا الـ emit هو ما يُسجّل الكابتن في geo:drivers:available بعد كل
|
||||||
|
// اتصال جديد، فلا نتخطاه لمجرد أن أول تثبيت GPS لم يصل بعد.
|
||||||
print("🚀 Sending initial location to socket after connect...");
|
print("🚀 Sending initial location to socket after connect...");
|
||||||
emitLocationToSocket(myLocation, heading, speed);
|
_emitCurrentLocationNow();
|
||||||
}
|
|
||||||
|
|
||||||
_startHeartbeat();
|
_startHeartbeat();
|
||||||
|
|
||||||
@@ -546,6 +552,30 @@ class LocationController extends GetxController with WidgetsBindingObserver {
|
|||||||
_socketHeartbeat?.cancel();
|
_socketHeartbeat?.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// يبثّ الموقع الحالي فوراً، ويجلب تثبيتاً واحداً إن لم يكن لدينا موقع بعد.
|
||||||
|
///
|
||||||
|
/// ضروري بعد كل اتصال جديد وبعد كل تغيّر حالة: ملفّ التتبّع في وضع الانتظار
|
||||||
|
/// يستخدم فلتر مسافة (50–100 متر)، فالكابتن الواقف قد لا يُصدر أي حدث
|
||||||
|
/// onLocationChanged إطلاقاً — ولو اعتمدنا عليه وحده لبقي غير مرئي على
|
||||||
|
/// خريطة الراكب حتى يتحرّك فعلياً.
|
||||||
|
Future<void> _emitCurrentLocationNow() async {
|
||||||
|
if (socket == null || !socket!.connected) return;
|
||||||
|
|
||||||
|
if (myLocation.latitude == 0 && myLocation.longitude == 0) {
|
||||||
|
await getLocation();
|
||||||
|
}
|
||||||
|
if (myLocation.latitude == 0 && myLocation.longitude == 0) {
|
||||||
|
Log.print("⚠️ No GPS fix yet — initial location emit skipped.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBusMode) {
|
||||||
|
emitBusLocationToSocket(myLocation, heading, speed);
|
||||||
|
} else {
|
||||||
|
emitLocationToSocket(myLocation, heading, speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// In LocationController.dart
|
// In LocationController.dart
|
||||||
|
|
||||||
void emitLocationToSocket(LatLng pos, double head, double spd) {
|
void emitLocationToSocket(LatLng pos, double head, double spd) {
|
||||||
|
|||||||
@@ -373,24 +373,51 @@ class HomeCaptainController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onButtonSelected() {
|
/// زرّ «متاح / غير متاح» في الواجهة — يقلب الحالة الحالية.
|
||||||
|
void onButtonSelected() => setActive(!isActive);
|
||||||
|
|
||||||
|
/// تفعيل/إيقاف الكابتن بشكل صريح.
|
||||||
|
/// مُعامِلة صريحة بدل القلب (toggle) لأن الاستدعاء التلقائي في onInit كان
|
||||||
|
/// يعتمد على أن isActive تساوي false — فأي إعادة بناء للكونترولر أو
|
||||||
|
/// استدعاء ثانٍ كانت تُطفئ الكابتن بدل تشغيله. الاستدعاء بنفس القيمة
|
||||||
|
/// الحالية آمن: يعيد التأكد من أن التتبّع شغّال فقط.
|
||||||
|
void setActive(bool active) {
|
||||||
if (!Get.isRegistered<CaptainWalletController>()) {
|
if (!Get.isRegistered<CaptainWalletController>()) {
|
||||||
Get.put(CaptainWalletController());
|
Get.put(CaptainWalletController());
|
||||||
}
|
}
|
||||||
totalPoints = Get.find<CaptainWalletController>().totalPoints;
|
totalPoints = Get.find<CaptainWalletController>().totalPoints;
|
||||||
|
|
||||||
// Toggle Active State
|
if (!active) {
|
||||||
isActive = !isActive;
|
_goOffline();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isActive) {
|
|
||||||
try {
|
try {
|
||||||
_checkFatigueBeforeOnline(); // Throws exception if tired
|
_checkFatigueBeforeOnline(); // يرمي استثناءً إذا تجاوز 12 ساعة
|
||||||
|
} catch (_) {
|
||||||
|
isActive = false;
|
||||||
|
update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (double.parse(totalPoints) > minPointsThreshold) {
|
// الرصيد غير كافٍ: نُطفئ فعلياً بدل إبقاء isActive = true بلا تتبّع،
|
||||||
|
// فقد كانت الواجهة تعرض «متاح» بينما لا يُبَث أي موقع.
|
||||||
|
final double? points = double.tryParse(totalPoints);
|
||||||
|
if (points == null || points <= minPointsThreshold) {
|
||||||
|
_goOffline();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final bool wasActive = isActive;
|
||||||
|
isActive = true;
|
||||||
|
|
||||||
|
// آمنة للاستدعاء المتكرر: تتجاهل الاشتراك إن كان قائماً بالفعل.
|
||||||
locationController.startLocationUpdates();
|
locationController.startLocationUpdates();
|
||||||
|
|
||||||
|
if (!wasActive) {
|
||||||
HapticFeedback.heavyImpact();
|
HapticFeedback.heavyImpact();
|
||||||
activeStartTime = DateTime.now();
|
activeStartTime = DateTime.now();
|
||||||
|
activeTimer?.cancel();
|
||||||
activeTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
activeTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
activeDuration = DateTime.now().difference(activeStartTime!);
|
activeDuration = DateTime.now().difference(activeStartTime!);
|
||||||
stringActiveDuration = formatDuration(activeDuration);
|
stringActiveDuration = formatDuration(activeDuration);
|
||||||
@@ -410,31 +437,51 @@ class HomeCaptainController extends GetxController {
|
|||||||
|
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
locationController.stopLocationUpdates();
|
|
||||||
activeStartTime = null;
|
|
||||||
activeTimer?.cancel();
|
|
||||||
savePeriod(activeDuration);
|
|
||||||
activeDuration = Duration.zero;
|
|
||||||
box.write('fatigue_last_offline', DateTime.now().toIso8601String());
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
// Driver is fatigued, revert state
|
void _goOffline() {
|
||||||
isActive = false;
|
isActive = false;
|
||||||
update();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
locationController.stopLocationUpdates();
|
locationController.stopLocationUpdates();
|
||||||
activeStartTime = null;
|
activeStartTime = null;
|
||||||
activeTimer?.cancel();
|
activeTimer?.cancel();
|
||||||
savePeriod(activeDuration);
|
if (activeDuration.inSeconds > 0) savePeriod(activeDuration);
|
||||||
activeDuration = Duration.zero;
|
activeDuration = Duration.zero;
|
||||||
|
|
||||||
// Save offline time for Fatigue Monitoring reset
|
// Save offline time for Fatigue Monitoring reset
|
||||||
box.write('fatigue_last_offline', DateTime.now().toIso8601String());
|
box.write('fatigue_last_offline', DateTime.now().toIso8601String());
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// يضبط حالة الكابتن المخزَّنة عند إقلاع التطبيق.
|
||||||
|
/// تذكير بمصطلحات التطبيق: 'off' = متاح، 'on' = مشغول برحلة،
|
||||||
|
/// 'blocked' = محظور، وهي القيمة التي يقرأها emitLocationToSocket ويبني
|
||||||
|
/// عليها السيرفر عضوية geo:drivers:available.
|
||||||
|
///
|
||||||
|
/// كانت 'off' تُكتب دون شرط في آخر onInit، فتُلغي حظراً ساري المفعول
|
||||||
|
/// كتبه checkAndShowBlockDialog قبلها بسطر، وتُعيد كابتناً في رحلة نشطة
|
||||||
|
/// إلى حوض المتاحين بعد إعادة فتح التطبيق.
|
||||||
|
void _applyInitialDriverStatus() {
|
||||||
|
final String? blockStr = box.read(BoxName.blockUntilDate);
|
||||||
|
if (blockStr != null && blockStr.isNotEmpty) {
|
||||||
|
final DateTime? blockExpiry = DateTime.tryParse(blockStr);
|
||||||
|
if (blockExpiry != null && DateTime.now().isBefore(blockExpiry)) {
|
||||||
|
box.write(BoxName.statusDriverLocation, 'blocked');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// رحلة نجت من إغلاق التطبيق: نُبقيه مشغولاً حتى لا يُوزَّع عليه طلب ثانٍ.
|
||||||
|
final String? rideStatus = box.read(BoxName.rideStatus);
|
||||||
|
if (rideStatus == 'Apply' || rideStatus == 'Arrived' ||
|
||||||
|
rideStatus == 'Begin') {
|
||||||
|
box.write(BoxName.statusDriverLocation, 'on');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
box.write(BoxName.statusDriverLocation, 'off'); // متاح
|
||||||
}
|
}
|
||||||
|
|
||||||
// متغيرات العداد للحظر
|
// متغيرات العداد للحظر
|
||||||
@@ -815,8 +862,16 @@ class HomeCaptainController extends GetxController {
|
|||||||
|
|
||||||
Get.put(FirebaseMessagesController());
|
Get.put(FirebaseMessagesController());
|
||||||
addToken();
|
addToken();
|
||||||
|
|
||||||
|
// ⚠️ الترتيب مقصود: الحالة تُكتب قبل تشغيل التتبّع.
|
||||||
|
// أول update_location يُرسَل بعد اتصال السوكيت مباشرة، وهو الذي يُدخل
|
||||||
|
// الكابتن إلى geo:drivers:available على السيرفر. وكتابة الحالة بعد
|
||||||
|
// تشغيل التتبّع (كما كانت في آخر السطور) تعني أن ذلك الـ emit قد يحمل
|
||||||
|
// حالة قديمة ('on' من رحلة سابقة لم تُغلق مثلاً).
|
||||||
|
_applyInitialDriverStatus();
|
||||||
|
|
||||||
await getlocation();
|
await getlocation();
|
||||||
onButtonSelected();
|
setActive(true);
|
||||||
getDriverRate();
|
getDriverRate();
|
||||||
addCustomCarIcon();
|
addCustomCarIcon();
|
||||||
getKazanPercent();
|
getKazanPercent();
|
||||||
@@ -829,8 +884,8 @@ class HomeCaptainController extends GetxController {
|
|||||||
// totalPoints = Get.find<CaptainWalletController>().totalPoints.toString();
|
// totalPoints = Get.find<CaptainWalletController>().totalPoints.toString();
|
||||||
// getRefusedOrderByCaptain();
|
// getRefusedOrderByCaptain();
|
||||||
// 🔥 الفحص عند تشغيل التطبيق
|
// 🔥 الفحص عند تشغيل التطبيق
|
||||||
|
// (يكتب 'blocked' عند وجود حظر ساري — ولم تعد أي كتابة بعده تدهسه)
|
||||||
checkAndShowBlockDialog();
|
checkAndShowBlockDialog();
|
||||||
box.write(BoxName.statusDriverLocation, 'off');
|
|
||||||
// 2. عدل الليسنر ليصبح مشروطاً
|
// 2. عدل الليسنر ليصبح مشروطاً
|
||||||
// Camera follow timer — only moves when the driver has
|
// Camera follow timer — only moves when the driver has
|
||||||
// actually moved > 15 meters, saving GPU/battery on idle.
|
// actually moved > 15 meters, saving GPU/battery on idle.
|
||||||
|
|||||||
@@ -766,6 +766,20 @@ $io->on('connection', function ($socket) use ($INTERNAL_KEY) {
|
|||||||
'status' => '',
|
'status' => '',
|
||||||
'expire_ts' => 0,
|
'expire_ts' => 0,
|
||||||
];
|
];
|
||||||
|
} else {
|
||||||
|
// اتصال جديد لا يضمن أن السائق ما زال عضواً في geo:drivers:* —
|
||||||
|
// api_get_nearby.php يحذف العضوية كلّما وجد driver:profile منتهياً
|
||||||
|
// (TTL = 900 ثانية)، بينما تبقى هذه الحالة في ذاكرة الـ worker لأن
|
||||||
|
// سوكيت خدمة الخلفية (background_service) يظل مسجَّلاً فيمنع تنظيفها
|
||||||
|
// عند إغلاق سوكيت الواجهة.
|
||||||
|
// وبلا تصفيرها يجد أول update_location بعد فتح التطبيق أن status و
|
||||||
|
// lat/lng بلا تغيير ⇒ لا GEOADD ⇒ يبقى الكابتن غير مرئي على خريطة
|
||||||
|
// الراكب حتى يتحرك 10 أمتار أو يضغط زر التوفّر (الذي يقطع السوكيت).
|
||||||
|
// نصفّر الجزء المتطاير فقط ليُجبَر أول تحديث على إعادة تسجيله.
|
||||||
|
$driverState[$driverId]['lat'] = 0.0;
|
||||||
|
$driverState[$driverId]['lng'] = 0.0;
|
||||||
|
$driverState[$driverId]['status'] = '';
|
||||||
|
$driverState[$driverId]['expire_ts'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
logMsg("✅ Driver Connected: #$driverId ($platform)");
|
logMsg("✅ Driver Connected: #$driverId ($platform)");
|
||||||
@@ -941,7 +955,12 @@ $io->on('connection', function ($socket) use ($INTERNAL_KEY) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($needGeoadd || $statusChanged) {
|
// نُعيد تأكيد العضوية في geo:drivers:* مع كل تجديد صلاحية (كل
|
||||||
|
// EXPIRE_REFRESH_SECONDS) لا عند الحركة فقط: الكابتن المتاح والواقف
|
||||||
|
// لا يُصدر didMove ولا statusChanged أبداً، فلو حُذف من المجموعة
|
||||||
|
// (انقطاع، إعادة تشغيل السيرفر، تنظيف api_get_nearby) لما عاد إليها
|
||||||
|
// قط. التكلفة: عملية GEOADD واحدة لكل كابتن كل دقيقتين.
|
||||||
|
if ($needGeoadd || $statusChanged || $needExpireRefresh) {
|
||||||
$eventBuffer[$driverId]['geoadd'] = [
|
$eventBuffer[$driverId]['geoadd'] = [
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'lng' => $lng,
|
'lng' => $lng,
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/backend/core/bootstrap.php';
|
||||||
|
$jwtService = new JwtService($redis);
|
||||||
|
$token = $jwtService->generateAccessToken('34feffd3fa72d6bee56b', 'driver', 'wallet-app:ios');
|
||||||
|
echo $token;
|
||||||
Reference in New Issue
Block a user