From 7e33390534ef7c93724f892a0c2bfccadd017309 Mon Sep 17 00:00:00 2001 From: Tom Bursch Date: Mon, 3 Feb 2025 21:39:34 +0100 Subject: [PATCH 1/2] fix: Make API-Service more robust to network outages --- kitchenowl/lib/services/api/api_service.dart | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/kitchenowl/lib/services/api/api_service.dart b/kitchenowl/lib/services/api/api_service.dart index c7a92185..a2da56f7 100644 --- a/kitchenowl/lib/services/api/api_service.dart +++ b/kitchenowl/lib/services/api/api_service.dart @@ -180,9 +180,11 @@ class ApiService { (int.tryParse((await Config.packageInfo)?.buildNumber ?? '0') ?? 0) && (healthy.item2!['version'] ?? 0) >= Config.MIN_BACKEND_VERSION) { - await getInstance().refreshAuth() - ? status = Connection.authenticated - : status = Connection.connected; + status = switch (await getInstance().refreshAuth()) { + null => Connection.disconnected, + true => Connection.authenticated, + false => Connection.connected, + }; } else { status = healthy.item2 == null || (healthy.item2!['version'] ?? 0) < Config.MIN_BACKEND_VERSION @@ -331,7 +333,7 @@ class ApiService { return const Tuple2(false, null); } - Future refreshAuth() async { + Future refreshAuth() async { if (_handleTokenBeforeReauth != null) { _refreshToken = await _handleTokenBeforeReauth!(_refreshToken); } @@ -353,13 +355,13 @@ class ApiService { if (_handleTokenRotation != null) { _handleTokenRotation!(_refreshToken!); } - _setConnectionState(Connection.authenticated); return true; + } else if (res.statusCode == 401 || res.statusCode == 403) { + return false; } } catch (_) {} - - return false; + return null; } Future login(String username, String password) async { From ca51ddf8da6a1fba7681bfc87e7c6be0edebe5f2 Mon Sep 17 00:00:00 2001 From: Tom Bursch Date: Mon, 3 Feb 2025 21:45:43 +0100 Subject: [PATCH 2/2] Remove tuple --- kitchenowl/lib/services/api/api_service.dart | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/kitchenowl/lib/services/api/api_service.dart b/kitchenowl/lib/services/api/api_service.dart index a2da56f7..833e13fc 100644 --- a/kitchenowl/lib/services/api/api_service.dart +++ b/kitchenowl/lib/services/api/api_service.dart @@ -8,7 +8,6 @@ import 'package:kitchenowl/helpers/named_bytearray.dart'; import 'package:kitchenowl/models/household.dart'; import 'package:kitchenowl/models/token.dart'; import 'package:socket_io_client/socket_io_client.dart'; -import 'package:tuple/tuple.dart'; // Export extensions export 'user.dart'; @@ -173,21 +172,21 @@ class ApiService { Connection status = Connection.disconnected; if (baseUrl.isNotEmpty) { final healthy = await getInstance().healthy(); - _serverInfoNotifier.value = healthy.item2; - if (healthy.item1) { - if (healthy.item2 != null && - healthy.item2!['min_frontend_version'] <= + _serverInfoNotifier.value = healthy.body; + if (healthy.success) { + if (healthy.body != null && + healthy.body!['min_frontend_version'] <= (int.tryParse((await Config.packageInfo)?.buildNumber ?? '0') ?? 0) && - (healthy.item2!['version'] ?? 0) >= Config.MIN_BACKEND_VERSION) { + (healthy.body!['version'] ?? 0) >= Config.MIN_BACKEND_VERSION) { status = switch (await getInstance().refreshAuth()) { null => Connection.disconnected, true => Connection.authenticated, false => Connection.connected, }; } else { - status = healthy.item2 == null || - (healthy.item2!['version'] ?? 0) < Config.MIN_BACKEND_VERSION + status = healthy.body == null || + (healthy.body!['version'] ?? 0) < Config.MIN_BACKEND_VERSION ? Connection.unsupportedBackend : Connection.unsupportedFrontend; } @@ -311,7 +310,7 @@ class ApiService { _connectionNotifier.value = newState; } - Future?>> healthy() async { + Future<({bool success, Map? body})> healthy() async { try { final res = await get( '/health/8M4F88S8ooi4sMbLBfkkV7ctWwgibW6V', @@ -319,9 +318,9 @@ class ApiService { timeout: _TIMEOUT_HEALTH, ); if (res.statusCode == 200) { - return Tuple2( - jsonDecode(res.body)['msg'] == 'OK', - jsonDecode(res.body), + return ( + success: jsonDecode(res.body)['msg'] == 'OK', + body: jsonDecode(res.body) as Map?, ); } else { debugPrint("Health check: Response code ${res.statusCode}"); @@ -330,7 +329,7 @@ class ApiService { debugPrint("Health check: ${ex.toString()}"); } - return const Tuple2(false, null); + return const (success: false, body: null); } Future refreshAuth() async {