From 7847839ea66290f1cfcb65188b130b3bfacc2728 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Thu, 15 Dec 2022 15:42:21 +0400 Subject: [PATCH 1/3] feat: Enable server provider logging --- assets/translations/en.json | 1 + assets/translations/ru.json | 1 + .../digital_ocean/digital_ocean.dart | 2 +- .../server_providers/hetzner/hetzner.dart | 2 +- .../server_installation_cubit.dart | 33 ++++++++++++------- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index d490583e..daa4544f 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -392,6 +392,7 @@ "generation_error": "Couldn't generate a recovery key. {}" }, "modals": { + "server_validators_error": "Couldn't fetch available servers.", "already_exists": "Such server already exists.", "unexpected_error": "Unexpected error during placement from the provider side.", "destroy_server": "Destroy the server and create a new one?", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 17cdbcad..a5cc6634 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -392,6 +392,7 @@ "generation_error": "Не удалось сгенерировать ключ. {}" }, "modals": { + "server_validators_error": "Не удалось получить список серверов.", "already_exists": "Такой сервер уже существует.", "unexpected_error": "Непредвиденная ошибка со стороны провайдера.", "destroy_server": "Уничтожить сервер и создать новый?", diff --git a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart index 1ab5795c..c7928653 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean.dart @@ -23,7 +23,7 @@ import 'package:selfprivacy/utils/password_generator.dart'; class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { DigitalOceanApi({ required this.region, - this.hasLogger = false, + this.hasLogger = true, this.isWithToken = true, }); @override diff --git a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart index 6e2049e9..f0e032e8 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner.dart @@ -24,7 +24,7 @@ import 'package:selfprivacy/utils/password_generator.dart'; class HetznerApi extends ServerProviderApi with VolumeProviderApi { HetznerApi({ this.region, - this.hasLogger = false, + this.hasLogger = true, this.isWithToken = true, }); @override diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index c63154c0..4da57479 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -633,18 +633,27 @@ class ServerInstallationCubit extends Cubit { state as ServerInstallationRecovery; final List servers = await repository.getServersOnProviderAccount(); - final Iterable validated = servers.map( - (final ServerBasicInfo server) => - ServerBasicInfoWithValidators.fromServerBasicInfo( - serverBasicInfo: server, - isIpValid: server.ip == dataState.serverDetails?.ip4, - isReverseDnsValid: - server.reverseDns == dataState.serverDomain?.domainName || - server.reverseDns == - dataState.serverDomain?.domainName.split('.')[0], - ), - ); - return validated.toList(); + List validatedList = []; + try { + final Iterable validated = servers.map( + (final ServerBasicInfo server) => + ServerBasicInfoWithValidators.fromServerBasicInfo( + serverBasicInfo: server, + isIpValid: server.ip == dataState.serverDetails?.ip4, + isReverseDnsValid: + server.reverseDns == dataState.serverDomain?.domainName || + server.reverseDns == + dataState.serverDomain?.domainName.split('.')[0], + ), + ); + validatedList = validated.toList(); + } catch (e) { + print(e); + getIt() + .showSnackBar('modals.server_validators_error'.tr()); + } + + return validatedList; } Future setServerId(final ServerBasicInfo server) async { From 813d275d1262a0ef74313beac66f4b0d78f3dc26 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 19 Dec 2022 22:47:35 +0400 Subject: [PATCH 2/3] feat: Implement logging for GraphQL API map Log to application console all requests and all responses --- lib/logic/api_maps/graphql_maps/api_map.dart | 58 ++++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/lib/logic/api_maps/graphql_maps/api_map.dart b/lib/logic/api_maps/graphql_maps/api_map.dart index 185a5e54..0f786417 100644 --- a/lib/logic/api_maps/graphql_maps/api_map.dart +++ b/lib/logic/api_maps/graphql_maps/api_map.dart @@ -1,9 +1,48 @@ +// ignore_for_file: prefer_foreach + +import 'dart:async'; import 'dart:io'; import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:http/io_client.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/staging_options.dart'; +import 'package:selfprivacy/logic/models/message.dart'; + +void _logToAppConsole(final T objectToLog) { + getIt.get().addMessage( + Message( + text: objectToLog.toString(), + ), + ); +} + +class LoggingLink extends Link { + @override + Stream request( + final Request request, [ + final NextLink? forward, + ]) async* { + _logToAppConsole(request); + yield* forward!(request); + } +} + +class LoggingResponseParser extends ResponseParser { + @override + Response parseResponse(final Map body) { + final response = super.parseResponse(body); + _logToAppConsole(response); + return response; + } + + @override + GraphQLError parseError(final Map error) { + final graphQlError = super.parseError(error); + _logToAppConsole(graphQlError); + return graphQlError; + } +} abstract class ApiMap { Future getClient() async { @@ -22,16 +61,23 @@ abstract class ApiMap { final httpLink = HttpLink( 'https://api.$rootAddress/graphql', httpClient: ioClient, + parser: LoggingResponseParser(), ); final String token = _getApiToken(); - final Link graphQLLink = isWithToken - ? AuthLink( - getToken: () async => - customToken == '' ? 'Bearer $token' : customToken, - ).concat(httpLink) - : httpLink; + final Link graphQLLink = LoggingLink().concat( + isWithToken + ? AuthLink( + getToken: () async => + customToken == '' ? 'Bearer $token' : customToken, + ).concat(httpLink) + : httpLink, + ); + + // Every request goes through either chain: + // 1. AuthLink -> HttpLink -> LoggingLink + // 2. HttpLink -> LoggingLink return GraphQLClient( cache: GraphQLCache(), From 8dffcab30d28caab2b679ef5c5c99c2be3d3ea41 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Mon, 19 Dec 2022 22:53:07 +0400 Subject: [PATCH 3/3] chore: Rename and unify GraphQL logging classes --- lib/logic/api_maps/graphql_maps/api_map.dart | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/logic/api_maps/graphql_maps/api_map.dart b/lib/logic/api_maps/graphql_maps/api_map.dart index 0f786417..02b9bc04 100644 --- a/lib/logic/api_maps/graphql_maps/api_map.dart +++ b/lib/logic/api_maps/graphql_maps/api_map.dart @@ -1,6 +1,3 @@ -// ignore_for_file: prefer_foreach - -import 'dart:async'; import 'dart:io'; import 'package:graphql_flutter/graphql_flutter.dart'; @@ -17,7 +14,7 @@ void _logToAppConsole(final T objectToLog) { ); } -class LoggingLink extends Link { +class RequestLoggingLink extends Link { @override Stream request( final Request request, [ @@ -28,7 +25,7 @@ class LoggingLink extends Link { } } -class LoggingResponseParser extends ResponseParser { +class ResponseLoggingParser extends ResponseParser { @override Response parseResponse(final Map body) { final response = super.parseResponse(body); @@ -61,12 +58,12 @@ abstract class ApiMap { final httpLink = HttpLink( 'https://api.$rootAddress/graphql', httpClient: ioClient, - parser: LoggingResponseParser(), + parser: ResponseLoggingParser(), ); final String token = _getApiToken(); - final Link graphQLLink = LoggingLink().concat( + final Link graphQLLink = RequestLoggingLink().concat( isWithToken ? AuthLink( getToken: () async => @@ -76,8 +73,8 @@ abstract class ApiMap { ); // Every request goes through either chain: - // 1. AuthLink -> HttpLink -> LoggingLink - // 2. HttpLink -> LoggingLink + // 1. RequestLoggingLink -> AuthLink -> HttpLink + // 2. RequestLoggingLink -> HttpLink return GraphQLClient( cache: GraphQLCache(),