64 lines
1.6 KiB
Dart
64 lines
1.6 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import 'intra_api_exception.dart';
|
|
|
|
/// GET API 42 avec gestion 401 / 429 (retry + backoff).
|
|
Future<http.Response> intraApiGet(
|
|
Uri uri, {
|
|
required Map<String, String> headers,
|
|
int maxAttempts = 4,
|
|
}) async {
|
|
for (var attempt = 0; attempt < maxAttempts; attempt++) {
|
|
final response = await http.get(uri, headers: headers);
|
|
|
|
if (response.statusCode == 429) {
|
|
if (attempt + 1 >= maxAttempts) {
|
|
throw const IntraRateLimitException();
|
|
}
|
|
await Future<void>.delayed(_retryDelay(response, attempt));
|
|
continue;
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
throw const IntraRateLimitException();
|
|
}
|
|
|
|
Duration _retryDelay(http.Response response, int attempt) {
|
|
final header = response.headers['retry-after'];
|
|
if (header != null) {
|
|
final seconds = int.tryParse(header.trim());
|
|
if (seconds != null && seconds > 0) {
|
|
return Duration(seconds: seconds.clamp(1, 30));
|
|
}
|
|
}
|
|
// 0.8s, 1.6s, 3.2s…
|
|
final ms = 800 * (1 << attempt);
|
|
return Duration(milliseconds: ms.clamp(800, 8000));
|
|
}
|
|
|
|
void ensureIntraOk(http.Response response) {
|
|
if (response.statusCode == 401) {
|
|
throw const IntraUnauthorizedException();
|
|
}
|
|
if (response.statusCode == 403) {
|
|
throw const IntraForbiddenException();
|
|
}
|
|
if (response.statusCode == 429) {
|
|
throw const IntraRateLimitException();
|
|
}
|
|
if (response.statusCode != 200) {
|
|
throw IntraApiErrorException(
|
|
'Erreur API (${response.statusCode})',
|
|
);
|
|
}
|
|
}
|
|
|
|
dynamic decodeIntraBody(http.Response response) {
|
|
ensureIntraOk(response);
|
|
return jsonDecode(response.body);
|
|
}
|