Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Make API-Service more robust to network outages #645

Merged
merged 2 commits into from
Feb 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions kitchenowl/lib/services/api/api_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -173,19 +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) {
await getInstance().refreshAuth()
? status = Connection.authenticated
: status = Connection.connected;
(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;
}
Expand Down Expand Up @@ -309,17 +310,17 @@ class ApiService {
_connectionNotifier.value = newState;
}

Future<Tuple2<bool, Map<String, dynamic>?>> healthy() async {
Future<({bool success, Map<String, dynamic>? body})> healthy() async {
try {
final res = await get(
'/health/8M4F88S8ooi4sMbLBfkkV7ctWwgibW6V',
refreshOnException: false,
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<String, dynamic>?,
);
} else {
debugPrint("Health check: Response code ${res.statusCode}");
Expand All @@ -328,10 +329,10 @@ class ApiService {
debugPrint("Health check: ${ex.toString()}");
}

return const Tuple2(false, null);
return const (success: false, body: null);
}

Future<bool> refreshAuth() async {
Future<bool?> refreshAuth() async {
if (_handleTokenBeforeReauth != null) {
_refreshToken = await _handleTokenBeforeReauth!(_refreshToken);
}
Expand All @@ -353,13 +354,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<String?> login(String username, String password) async {
Expand Down
Loading