Update: 2026-08-06 14:24:16

This commit is contained in:
Hamza-Ayed
2026-08-06 14:24:16 +03:00
parent e4553dabc1
commit 52101e650c
2 changed files with 109 additions and 20 deletions
@@ -237,7 +237,14 @@ class LoginDriverController extends GetxController {
return d.isNegative ? Duration.zero : d;
}
Future<bool> getJWT() async {
/// [force] يتجاوز الـ backoff cooldown — يُستخدم فقط في المسارات التي
/// يبدأها المستخدم (فتح التطبيق / تسجيل الدخول)، لا في الطلبات الخلفية،
/// حتى لا يعلق الكابتن خارج التطبيق بانتظار انتهاء الـ cooldown.
Future<bool> getJWT({bool force = false}) async {
if (force) {
_jwtCooldownUntil = DateTime(2000);
_jwtFailures = 0;
}
if (_jwtFuture != null) {
Log.print('⏳ getJWT: تجديد قيد التنفيذ — إعادة استخدام نفس الـ future.');
return _jwtFuture!;
@@ -297,7 +304,8 @@ class LoginDriverController extends GetxController {
final driverId = box.read(BoxName.driverID);
final isRegistering = driverId == null || driverId.toString().isEmpty;
if (isRegistering && box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
if (isRegistering &&
box.read(BoxName.firstTimeLoadKey).toString() != 'false') {
var payload = {
'id': box.read(BoxName.driverID) ?? AK.newId,
'password': AK.passnpassenger,
@@ -306,18 +314,21 @@ class LoginDriverController extends GetxController {
await DeviceHelper.getDeviceFingerprint(),
};
var response0 = await http.post(
Uri.parse(AppLink.loginFirstTimeDriver),
body: payload,
).timeout(const Duration(seconds: 30));
var response0 = await http
.post(
Uri.parse(AppLink.loginFirstTimeDriver),
body: payload,
)
.timeout(const Duration(seconds: 30));
if (response0.statusCode == 429) {
final retryAfter = int.tryParse(response0.headers['retry-after'] ?? '') ?? 60;
final retryAfter =
int.tryParse(response0.headers['retry-after'] ?? '') ?? 60;
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: retryAfter));
Log.print('🛑 getJWT(firstTime): 429 — cooldown ${retryAfter}s');
return false;
}
if (response0.statusCode == 200) {
final decodedResponse1 = jsonDecode(response0.body);
String? jwt;
@@ -350,14 +361,17 @@ class LoginDriverController extends GetxController {
'fingerPrint': box.read(BoxName.deviceFingerprint) ??
await DeviceHelper.getDeviceFingerprint(),
};
var response1 = await http.post(
Uri.parse(AppLink.loginJwtDriver),
body: payload,
).timeout(const Duration(seconds: 30));
var response1 = await http
.post(
Uri.parse(AppLink.loginJwtDriver),
body: payload,
)
.timeout(const Duration(seconds: 30));
if (response1.statusCode == 429) {
final retryAfter = int.tryParse(response1.headers['retry-after'] ?? '') ?? 60;
final retryAfter =
int.tryParse(response1.headers['retry-after'] ?? '') ?? 60;
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: retryAfter));
Log.print('🛑 getJWT: 429 — cooldown ${retryAfter}ث');
return false;
@@ -394,7 +408,8 @@ class LoginDriverController extends GetxController {
_jwtFailures++;
final seconds = _jwtFailures >= 6 ? 60 : (1 << _jwtFailures);
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: seconds));
Log.print('❌ getJWT فشل ($reason) — محاولة #$_jwtFailures، cooldown ${seconds}ث');
Log.print(
'❌ getJWT فشل ($reason) — محاولة #$_jwtFailures، cooldown ${seconds}ث');
return false;
}
@@ -443,6 +458,23 @@ class LoginDriverController extends GetxController {
}
}
/// جلسة محلية صالحة: عندنا driverID + رقم متحقق منه مسبقاً.
/// في هذه الحالة أي فشل شبكة/توكن هو عارض ولا يجوز إرجاع الكابتن لـ OTP.
bool get hasLocalVerifiedSession {
final id = box.read(BoxName.driverID)?.toString() ?? '';
return id.isNotEmpty &&
box.read(BoxName.phoneVerified).toString() == '1' &&
box.read(BoxName.firstTimeLoadKey).toString() == 'false';
}
/// نتائج عارضة من CRUD (ليست JSON) — شبكة/توكن/ضغط سيرفر.
static const _transientResults = {
'failure',
'no_internet',
'token_expired',
'rate_limited',
};
loginDriver(String driverID, email) async {
isloading = true;
update();
@@ -452,6 +484,40 @@ class LoginDriverController extends GetxController {
var res = await CRUD().get(
link: AppLink.loginFromGoogleCaptin, payload: {'driver_id': driverID});
Log.print('loginDriver: ${res}');
// ═══════════════════════════════════════════════════════════════
// فشل عارض (شبكة / توكن منتهي / rate limit):
// إذا الجهاز محفوظ والرقم متحقق ⇒ لا نرجع لـ OTP إطلاقاً.
// نجدّد التوكن مرة (متجاوزين الـ cooldown) ونعيد المحاولة مرة واحدة.
// ═══════════════════════════════════════════════════════════════
if (res is String && _transientResults.contains(res)) {
if (hasLocalVerifiedSession) {
Log.print('⚠️ loginDriver: نتيجة عارضة "$res" مع جلسة محلية صالحة — '
'إعادة محاولة بعد تجديد التوكن قسراً.');
final refreshed = await getJWT(force: true);
if (refreshed) {
res = await CRUD().get(
link: AppLink.loginFromGoogleCaptin,
payload: {'driver_id': driverID});
Log.print('loginDriver(retry): $res');
}
}
// ما زالت النتيجة عارضة
if (res is String && _transientResults.contains(res)) {
isloading = false;
update();
if (hasLocalVerifiedSession) {
// ندخله للتطبيق بجلسته المحفوظة بدل رميه على OTP.
mySnackbarError('Connection problem, please try again'.tr);
Get.offAll(() => HomeCaptain());
return true;
}
await isPhoneVerified();
return false;
}
}
if (res == 'failure') {
await isPhoneVerified();
isloading = false; // <--- أضفت هذا أيضاً
@@ -459,7 +525,21 @@ class LoginDriverController extends GetxController {
return false;
// Get.snackbar('Failure', '', backgroundColor: Colors.red);
} else {
var jsonDecoeded = jsonDecode(res);
dynamic jsonDecoeded;
try {
jsonDecoeded = jsonDecode(res);
} catch (e) {
// رد غير JSON — لا نُسقط الجلسة بسببه.
Log.print('❌ loginDriver: رد غير صالح "$res" ($e)');
isloading = false;
update();
if (hasLocalVerifiedSession) {
Get.offAll(() => HomeCaptain());
return true;
}
await isPhoneVerified();
return false;
}
var d = jsonDecoeded['data'][0];
if (jsonDecoeded.isNotEmpty) {
if (jsonDecoeded['status'] == 'success' &&
@@ -537,7 +617,7 @@ class LoginDriverController extends GetxController {
final serverFp = serverData['data'][0]['fingerPrint'].toString();
final tokenMismatch =
storedToken.isNotEmpty && serverToken != storedToken;
final fingerprintMismatch =
final fingerprintMismatch =
serverFp.isNotEmpty && serverFp != fingerPrint.toString();
Log.print(
'🔍 [FP_COMPARE] serverFp: $serverFp | localFp: ${fingerPrint.toString()} | fingerprintMismatch: $fingerprintMismatch | tokenMismatch: $tokenMismatch | serverToken: $serverToken | storedToken: $storedToken');