-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add fallback backends with respect to load + Backend rework (#613)
* Start rework load service * Fix wordinf * Remove sendStartNotification * Add first failover implementation * Add failover implementation when loading the app * Remove option to use beta deployment for normal users * Start reworking load service * Rework failover implementation * Fix comment * Refactor code * Refactor code * Add recommendFallback to model * Fix typo * WIP * Fix syntax * Refactor load servi e * Fix title in home view * Fix persistence of city selection * Remove second get backend function in settings and refactor code * Rename node to backend * fix prev value set city * Remove unused load service * Remove unused isLoading and reset in load service * Refactor checkLoad function to check both default and fallback backend and use default if both are not usable * Add naming convention for backends * Fix auth service to support multiple configs * Refactor load service * Undo backend renaming * Fix fallback logic --------- Co-authored-by: PaulPickhardt <s2137275@msx.tu-dresden.de>
- Loading branch information
1 parent
c1befc4
commit ac48e2d
Showing
48 changed files
with
641 additions
and
1,280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
class BackendStatus { | ||
/// If another backend should be used. | ||
final bool recommendOtherBackend; | ||
|
||
/// If the backend has a load warning. | ||
final bool warning; | ||
|
||
/// The timestamp of the current load status data. | ||
final DateTime timestamp; | ||
|
||
BackendStatus({required this.recommendOtherBackend, required this.warning, required this.timestamp}); | ||
|
||
factory BackendStatus.fromJson(Map<String, dynamic> json) => BackendStatus( | ||
recommendOtherBackend: json['recommendOtherBackend'], | ||
warning: json['warning'], | ||
timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] * 1000), | ||
); | ||
|
||
Map<String, dynamic> toJson() => { | ||
'recommendOtherBackend': recommendOtherBackend, | ||
'warning': warning, | ||
'timestamp': timestamp.millisecondsSinceEpoch, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,102 @@ | ||
import 'dart:convert'; | ||
|
||
import 'package:flutter/material.dart'; | ||
import 'package:priobike/home/models/backend_status.dart'; | ||
import 'package:priobike/http.dart'; | ||
import 'package:priobike/logging/logger.dart'; | ||
import 'package:priobike/logging/toast.dart'; | ||
import 'package:priobike/main.dart'; | ||
import 'package:priobike/settings/models/backend.dart'; | ||
import 'package:priobike/settings/services/features.dart'; | ||
import 'package:priobike/settings/services/settings.dart'; | ||
|
||
class LoadStatus with ChangeNotifier { | ||
/// If the service is currently loading the status history. | ||
bool isLoading = false; | ||
|
||
/// The warning that should be displayed. | ||
String? text; | ||
|
||
/// If there exists a warning. | ||
bool hasWarning = false; | ||
|
||
/// If the fallback backend should be used. | ||
bool useFallback = false; | ||
|
||
/// Logger for the status history. | ||
final log = Logger("Load"); | ||
|
||
LoadStatus(); | ||
|
||
/// Fetches the status data from the priobike-load-service. | ||
Future<void> fetch() async { | ||
if (isLoading) return; | ||
isLoading = true; | ||
/// Fetches the status data and returns if the given backend is usable. | ||
/// Otherwise also checking the fallback backend. | ||
/// If both backends are not usable, the default is used. | ||
Future<void> checkLoad() async { | ||
final baseUrl = getIt<Settings>().city.defaultBackend.path; | ||
var (hasWarning, recommendOtherBackend) = await fetchLoad(baseUrl); | ||
useFallback = recommendOtherBackend; | ||
this.hasWarning = hasWarning; | ||
|
||
if (recommendOtherBackend) { | ||
// If the default backend should not be used, we try to fetch the status of the fallback backend. | ||
// If the fallback backend is not usable, we use the default backend anyway. | ||
try { | ||
final baseUrl = getIt<Settings>().city.fallbackBackend?.path; | ||
|
||
if (baseUrl == null) { | ||
throw Exception("No fallback backend available"); | ||
} | ||
|
||
var (_, recommendOtherBackend) = await fetchLoad(baseUrl); | ||
useFallback = !recommendOtherBackend; | ||
} catch (e, stacktrace) { | ||
final hint = "Error while checking fallback backend: $e $stacktrace"; | ||
log.e(hint); | ||
useFallback = false; | ||
} | ||
} | ||
|
||
try { | ||
final settings = getIt<Settings>(); | ||
final baseUrl = settings.backend.path; | ||
if (getIt<Feature>().canEnableInternalFeatures) { | ||
// Don't switch the backend if the internal version is used. We want to keep the possibility | ||
// to manually set the backend. | ||
if (useFallback) { | ||
ToastMessage.showError( | ||
"Fallback müsste benutzt werden. Aufgrund der internen Version wird das Fallback jedoch nicht benutzt."); | ||
} | ||
useFallback = false; | ||
} | ||
|
||
final url = "https://$baseUrl/load-service/static/load_response.json"; | ||
notifyListeners(); | ||
} | ||
|
||
/// Returns if a warning should be shown and if another backend should be used. | ||
Future<(bool, bool)> fetchLoad(String baseUrl) async { | ||
bool hasWarning = false; | ||
bool recommendOtherBackend = false; | ||
try { | ||
final url = "https://$baseUrl/load-service/load.json"; | ||
final endpoint = Uri.parse(url); | ||
|
||
final response = await Http.get(endpoint).timeout(const Duration(seconds: 4)); | ||
|
||
if (response.statusCode != 200) { | ||
isLoading = false; | ||
notifyListeners(); | ||
final err = "Error while fetching load status from $endpoint: ${response.statusCode}"; | ||
throw Exception(err); | ||
} | ||
|
||
final json = jsonDecode(response.body); | ||
final backendStatus = BackendStatus.fromJson(json); | ||
|
||
if (json["warning"]) { | ||
// Load status is updated every minute. | ||
// If the timestamp of the status is older than 5 minutes, we assume the backend is not usable. | ||
if (DateTime.now().difference(backendStatus.timestamp).inMinutes > 5) { | ||
hasWarning = true; | ||
text = json["response_text"]; | ||
recommendOtherBackend = true; | ||
log.w("Load status is older than 5 minutes"); | ||
} else { | ||
hasWarning = false; | ||
text = null; | ||
hasWarning = backendStatus.warning; | ||
recommendOtherBackend = backendStatus.recommendOtherBackend; | ||
} | ||
|
||
isLoading = false; | ||
notifyListeners(); | ||
} catch (e, stacktrace) { | ||
isLoading = false; | ||
notifyListeners(); | ||
final hint = "Error while fetching load status: $e $stacktrace"; | ||
final hint = "Error while fetching load status for backend: $e $stacktrace"; | ||
log.e(hint); | ||
hasWarning = true; | ||
recommendOtherBackend = true; | ||
} | ||
} | ||
|
||
/// Sends an app start notification to the load service in the backend. | ||
Future<void> sendAppStartNotification() async { | ||
try { | ||
final settings = getIt<Settings>(); | ||
final baseUrl = settings.backend.path; | ||
|
||
final url = "https://$baseUrl/load-service/app/start"; | ||
final endpoint = Uri.parse(url); | ||
|
||
final response = await Http.post(endpoint).timeout(const Duration(seconds: 4)); | ||
if (response.statusCode != 200) { | ||
final err = "Error while sending app start to load service $endpoint: ${response.statusCode}"; | ||
throw Exception(err); | ||
} | ||
} catch (e, stacktrace) { | ||
final hint = "Error while sending app start to load service: $e $stacktrace"; | ||
log.e(hint); | ||
} | ||
} | ||
|
||
/// Reset the status. | ||
Future<void> reset() async { | ||
hasWarning = false; | ||
text = null; | ||
isLoading = false; | ||
notifyListeners(); | ||
return (hasWarning, recommendOtherBackend); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.