diff --git a/lib/logic/api_maps/graphql_maps/server_api/server.dart b/lib/logic/api_maps/graphql_maps/server_api/server.dart index c7ee23e9..04f1d855 100644 --- a/lib/logic/api_maps/graphql_maps/server_api/server.dart +++ b/lib/logic/api_maps/graphql_maps/server_api/server.dart @@ -1,6 +1,7 @@ import 'package:graphql/client.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/api_map.dart'; +import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_api.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/disk_volumes.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.dart'; @@ -8,12 +9,34 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/api_token.dart'; import 'package:selfprivacy/logic/models/json/server_disk_volume.dart'; import 'package:selfprivacy/logic/models/json/server_job.dart'; +import 'package:selfprivacy/logic/models/service.dart'; part 'volume_api.dart'; part 'jobs_api.dart'; part 'server_actions_api.dart'; part 'services_api.dart'; +class GenericMutationResult { + GenericMutationResult({ + required this.success, + required this.code, + this.message, + }); + final bool success; + final int code; + final String? message; +} + +class GenericJobMutationReturn extends GenericMutationResult { + GenericJobMutationReturn({ + required final super.success, + required final super.code, + final super.message, + this.job, + }); + final ServerJob? job; +} + class ServerApi extends ApiMap with VolumeApi, JobsApi, ServerActionsApi { ServerApi({ this.hasLogger = false, diff --git a/lib/logic/api_maps/graphql_maps/server_api/services_api.dart b/lib/logic/api_maps/graphql_maps/server_api/services_api.dart index acbb8348..62a55e15 100644 --- a/lib/logic/api_maps/graphql_maps/server_api/services_api.dart +++ b/lib/logic/api_maps/graphql_maps/server_api/services_api.dart @@ -1,3 +1,159 @@ part of 'server.dart'; -mixin ServicesApi on ApiMap {} +mixin ServicesApi on ApiMap { + Future> getAllServices() async { + QueryResult response; + List services = []; + try { + final GraphQLClient client = await getClient(); + response = await client.query$AllServices(); + if (response.hasException) { + print(response.exception.toString()); + } + services = response.parsedData?.services.allServices + .map((final service) => Service.fromGraphQL(service)) + .toList() ?? + []; + } catch (e) { + print(e); + } + return services; + } + + Future enableService(final String serviceId) async { + try { + final GraphQLClient client = await getClient(); + final variables = Variables$Mutation$EnableService(serviceId: serviceId); + final mutation = Options$Mutation$EnableService(variables: variables); + final response = await client.mutate$EnableService(mutation); + return GenericMutationResult( + success: response.parsedData?.enableService.success ?? false, + code: response.parsedData?.enableService.code ?? 0, + message: response.parsedData?.enableService.message, + ); + } catch (e) { + print(e); + return GenericMutationResult( + success: false, + code: 0, + message: e.toString(), + ); + } + } + + Future disableService(final String serviceId) async { + try { + final GraphQLClient client = await getClient(); + final variables = Variables$Mutation$DisableService(serviceId: serviceId); + final mutation = Options$Mutation$DisableService(variables: variables); + final response = await client.mutate$DisableService(mutation); + return GenericMutationResult( + success: response.parsedData?.disableService.success ?? false, + code: response.parsedData?.disableService.code ?? 0, + message: response.parsedData?.disableService.message, + ); + } catch (e) { + print(e); + return GenericMutationResult( + success: false, + code: 0, + message: e.toString(), + ); + } + } + + Future stopService(final String serviceId) async { + try { + final GraphQLClient client = await getClient(); + final variables = Variables$Mutation$StopService(serviceId: serviceId); + final mutation = Options$Mutation$StopService(variables: variables); + final response = await client.mutate$StopService(mutation); + return GenericMutationResult( + success: response.parsedData?.stopService.success ?? false, + code: response.parsedData?.stopService.code ?? 0, + message: response.parsedData?.stopService.message, + ); + } catch (e) { + print(e); + return GenericMutationResult( + success: false, + code: 0, + message: e.toString(), + ); + } + } + + Future startService(final String serviceId) async { + try { + final GraphQLClient client = await getClient(); + final variables = Variables$Mutation$StartService(serviceId: serviceId); + final mutation = Options$Mutation$StartService(variables: variables); + final response = await client.mutate$StartService(mutation); + return GenericMutationResult( + success: response.parsedData?.startService.success ?? false, + code: response.parsedData?.startService.code ?? 0, + message: response.parsedData?.startService.message, + ); + } catch (e) { + print(e); + return GenericMutationResult( + success: false, + code: 0, + message: e.toString(), + ); + } + } + + Future restartService(final String serviceId) async { + try { + final GraphQLClient client = await getClient(); + final variables = Variables$Mutation$RestartService(serviceId: serviceId); + final mutation = Options$Mutation$RestartService(variables: variables); + final response = await client.mutate$RestartService(mutation); + return GenericMutationResult( + success: response.parsedData?.restartService.success ?? false, + code: response.parsedData?.restartService.code ?? 0, + message: response.parsedData?.restartService.message, + ); + } catch (e) { + print(e); + return GenericMutationResult( + success: false, + code: 0, + message: e.toString(), + ); + } + } + + Future moveService( + final String serviceId, + final String destination, + ) async { + try { + final GraphQLClient client = await getClient(); + final variables = Variables$Mutation$MoveService( + input: Input$MoveServiceInput( + serviceId: serviceId, + location: destination, + ), + ); + final mutation = Options$Mutation$MoveService(variables: variables); + final response = await client.mutate$MoveService(mutation); + final jobJson = response.parsedData?.moveService.job?.toJson(); + return GenericJobMutationReturn( + success: response.parsedData?.moveService.success ?? false, + code: response.parsedData?.moveService.code ?? 0, + message: response.parsedData?.moveService.message, + job: jobJson != null ? ServerJob.fromJson(jobJson) : null, + ); + } catch (e) { + print(e); + return GenericJobMutationReturn( + success: false, + code: 0, + message: e.toString(), + job: null, + ); + } + } +} diff --git a/lib/logic/models/json/dns_records.dart b/lib/logic/models/json/dns_records.dart index cd4867c3..1bb385b5 100644 --- a/lib/logic/models/json/dns_records.dart +++ b/lib/logic/models/json/dns_records.dart @@ -1,4 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; +import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.dart'; part 'dns_records.g.dart'; @@ -13,6 +14,16 @@ class DnsRecord { this.proxied = false, }); + DnsRecord.fromGraphQL( + final Query$AllServices$services$allServices$dnsRecords record, + ) : this( + type: record.recordType, + name: record.name, + content: record.content, + ttl: record.ttl, + priority: record.priority ?? 10, + ); + final String type; final String? name; final String? content; diff --git a/lib/logic/models/service.dart b/lib/logic/models/service.dart new file mode 100644 index 00000000..c0f54224 --- /dev/null +++ b/lib/logic/models/service.dart @@ -0,0 +1,94 @@ +import 'dart:convert'; + +import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart'; +import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.dart'; +import 'package:selfprivacy/logic/models/disk_size.dart'; +import 'package:selfprivacy/logic/models/json/dns_records.dart'; + +class Service { + Service({ + required this.id, + required this.displayName, + required this.description, + required this.isEnabled, + required this.isRequired, + required this.status, + required this.storageUsage, + required this.svgIcon, + required this.dnsRecords, + this.url, + }); + + Service.fromGraphQL(final Query$AllServices$services$allServices service) + : this( + id: service.id, + displayName: service.displayName, + description: service.description, + isEnabled: service.isEnabled, + isRequired: service.isRequired, + status: ServiceStatus.fromGraphQL(service.status), + storageUsage: ServiceStorageUsage( + used: DiskSize(byte: int.parse(service.storageUsage.usedSpace)), + volume: service.storageUsage.volume?.name, + ), + // Decode the base64 encoded svg icon to text. + svgIcon: utf8.decode(base64.decode(service.svgIcon)), + dnsRecords: service.dnsRecords + ?.map((final record) => DnsRecord.fromGraphQL(record)) + .toList() ?? + [], + url: service.url, + ); + + final String id; + final String displayName; + final String description; + final bool isEnabled; + final bool isRequired; + final ServiceStatus status; + final ServiceStorageUsage storageUsage; + final String svgIcon; + final String? url; + final List dnsRecords; +} + +class ServiceStorageUsage { + ServiceStorageUsage({ + required this.used, + required this.volume, + }); + + final DiskSize used; + final String? volume; +} + +enum ServiceStatus { + activating, + active, + deactivating, + failed, + inactive, + off, + reloading; + + factory ServiceStatus.fromGraphQL(final Enum$ServiceStatusEnum graphQL) { + switch (graphQL) { + case Enum$ServiceStatusEnum.ACTIVATING: + return activating; + case Enum$ServiceStatusEnum.ACTIVE: + return active; + case Enum$ServiceStatusEnum.DEACTIVATING: + return deactivating; + case Enum$ServiceStatusEnum.FAILED: + return failed; + case Enum$ServiceStatusEnum.INACTIVE: + return inactive; + case Enum$ServiceStatusEnum.OFF: + return off; + case Enum$ServiceStatusEnum.RELOADING: + return reloading; + case Enum$ServiceStatusEnum.$unknown: + return inactive; + } + } +}