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,13 +314,16 @@ class LoginDriverController extends GetxController {
await DeviceHelper.getDeviceFingerprint(),
};
var response0 = await http.post(
var response0 = await http
.post(
Uri.parse(AppLink.loginFirstTimeDriver),
body: payload,
).timeout(const Duration(seconds: 30));
)
.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;
@@ -351,13 +362,16 @@ class LoginDriverController extends GetxController {
await DeviceHelper.getDeviceFingerprint(),
};
var response1 = await http.post(
var response1 = await http
.post(
Uri.parse(AppLink.loginJwtDriver),
body: payload,
).timeout(const Duration(seconds: 30));
)
.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' &&
@@ -6,6 +6,7 @@ import 'package:get/get.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:siro_driver/controller/auth/captin/login_captin_controller.dart';
import 'package:siro_driver/views/auth/captin/login_captin.dart';
import 'package:siro_driver/views/home/Captin/home_captain/home_captin.dart';
import 'package:siro_driver/views/home/on_boarding_page.dart';
import '../functions/app_update_controller.dart';
@@ -131,7 +132,9 @@ class SplashScreenController extends GetxController
await EncryptionHelper.initialize();
await DeviceHelper.getDeviceFingerprint();
await loginController.getJWT();
// بداية باردة يبدأها المستخدم ⇒ force حتى لا يمنعنا الـ cooldown
// من توليد توكن جديد بعد انتهاء صلاحية الـ 4 ساعات.
await loginController.getJWT(force: true);
await loginController.loginDriver(
box.read(BoxName.driverID).toString(),
@@ -141,6 +144,12 @@ class SplashScreenController extends GetxController
return null; // لأن loginWithGoogleCredential يوجّه
} catch (e) {
Log.print("Error during navigation logic: $e");
// لا نُسقط جلسة كابتن محفوظة ومتحقق منها بسبب خطأ عارض (شبكة/تحليل رد).
try {
if (Get.put(LoginDriverController()).hasLocalVerifiedSession) {
return HomeCaptain();
}
} catch (_) {}
return LoginCaptin();
}
}