aves_mio22/lib/remote.ok/remote_client.dart.ok
2026-04-18 20:05:02 +02:00

117 lines
3.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// lib/remote/remote_client.dart
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'remote_models.dart';
import 'auth_client.dart';
class RemoteJsonClient {
final Uri indexUri;
final RemoteAuth? auth;
RemoteJsonClient(
String baseUrl,
String indexPath, {
this.auth,
}) : indexUri = Uri.parse(
baseUrl.endsWith('/') ? baseUrl : '$baseUrl/',
).resolve(indexPath);
// 🔥 PING SUPER LEGGERO → usa /ping
Future<void> ping() async {
final client = HttpClient();
client.connectionTimeout = const Duration(seconds: 2);
// Costruisce lURL /ping a partire dalla baseUrl
final pingUri = Uri.parse(indexUri.origin + '/ping');
try {
final req = await client.getUrl(pingUri);
req.followRedirects = false;
final res = await req.close().timeout(const Duration(seconds: 2));
print('[remote-client] PING url=$pingUri status=${res.statusCode}');
// 5xx → errore server
if (res.statusCode >= 500) {
throw HttpException('HTTP ${res.statusCode}', uri: pingUri);
}
// 200, 401, 403, 404 → server raggiungibile
} on TimeoutException {
throw TimeoutException('Ping timeout');
} on SocketException catch (e) {
throw SocketException('Network error: ${e.message}');
} on HttpException {
rethrow;
} catch (e) {
rethrow;
} finally {
client.close();
}
}
// FETCH ALL (come prima)
Future<List<RemotePhotoItem>> fetchAll() async {
Map<String, String> headers = {};
if (auth != null) {
headers = await auth!.authHeaders();
}
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');
}
if (res.statusCode == 401 && auth != null) {
headers = await auth!.refreshAndHeaders();
res = await http
.get(indexUri, headers: headers)
.timeout(const Duration(seconds: 20));
}
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 HttpException(
'HTTP ${res.statusCode} ${res.reasonPhrase}. Body: $snippet',
uri: indexUri,
);
}
final body = utf8.decode(res.bodyBytes);
final dynamic decoded = json.decode(body);
if (decoded is! List) {
throw Exception(
'JSON inatteso: atteso array top-level, ricevuto ${decoded.runtimeType}',
);
}
final rawList = decoded as List<dynamic>;
return 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();
}
}