Update: 2026-08-06 14:24:16
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user