نسخة كاملة من مستودع سيرو عند ecfe7568 لتكون أساس تطبيق «انطلق». نُسخ المتعقَّب في git فقط (12,509 ملفاً / 302 م.ب) بـ git archive، لا `cp -r` — فاستُثنيت تلقائياً مخلفات البناء (build · node_modules · .dart_tool · .gradle · Pods ≈ 10.7 غ.ب) وكل ما يستثنيه .gitignore. هذا الكوميت **بلا أي تعديل عمداً** حتى يكون كل ما يليه فرقاً مقروءاً مقابل سيرو الأصلي. سيرو نفسه لم يُمسّ. ⚠️ لا يبني بعد: `.env` و`lib/env/env.g.dart` غير متعقَّبين في سيرو (وهذا صحيح — أسرار لكل مستأجر). كل تطبيق فلاتر هنا يحتاج .env خاصاً بانطلق ثم توليد env.g.dart عبر build_runner. لا تُنسخ أسرار سيرو. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
49 lines
1.6 KiB
Dart
49 lines
1.6 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import 'net_guard.dart';
|
|
|
|
typedef BodyEncoder = Future<http.Response> Function();
|
|
|
|
class HttpRetry {
|
|
/// ريتراي لـ network/transient errors فقط.
|
|
static Future<http.Response> sendWithRetry(
|
|
BodyEncoder send, {
|
|
int maxRetries = 3,
|
|
Duration baseDelay = const Duration(milliseconds: 400),
|
|
Duration timeout = const Duration(seconds: 12),
|
|
}) async {
|
|
// ✅ Pre-flight check for internet connection
|
|
if (!await NetGuard().hasInternet()) {
|
|
// Immediately throw a specific exception if there's no internet.
|
|
// This avoids pointless retries.
|
|
throw const SocketException("No internet connection");
|
|
}
|
|
int attempt = 0;
|
|
while (true) {
|
|
attempt++;
|
|
try {
|
|
final res = await send().timeout(timeout);
|
|
return res;
|
|
} on TimeoutException catch (_) {
|
|
if (attempt >= maxRetries) rethrow;
|
|
} on SocketException catch (_) {
|
|
if (attempt >= maxRetries) rethrow;
|
|
} on HandshakeException catch (_) {
|
|
if (attempt >= maxRetries) rethrow;
|
|
} on http.ClientException catch (e) {
|
|
// مثال: Connection reset by peer
|
|
final msg = e.message.toLowerCase();
|
|
final transient = msg.contains('connection reset') ||
|
|
msg.contains('broken pipe') ||
|
|
msg.contains('timed out');
|
|
if (!transient || attempt >= maxRetries) rethrow;
|
|
}
|
|
// backoff: 0.4s, 0.8s, 1.6s
|
|
final delay = baseDelay * (1 << (attempt - 1));
|
|
await Future.delayed(delay);
|
|
}
|
|
}
|
|
}
|