aves_mio1/lib/remote/new/remote_client.dart
FabioMich66 5e112be16b
Some checks are pending
Quality check / Flutter analysis (push) Waiting to run
Quality check / CodeQL analysis (java-kotlin) (push) Waiting to run
ok
2026-03-07 05:42:08 +01:00

93 lines
3.1 KiB
Dart

// lib/remote/remote_client.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'remote_models.dart';
import 'auth_client.dart';
class RemoteJsonClient {
final Uri indexUri; // es. https://prova.patachina.it/photos/
final RemoteAuth? auth; // opzionale: se presente, aggiunge Bearer
RemoteJsonClient(
String baseUrl,
String indexPath, {
this.auth,
}) : indexUri = Uri.parse(baseUrl.endsWith('/') ? baseUrl : '$baseUrl/')
.resolve(indexPath);
Future<List<RemotePhotoItem>> fetchAll() async {
Map<String, String> headers = {};
if (auth != null) {
headers = await auth!.authHeaders();
}
// DEBUG: stampa la URL precisa
// ignore: avoid_print
print('[remote-client] GET $indexUri');
http.Response res;
try {
res = await http.get(indexUri, headers: headers).timeout(const Duration(seconds: 20));
} catch (e) {
throw Exception('Errore rete su $indexUri: $e');
}
// Retry 1 volta in caso di 401 (token scaduto/invalidato)
if (res.statusCode == 401 && auth != null) {
headers = await auth!.refreshAndHeaders();
res = await http.get(indexUri, headers: headers).timeout(const Duration(seconds: 20));
}
// Follow 30x mantenendo Authorization
if ({301, 302, 307, 308}.contains(res.statusCode) && res.headers['location'] != null) {
final loc = res.headers['location']!;
final redirectUri = indexUri.resolve(loc);
res = await http.get(redirectUri, headers: headers).timeout(const Duration(seconds: 20));
}
if (res.statusCode != 200) {
final snippet = utf8.decode(res.bodyBytes.take(200).toList());
throw Exception('HTTP ${res.statusCode} ${res.reasonPhrase} su $indexUri. Body: $snippet');
}
final body = utf8.decode(res.bodyBytes);
// Qui siamo espliciti: ci aspettiamo SEMPRE una lista top-level
final dynamic decoded = json.decode(body);
if (decoded is! List) {
throw Exception('JSON inatteso: atteso array top-level, ricevuto ${decoded.runtimeType}');
}
final List<dynamic> rawList = decoded;
// --- DIAGNOSTICA: conteggio pattern dai dati del SERVER (non stampo il JSON intero)
int withOriginal = 0, withoutOriginal = 0, leadingSlash = 0, noLeadingSlash = 0;
for (final e in rawList) {
if (e is Map<String, dynamic>) {
final p = (e['path'] ?? '').toString();
if (p.startsWith('/')) {
leadingSlash++;
} else {
noLeadingSlash++;
}
if (p.contains('/original/')) {
withOriginal++;
} else {
withoutOriginal++;
}
}
}
// ignore: avoid_print
print('[remote-client] SERVER paths -> withOriginal=$withOriginal | withoutOriginal=$withoutOriginal | '
'leadingSlash=$leadingSlash | noLeadingSlash=$noLeadingSlash');
// Costruiamo List<RemotePhotoItem>
final List<RemotePhotoItem> items = rawList.map<RemotePhotoItem>((e) {
if (e is! Map<String, dynamic>) {
throw Exception('Elemento JSON non è una mappa: ${e.runtimeType} -> $e');
}
return RemotePhotoItem.fromJson(e);
}).toList();
return items;
}
}