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;
|
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) {
|
if (_jwtFuture != null) {
|
||||||
Log.print('⏳ getJWT: تجديد قيد التنفيذ — إعادة استخدام نفس الـ future.');
|
Log.print('⏳ getJWT: تجديد قيد التنفيذ — إعادة استخدام نفس الـ future.');
|
||||||
return _jwtFuture!;
|
return _jwtFuture!;
|
||||||
@@ -297,7 +304,8 @@ class LoginDriverController extends GetxController {
|
|||||||
final driverId = box.read(BoxName.driverID);
|
final driverId = box.read(BoxName.driverID);
|
||||||
final isRegistering = driverId == null || driverId.toString().isEmpty;
|
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 = {
|
var payload = {
|
||||||
'id': box.read(BoxName.driverID) ?? AK.newId,
|
'id': box.read(BoxName.driverID) ?? AK.newId,
|
||||||
'password': AK.passnpassenger,
|
'password': AK.passnpassenger,
|
||||||
@@ -306,13 +314,16 @@ class LoginDriverController extends GetxController {
|
|||||||
await DeviceHelper.getDeviceFingerprint(),
|
await DeviceHelper.getDeviceFingerprint(),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response0 = await http.post(
|
var response0 = await http
|
||||||
Uri.parse(AppLink.loginFirstTimeDriver),
|
.post(
|
||||||
body: payload,
|
Uri.parse(AppLink.loginFirstTimeDriver),
|
||||||
).timeout(const Duration(seconds: 30));
|
body: payload,
|
||||||
|
)
|
||||||
|
.timeout(const Duration(seconds: 30));
|
||||||
|
|
||||||
if (response0.statusCode == 429) {
|
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));
|
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: retryAfter));
|
||||||
Log.print('🛑 getJWT(firstTime): 429 — cooldown ${retryAfter}s');
|
Log.print('🛑 getJWT(firstTime): 429 — cooldown ${retryAfter}s');
|
||||||
return false;
|
return false;
|
||||||
@@ -351,13 +362,16 @@ class LoginDriverController extends GetxController {
|
|||||||
await DeviceHelper.getDeviceFingerprint(),
|
await DeviceHelper.getDeviceFingerprint(),
|
||||||
};
|
};
|
||||||
|
|
||||||
var response1 = await http.post(
|
var response1 = await http
|
||||||
Uri.parse(AppLink.loginJwtDriver),
|
.post(
|
||||||
body: payload,
|
Uri.parse(AppLink.loginJwtDriver),
|
||||||
).timeout(const Duration(seconds: 30));
|
body: payload,
|
||||||
|
)
|
||||||
|
.timeout(const Duration(seconds: 30));
|
||||||
|
|
||||||
if (response1.statusCode == 429) {
|
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));
|
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: retryAfter));
|
||||||
Log.print('🛑 getJWT: 429 — cooldown ${retryAfter}ث');
|
Log.print('🛑 getJWT: 429 — cooldown ${retryAfter}ث');
|
||||||
return false;
|
return false;
|
||||||
@@ -394,7 +408,8 @@ class LoginDriverController extends GetxController {
|
|||||||
_jwtFailures++;
|
_jwtFailures++;
|
||||||
final seconds = _jwtFailures >= 6 ? 60 : (1 << _jwtFailures);
|
final seconds = _jwtFailures >= 6 ? 60 : (1 << _jwtFailures);
|
||||||
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: seconds));
|
_jwtCooldownUntil = DateTime.now().add(Duration(seconds: seconds));
|
||||||
Log.print('❌ getJWT فشل ($reason) — محاولة #$_jwtFailures، cooldown ${seconds}ث');
|
Log.print(
|
||||||
|
'❌ getJWT فشل ($reason) — محاولة #$_jwtFailures، cooldown ${seconds}ث');
|
||||||
return false;
|
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 {
|
loginDriver(String driverID, email) async {
|
||||||
isloading = true;
|
isloading = true;
|
||||||
update();
|
update();
|
||||||
@@ -452,6 +484,40 @@ class LoginDriverController extends GetxController {
|
|||||||
var res = await CRUD().get(
|
var res = await CRUD().get(
|
||||||
link: AppLink.loginFromGoogleCaptin, payload: {'driver_id': driverID});
|
link: AppLink.loginFromGoogleCaptin, payload: {'driver_id': driverID});
|
||||||
Log.print('loginDriver: ${res}');
|
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') {
|
if (res == 'failure') {
|
||||||
await isPhoneVerified();
|
await isPhoneVerified();
|
||||||
isloading = false; // <--- أضفت هذا أيضاً
|
isloading = false; // <--- أضفت هذا أيضاً
|
||||||
@@ -459,7 +525,21 @@ class LoginDriverController extends GetxController {
|
|||||||
return false;
|
return false;
|
||||||
// Get.snackbar('Failure', '', backgroundColor: Colors.red);
|
// Get.snackbar('Failure', '', backgroundColor: Colors.red);
|
||||||
} else {
|
} 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];
|
var d = jsonDecoeded['data'][0];
|
||||||
if (jsonDecoeded.isNotEmpty) {
|
if (jsonDecoeded.isNotEmpty) {
|
||||||
if (jsonDecoeded['status'] == 'success' &&
|
if (jsonDecoeded['status'] == 'success' &&
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:package_info_plus/package_info_plus.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/controller/auth/captin/login_captin_controller.dart';
|
||||||
import 'package:siro_driver/views/auth/captin/login_captin.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 'package:siro_driver/views/home/on_boarding_page.dart';
|
||||||
import '../functions/app_update_controller.dart';
|
import '../functions/app_update_controller.dart';
|
||||||
|
|
||||||
@@ -131,7 +132,9 @@ class SplashScreenController extends GetxController
|
|||||||
await EncryptionHelper.initialize();
|
await EncryptionHelper.initialize();
|
||||||
|
|
||||||
await DeviceHelper.getDeviceFingerprint();
|
await DeviceHelper.getDeviceFingerprint();
|
||||||
await loginController.getJWT();
|
// بداية باردة يبدأها المستخدم ⇒ force حتى لا يمنعنا الـ cooldown
|
||||||
|
// من توليد توكن جديد بعد انتهاء صلاحية الـ 4 ساعات.
|
||||||
|
await loginController.getJWT(force: true);
|
||||||
|
|
||||||
await loginController.loginDriver(
|
await loginController.loginDriver(
|
||||||
box.read(BoxName.driverID).toString(),
|
box.read(BoxName.driverID).toString(),
|
||||||
@@ -141,6 +144,12 @@ class SplashScreenController extends GetxController
|
|||||||
return null; // لأن loginWithGoogleCredential يوجّه
|
return null; // لأن loginWithGoogleCredential يوجّه
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.print("Error during navigation logic: $e");
|
Log.print("Error during navigation logic: $e");
|
||||||
|
// لا نُسقط جلسة كابتن محفوظة ومتحقق منها بسبب خطأ عارض (شبكة/تحليل رد).
|
||||||
|
try {
|
||||||
|
if (Get.put(LoginDriverController()).hasLocalVerifiedSession) {
|
||||||
|
return HomeCaptain();
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
return LoginCaptin();
|
return LoginCaptin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user