chore: Continue refactoring

- Rename APIGenericResult to GenericResult
- Wrap all provider functions results with GenericResult
- Move basic server commands and getters to business logic layer from API on Hetzner
pull/213/head
NaiJi ✨ 2023-02-13 18:13:32 +04:00
parent efe4f620ee
commit bad6926567
24 changed files with 634 additions and 489 deletions

View File

@ -1,5 +1,5 @@
class APIGenericResult<T> {
APIGenericResult({
class GenericResult<T> {
GenericResult({
required this.success,
required this.data,
this.message,

View File

@ -22,13 +22,13 @@ mixin JobsApi on ApiMap {
return jobsList;
}
Future<APIGenericResult<bool>> removeApiJob(final String uid) async {
Future<GenericResult<bool>> removeApiJob(final String uid) async {
try {
final GraphQLClient client = await getClient();
final variables = Variables$Mutation$RemoveJob(jobId: uid);
final mutation = Options$Mutation$RemoveJob(variables: variables);
final response = await client.mutate$RemoveJob(mutation);
return APIGenericResult(
return GenericResult(
data: response.parsedData?.removeJob.success ?? false,
success: true,
code: response.parsedData?.removeJob.code ?? 0,
@ -36,7 +36,7 @@ mixin JobsApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
code: 0,

View File

@ -1,6 +1,6 @@
import 'package:graphql/client.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/generic_result.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/api_map.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/disk_volumes.graphql.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.dart';
@ -24,7 +24,7 @@ import 'package:selfprivacy/logic/models/service.dart';
import 'package:selfprivacy/logic/models/ssh_settings.dart';
import 'package:selfprivacy/logic/models/system_settings.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
part 'jobs_api.dart';
part 'server_actions_api.dart';
@ -205,7 +205,7 @@ class ServerApi extends ApiMap
return settings;
}
Future<APIGenericResult<RecoveryKeyStatus?>> getRecoveryTokenStatus() async {
Future<GenericResult<RecoveryKeyStatus?>> getRecoveryTokenStatus() async {
RecoveryKeyStatus? key;
QueryResult<Query$RecoveryKey> response;
String? error;
@ -222,18 +222,18 @@ class ServerApi extends ApiMap
print(e);
}
return APIGenericResult<RecoveryKeyStatus?>(
return GenericResult<RecoveryKeyStatus?>(
success: error == null,
data: key,
message: error,
);
}
Future<APIGenericResult<String>> generateRecoveryToken(
Future<GenericResult<String>> generateRecoveryToken(
final DateTime? expirationDate,
final int? numberOfUses,
) async {
APIGenericResult<String> key;
GenericResult<String> key;
QueryResult<Mutation$GetNewRecoveryApiKey> response;
try {
@ -254,19 +254,19 @@ class ServerApi extends ApiMap
);
if (response.hasException) {
print(response.exception.toString());
key = APIGenericResult<String>(
key = GenericResult<String>(
success: false,
data: '',
message: response.exception.toString(),
);
}
key = APIGenericResult<String>(
key = GenericResult<String>(
success: true,
data: response.parsedData!.getNewRecoveryApiKey.key!,
);
} catch (e) {
print(e);
key = APIGenericResult<String>(
key = GenericResult<String>(
success: false,
data: '',
message: e.toString(),
@ -299,8 +299,8 @@ class ServerApi extends ApiMap
return records;
}
Future<APIGenericResult<List<ApiToken>>> getApiTokens() async {
APIGenericResult<List<ApiToken>> tokens;
Future<GenericResult<List<ApiToken>>> getApiTokens() async {
GenericResult<List<ApiToken>> tokens;
QueryResult<Query$GetApiTokens> response;
try {
@ -309,7 +309,7 @@ class ServerApi extends ApiMap
if (response.hasException) {
final message = response.exception.toString();
print(message);
tokens = APIGenericResult<List<ApiToken>>(
tokens = GenericResult<List<ApiToken>>(
success: false,
data: [],
message: message,
@ -323,13 +323,13 @@ class ServerApi extends ApiMap
ApiToken.fromGraphQL(device),
)
.toList();
tokens = APIGenericResult<List<ApiToken>>(
tokens = GenericResult<List<ApiToken>>(
success: true,
data: parsed,
);
} catch (e) {
print(e);
tokens = APIGenericResult<List<ApiToken>>(
tokens = GenericResult<List<ApiToken>>(
success: false,
data: [],
message: e.toString(),
@ -339,8 +339,8 @@ class ServerApi extends ApiMap
return tokens;
}
Future<APIGenericResult<void>> deleteApiToken(final String name) async {
APIGenericResult<void> returnable;
Future<GenericResult<void>> deleteApiToken(final String name) async {
GenericResult<void> returnable;
QueryResult<Mutation$DeleteDeviceApiToken> response;
try {
@ -357,19 +357,19 @@ class ServerApi extends ApiMap
);
if (response.hasException) {
print(response.exception.toString());
returnable = APIGenericResult<void>(
returnable = GenericResult<void>(
success: false,
data: null,
message: response.exception.toString(),
);
}
returnable = APIGenericResult<void>(
returnable = GenericResult<void>(
success: true,
data: null,
);
} catch (e) {
print(e);
returnable = APIGenericResult<void>(
returnable = GenericResult<void>(
success: false,
data: null,
message: e.toString(),
@ -379,8 +379,8 @@ class ServerApi extends ApiMap
return returnable;
}
Future<APIGenericResult<String>> createDeviceToken() async {
APIGenericResult<String> token;
Future<GenericResult<String>> createDeviceToken() async {
GenericResult<String> token;
QueryResult<Mutation$GetNewDeviceApiKey> response;
try {
@ -392,19 +392,19 @@ class ServerApi extends ApiMap
);
if (response.hasException) {
print(response.exception.toString());
token = APIGenericResult<String>(
token = GenericResult<String>(
success: false,
data: '',
message: response.exception.toString(),
);
}
token = APIGenericResult<String>(
token = GenericResult<String>(
success: true,
data: response.parsedData!.getNewDeviceApiKey.key!,
);
} catch (e) {
print(e);
token = APIGenericResult<String>(
token = GenericResult<String>(
success: false,
data: '',
message: e.toString(),
@ -416,10 +416,10 @@ class ServerApi extends ApiMap
Future<bool> isHttpServerWorking() async => (await getApiVersion()) != null;
Future<APIGenericResult<String>> authorizeDevice(
Future<GenericResult<String>> authorizeDevice(
final DeviceToken deviceToken,
) async {
APIGenericResult<String> token;
GenericResult<String> token;
QueryResult<Mutation$AuthorizeWithNewDeviceApiKey> response;
try {
@ -441,19 +441,19 @@ class ServerApi extends ApiMap
);
if (response.hasException) {
print(response.exception.toString());
token = APIGenericResult<String>(
token = GenericResult<String>(
success: false,
data: '',
message: response.exception.toString(),
);
}
token = APIGenericResult<String>(
token = GenericResult<String>(
success: true,
data: response.parsedData!.authorizeWithNewDeviceApiKey.token!,
);
} catch (e) {
print(e);
token = APIGenericResult<String>(
token = GenericResult<String>(
success: false,
data: '',
message: e.toString(),
@ -463,10 +463,10 @@ class ServerApi extends ApiMap
return token;
}
Future<APIGenericResult<String>> useRecoveryToken(
Future<GenericResult<String>> useRecoveryToken(
final DeviceToken deviceToken,
) async {
APIGenericResult<String> token;
GenericResult<String> token;
QueryResult<Mutation$UseRecoveryApiKey> response;
try {
@ -488,19 +488,19 @@ class ServerApi extends ApiMap
);
if (response.hasException) {
print(response.exception.toString());
token = APIGenericResult<String>(
token = GenericResult<String>(
success: false,
data: '',
message: response.exception.toString(),
);
}
token = APIGenericResult<String>(
token = GenericResult<String>(
success: true,
data: response.parsedData!.useRecoveryApiKey.token!,
);
} catch (e) {
print(e);
token = APIGenericResult<String>(
token = GenericResult<String>(
success: false,
data: '',
message: e.toString(),

View File

@ -20,7 +20,7 @@ mixin ServicesApi on ApiMap {
return services;
}
Future<APIGenericResult<bool>> enableService(
Future<GenericResult<bool>> enableService(
final String serviceId,
) async {
try {
@ -28,7 +28,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$EnableService(serviceId: serviceId);
final mutation = Options$Mutation$EnableService(variables: variables);
final response = await client.mutate$EnableService(mutation);
return APIGenericResult(
return GenericResult(
data: response.parsedData?.enableService.success ?? false,
success: true,
code: response.parsedData?.enableService.code ?? 0,
@ -36,7 +36,7 @@ mixin ServicesApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
code: 0,
@ -45,7 +45,7 @@ mixin ServicesApi on ApiMap {
}
}
Future<APIGenericResult<void>> disableService(
Future<GenericResult<void>> disableService(
final String serviceId,
) async {
try {
@ -53,7 +53,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$DisableService(serviceId: serviceId);
final mutation = Options$Mutation$DisableService(variables: variables);
final response = await client.mutate$DisableService(mutation);
return APIGenericResult(
return GenericResult(
data: null,
success: response.parsedData?.disableService.success ?? false,
code: response.parsedData?.disableService.code ?? 0,
@ -61,7 +61,7 @@ mixin ServicesApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
code: 0,
@ -70,7 +70,7 @@ mixin ServicesApi on ApiMap {
}
}
Future<APIGenericResult<bool>> stopService(
Future<GenericResult<bool>> stopService(
final String serviceId,
) async {
try {
@ -78,7 +78,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$StopService(serviceId: serviceId);
final mutation = Options$Mutation$StopService(variables: variables);
final response = await client.mutate$StopService(mutation);
return APIGenericResult(
return GenericResult(
data: response.parsedData?.stopService.success ?? false,
success: true,
code: response.parsedData?.stopService.code ?? 0,
@ -86,7 +86,7 @@ mixin ServicesApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
code: 0,
@ -95,13 +95,13 @@ mixin ServicesApi on ApiMap {
}
}
Future<APIGenericResult> startService(final String serviceId) async {
Future<GenericResult> 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 APIGenericResult(
return GenericResult(
data: null,
success: response.parsedData?.startService.success ?? false,
code: response.parsedData?.startService.code ?? 0,
@ -109,7 +109,7 @@ mixin ServicesApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
code: 0,
@ -118,7 +118,7 @@ mixin ServicesApi on ApiMap {
}
}
Future<APIGenericResult<bool>> restartService(
Future<GenericResult<bool>> restartService(
final String serviceId,
) async {
try {
@ -126,7 +126,7 @@ mixin ServicesApi on ApiMap {
final variables = Variables$Mutation$RestartService(serviceId: serviceId);
final mutation = Options$Mutation$RestartService(variables: variables);
final response = await client.mutate$RestartService(mutation);
return APIGenericResult(
return GenericResult(
data: response.parsedData?.restartService.success ?? false,
success: true,
code: response.parsedData?.restartService.code ?? 0,
@ -134,7 +134,7 @@ mixin ServicesApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
code: 0,
@ -143,7 +143,7 @@ mixin ServicesApi on ApiMap {
}
}
Future<APIGenericResult<ServerJob?>> moveService(
Future<GenericResult<ServerJob?>> moveService(
final String serviceId,
final String destination,
) async {
@ -158,7 +158,7 @@ mixin ServicesApi on ApiMap {
final mutation = Options$Mutation$MoveService(variables: variables);
final response = await client.mutate$MoveService(mutation);
final jobJson = response.parsedData?.moveService.job?.toJson();
return APIGenericResult(
return GenericResult(
success: true,
code: response.parsedData?.moveService.code ?? 0,
message: response.parsedData?.moveService.message,
@ -166,7 +166,7 @@ mixin ServicesApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
code: 0,
message: e.toString(),

View File

@ -45,7 +45,7 @@ mixin UsersApi on ApiMap {
return user;
}
Future<APIGenericResult<User?>> createUser(
Future<GenericResult<User?>> createUser(
final String username,
final String password,
) async {
@ -56,7 +56,7 @@ mixin UsersApi on ApiMap {
);
final mutation = Options$Mutation$CreateUser(variables: variables);
final response = await client.mutate$CreateUser(mutation);
return APIGenericResult(
return GenericResult(
success: true,
code: response.parsedData?.createUser.code ?? 500,
message: response.parsedData?.createUser.message,
@ -66,7 +66,7 @@ mixin UsersApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
code: 0,
message: e.toString(),
@ -75,7 +75,7 @@ mixin UsersApi on ApiMap {
}
}
Future<APIGenericResult<bool>> deleteUser(
Future<GenericResult<bool>> deleteUser(
final String username,
) async {
try {
@ -83,7 +83,7 @@ mixin UsersApi on ApiMap {
final variables = Variables$Mutation$DeleteUser(username: username);
final mutation = Options$Mutation$DeleteUser(variables: variables);
final response = await client.mutate$DeleteUser(mutation);
return APIGenericResult(
return GenericResult(
data: response.parsedData?.deleteUser.success ?? false,
success: true,
code: response.parsedData?.deleteUser.code ?? 500,
@ -91,7 +91,7 @@ mixin UsersApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
code: 500,
@ -100,7 +100,7 @@ mixin UsersApi on ApiMap {
}
}
Future<APIGenericResult<User?>> updateUser(
Future<GenericResult<User?>> updateUser(
final String username,
final String password,
) async {
@ -111,7 +111,7 @@ mixin UsersApi on ApiMap {
);
final mutation = Options$Mutation$UpdateUser(variables: variables);
final response = await client.mutate$UpdateUser(mutation);
return APIGenericResult(
return GenericResult(
success: true,
code: response.parsedData?.updateUser.code ?? 500,
message: response.parsedData?.updateUser.message,
@ -121,7 +121,7 @@ mixin UsersApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
code: 0,
@ -130,7 +130,7 @@ mixin UsersApi on ApiMap {
}
}
Future<APIGenericResult<User?>> addSshKey(
Future<GenericResult<User?>> addSshKey(
final String username,
final String sshKey,
) async {
@ -144,7 +144,7 @@ mixin UsersApi on ApiMap {
);
final mutation = Options$Mutation$AddSshKey(variables: variables);
final response = await client.mutate$AddSshKey(mutation);
return APIGenericResult(
return GenericResult(
success: true,
code: response.parsedData?.addSshKey.code ?? 500,
message: response.parsedData?.addSshKey.message,
@ -154,7 +154,7 @@ mixin UsersApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
code: 0,
@ -163,7 +163,7 @@ mixin UsersApi on ApiMap {
}
}
Future<APIGenericResult<User?>> removeSshKey(
Future<GenericResult<User?>> removeSshKey(
final String username,
final String sshKey,
) async {
@ -177,7 +177,7 @@ mixin UsersApi on ApiMap {
);
final mutation = Options$Mutation$RemoveSshKey(variables: variables);
final response = await client.mutate$RemoveSshKey(mutation);
return APIGenericResult(
return GenericResult(
success: response.parsedData?.removeSshKey.success ?? false,
code: response.parsedData?.removeSshKey.code ?? 500,
message: response.parsedData?.removeSshKey.message,
@ -187,7 +187,7 @@ mixin UsersApi on ApiMap {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
code: 0,

View File

@ -57,10 +57,10 @@ mixin VolumeApi on ApiMap {
}
}
Future<APIGenericResult<String?>> migrateToBinds(
Future<GenericResult<String?>> migrateToBinds(
final Map<String, String> serviceToDisk,
) async {
APIGenericResult<String?>? mutation;
GenericResult<String?>? mutation;
try {
final GraphQLClient client = await getClient();
@ -78,7 +78,7 @@ mixin VolumeApi on ApiMap {
await client.mutate$MigrateToBinds(
migrateMutation,
);
mutation = mutation = APIGenericResult(
mutation = mutation = GenericResult(
success: true,
code: result.parsedData!.migrateToBinds.code,
message: result.parsedData!.migrateToBinds.message,
@ -86,7 +86,7 @@ mixin VolumeApi on ApiMap {
);
} catch (e) {
print(e);
mutation = APIGenericResult(
mutation = GenericResult(
success: false,
code: 0,
message: e.toString(),

View File

@ -2,11 +2,11 @@ import 'dart:io';
import 'package:dio/dio.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
class BackblazeApiAuth {
BackblazeApiAuth({required this.authorizationToken, required this.apiUrl});
@ -74,7 +74,7 @@ class BackblazeApi extends ApiMap {
);
}
Future<APIGenericResult<bool>> isApiTokenValid(
Future<GenericResult<bool>> isApiTokenValid(
final String encodedApiKey,
) async {
final Dio client = await getClient();
@ -99,7 +99,7 @@ class BackblazeApi extends ApiMap {
}
} on DioError catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
message: e.toString(),
@ -108,7 +108,7 @@ class BackblazeApi extends ApiMap {
close(client);
}
return APIGenericResult(
return GenericResult(
data: isTokenValid,
success: true,
);

View File

@ -46,7 +46,7 @@ class CloudflareApi extends DnsProviderApi {
String rootAddress = 'https://api.cloudflare.com/client/v4';
@override
Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
Future<GenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false;
Response? response;
String message = '';
@ -70,7 +70,7 @@ class CloudflareApi extends DnsProviderApi {
}
if (response == null) {
return APIGenericResult(
return GenericResult(
data: isValid,
success: false,
message: message,
@ -85,7 +85,7 @@ class CloudflareApi extends DnsProviderApi {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
return GenericResult(
data: isValid,
success: true,
message: response.statusMessage,
@ -113,7 +113,7 @@ class CloudflareApi extends DnsProviderApi {
}
@override
Future<APIGenericResult<void>> removeSimilarRecords({
Future<GenericResult<void>> removeSimilarRecords({
required final ServerDomain domain,
final String? ip4,
}) async {
@ -139,7 +139,7 @@ class CloudflareApi extends DnsProviderApi {
await Future.wait(allDeleteFutures);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: null,
message: e.toString(),
@ -148,7 +148,7 @@ class CloudflareApi extends DnsProviderApi {
close(client);
}
return APIGenericResult(success: true, data: null);
return GenericResult(success: true, data: null);
}
@override
@ -272,7 +272,7 @@ class CloudflareApi extends DnsProviderApi {
}
@override
Future<APIGenericResult<void>> createMultipleDnsRecords({
Future<GenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain,
final String? ip4,
}) async {
@ -298,7 +298,7 @@ class CloudflareApi extends DnsProviderApi {
rethrow;
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: null,
message: e.toString(),
@ -307,7 +307,7 @@ class CloudflareApi extends DnsProviderApi {
close(client);
}
return APIGenericResult(success: true, data: null);
return GenericResult(success: true, data: null);
}
@override

View File

@ -46,7 +46,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
String rootAddress = 'https://api.digitalocean.com/v2';
@override
Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
Future<GenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false;
Response? response;
String message = '';
@ -70,7 +70,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
}
if (response == null) {
return APIGenericResult(
return GenericResult(
data: isValid,
success: false,
message: message,
@ -85,7 +85,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
return GenericResult(
data: isValid,
success: true,
message: response.statusMessage,
@ -97,7 +97,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
Future<String?> getZoneId(final String domain) async => domain;
@override
Future<APIGenericResult<void>> removeSimilarRecords({
Future<GenericResult<void>> removeSimilarRecords({
required final ServerDomain domain,
final String? ip4,
}) async {
@ -118,7 +118,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
await Future.wait(allDeleteFutures);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: null,
message: e.toString(),
@ -127,7 +127,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
close(client);
}
return APIGenericResult(success: true, data: null);
return GenericResult(success: true, data: null);
}
@override
@ -262,7 +262,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
}
@override
Future<APIGenericResult<void>> createMultipleDnsRecords({
Future<GenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain,
final String? ip4,
}) async {
@ -292,7 +292,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
rethrow;
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: null,
message: e.toString(),
@ -301,7 +301,7 @@ class DigitalOceanDnsApi extends DnsProviderApi {
close(client);
}
return APIGenericResult(success: true, data: null);
return GenericResult(success: true, data: null);
}
@override

View File

@ -1,10 +1,10 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/json/dns_records.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
export 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
class DomainNotFoundException implements Exception {
@ -21,11 +21,11 @@ abstract class DnsProviderApi extends ApiMap {
final String? ipAddress,
final String? dkimPublicKey,
});
Future<APIGenericResult<void>> removeSimilarRecords({
Future<GenericResult<void>> removeSimilarRecords({
required final ServerDomain domain,
final String? ip4,
});
Future<APIGenericResult<void>> createMultipleDnsRecords({
Future<GenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain,
final String? ip4,
});
@ -36,7 +36,7 @@ abstract class DnsProviderApi extends ApiMap {
Future<String?> getZoneId(final String domain);
Future<List<String>> domainList();
Future<APIGenericResult<bool>> isApiTokenValid(final String token);
Future<GenericResult<bool>> isApiTokenValid(final String token);
RegExp getApiTokenValidation();
List<DnsRecord> getProjectDnsRecords(

View File

@ -60,7 +60,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
String get displayProviderName => 'Digital Ocean';
@override
Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
Future<GenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false;
Response? response;
String message = '';
@ -84,7 +84,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
if (response == null) {
return APIGenericResult(
return GenericResult(
data: isValid,
success: false,
message: message,
@ -99,7 +99,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
return GenericResult(
data: isValid,
success: true,
message: response.statusMessage,
@ -115,7 +115,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
);
@override
Future<APIGenericResult<ServerVolume?>> createVolume() async {
Future<GenericResult<ServerVolume?>> createVolume() async {
ServerVolume? volume;
Response? createVolumeResponse;
@ -147,7 +147,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
message: e.toString(),
@ -156,7 +156,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
client.close();
}
return APIGenericResult(
return GenericResult(
data: volume,
success: true,
code: createVolumeResponse.statusCode,
@ -230,7 +230,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
@override
Future<APIGenericResult<bool>> attachVolume(
Future<GenericResult<bool>> attachVolume(
final ServerVolume volume,
final int serverId,
) async {
@ -252,7 +252,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
attachVolumeResponse.data['action']['status'].toString() != 'error';
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
message: e.toString(),
@ -261,7 +261,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(
return GenericResult(
data: success,
success: true,
code: attachVolumeResponse.statusCode,
@ -327,7 +327,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
@override
Future<APIGenericResult<ServerHostingDetails?>> createServer({
Future<GenericResult<ServerHostingDetails?>> createServer({
required final String dnsApiToken,
required final User rootUser,
required final String domainName,
@ -399,7 +399,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: null,
message: e.toString(),
@ -408,7 +408,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(
return GenericResult(
data: serverDetails,
success: true,
code: serverCreateResponse.statusCode,
@ -417,7 +417,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
@override
Future<APIGenericResult<bool>> deleteServer({
Future<GenericResult<bool>> deleteServer({
required final String domainName,
}) async {
final Dio client = await getClient();
@ -431,7 +431,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
message: e.toString(),
@ -446,7 +446,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: false,
success: false,
message: e.toString(),
@ -464,7 +464,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
await Future.wait(laterFutures);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: false,
message: e.toString(),
@ -473,7 +473,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(
return GenericResult(
success: true,
data: true,
);
@ -762,7 +762,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
@override
Future<APIGenericResult<List<ServerProviderLocation>>>
Future<GenericResult<List<ServerProviderLocation>>>
getAvailableLocations() async {
List<ServerProviderLocation> locations = [];
@ -784,7 +784,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
.toList();
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: [],
success: false,
message: e.toString(),
@ -793,11 +793,11 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(data: locations, success: true);
return GenericResult(data: locations, success: true);
}
@override
Future<APIGenericResult<List<ServerType>>> getServerTypesByLocation({
Future<GenericResult<List<ServerType>>> getAvailableServerTypes({
required final ServerProviderLocation location,
}) async {
final List<ServerType> types = [];
@ -830,7 +830,7 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
}
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: [],
success: false,
message: e.toString(),
@ -839,17 +839,17 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(data: types, success: true);
return GenericResult(data: types, success: true);
}
@override
Future<APIGenericResult<void>> createReverseDns({
Future<GenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails,
required final ServerDomain domain,
}) async {
/// TODO remove from provider interface
const bool success = true;
return APIGenericResult(success: success, data: null);
return GenericResult(success: success, data: null);
}
@override

View File

@ -17,7 +17,6 @@ import 'package:selfprivacy/logic/models/price.dart';
import 'package:selfprivacy/logic/models/server_basic_info.dart';
import 'package:selfprivacy/logic/models/server_metadata.dart';
import 'package:selfprivacy/logic/models/server_provider_location.dart';
import 'package:selfprivacy/logic/models/server_type.dart';
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
import 'package:selfprivacy/utils/network_utils.dart';
import 'package:selfprivacy/utils/password_generator.dart';
@ -60,8 +59,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
@override
String get displayProviderName => 'Hetzner';
@override
Future<APIGenericResult<bool>> isApiTokenValid(final String token) async {
Future<GenericResult<bool>> isApiTokenValid(final String token) async {
bool isValid = false;
Response? response;
String message = '';
@ -85,7 +83,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
}
if (response == null) {
return APIGenericResult(
return GenericResult(
data: isValid,
success: false,
message: message,
@ -100,21 +98,19 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
throw Exception('code: ${response.statusCode}');
}
return APIGenericResult(
return GenericResult(
data: isValid,
success: true,
message: response.statusMessage,
);
}
@override
ProviderApiTokenValidation getApiTokenValidation() =>
ProviderApiTokenValidation(
regexp: RegExp(r'\s+|[-!$%^&*()@+|~=`{}\[\]:<>?,.\/]'),
length: 64,
);
@override
Future<Price?> getPricePerGb() async {
double? price;
@ -140,8 +136,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
@override
Future<APIGenericResult<ServerVolume?>> createVolume() async {
Future<GenericResult<ServerVolume?>> createVolume() async {
ServerVolume? volume;
Response? createVolumeResponse;
@ -172,7 +167,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: null,
success: false,
message: e.toString(),
@ -181,7 +176,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
client.close();
}
return APIGenericResult(
return GenericResult(
data: volume,
success: true,
code: createVolumeResponse.statusCode,
@ -189,7 +184,6 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
@override
Future<List<ServerVolume>> getVolumes({final String? status}) async {
final List<ServerVolume> volumes = [];
@ -257,7 +251,6 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
return volume;
}
@override
Future<void> deleteVolume(final ServerVolume volume) async {
final Dio client = await getClient();
try {
@ -269,8 +262,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
}
}
@override
Future<APIGenericResult<bool>> attachVolume(
Future<GenericResult<bool>> attachVolume(
final ServerVolume volume,
final int serverId,
) async {
@ -294,7 +286,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
client.close();
}
return APIGenericResult(
return GenericResult(
data: success,
success: true,
code: attachVolumeResponse?.statusCode,
@ -302,7 +294,6 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
@override
Future<bool> detachVolume(final ServerVolume volume) async {
bool success = false;
@ -323,7 +314,6 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
return success;
}
@override
Future<bool> resizeVolume(
final ServerVolume volume,
final DiskSize size,
@ -350,19 +340,17 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
return success;
}
@override
Future<APIGenericResult<ServerHostingDetails?>> createServer({
Future<GenericResult<ServerHostingDetails?>> createServer({
required final String dnsApiToken,
required final User rootUser,
required final String domainName,
required final String serverType,
required final DnsProviderType dnsProvider,
}) async {
final APIGenericResult<ServerVolume?> newVolumeResponse =
await createVolume();
final GenericResult<ServerVolume?> newVolumeResponse = await createVolume();
if (!newVolumeResponse.success || newVolumeResponse.data == null) {
return APIGenericResult(
return GenericResult(
data: null,
success: false,
message: newVolumeResponse.message,
@ -379,7 +367,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
Future<APIGenericResult<ServerHostingDetails?>> createServerWithVolume({
Future<GenericResult<ServerHostingDetails?>> createServerWithVolume({
required final String dnsApiToken,
required final User rootUser,
required final String domainName,
@ -457,7 +445,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
apiResultMessage = 'uniqueness_error';
}
return APIGenericResult(
return GenericResult(
data: serverDetails,
success: success && hetznerError == null,
code: serverCreateResponse?.statusCode ??
@ -466,8 +454,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
);
}
@override
Future<APIGenericResult<bool>> deleteServer({
Future<GenericResult<bool>> deleteServer({
required final String domainName,
}) async {
final Dio client = await getClient();
@ -494,7 +481,7 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
await Future.wait(laterFutures);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: false,
message: e.toString(),
@ -503,45 +490,55 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(
return GenericResult(
success: true,
data: true,
);
}
@override
Future<ServerHostingDetails> restart() async {
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
Future<GenericResult<void>> restart(final int serverId) async {
final Dio client = await getClient();
try {
await client.post('/servers/${server.id}/actions/reset');
await client.post('/servers/$serverId/actions/reset');
} catch (e) {
print(e);
return GenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally {
close(client);
}
return server.copyWith(startTime: DateTime.now());
return GenericResult(
success: true,
data: null,
);
}
@override
Future<ServerHostingDetails> powerOn() async {
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
Future<GenericResult<void>> powerOn(final int serverId) async {
final Dio client = await getClient();
try {
await client.post('/servers/${server.id}/actions/poweron');
await client.post('/servers/$serverId/actions/poweron');
} catch (e) {
print(e);
return GenericResult(
success: false,
data: null,
message: e.toString(),
);
} finally {
close(client);
}
return server.copyWith(startTime: DateTime.now());
return GenericResult(
success: true,
data: null,
);
}
Future<Map<String, dynamic>> requestRawMetrics(
Future<GenericResult<Map<String, dynamic>>> getMetrics(
final int serverId,
final DateTime start,
final DateTime end,
@ -562,127 +559,20 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
metrics = res.data['metrics'];
} catch (e) {
print(e);
return GenericResult(
success: false,
data: {},
message: e.toString(),
);
} finally {
close(client);
}
return metrics;
return GenericResult(data: metrics, success: true);
}
List<TimeSeriesData> serializeTimeSeries(
final Map<String, dynamic> json,
final String type,
) {
final List list = json['time_series'][type]['values'];
return list
.map((final el) => TimeSeriesData(el[0], double.parse(el[1])))
.toList();
}
@override
Future<ServerMetrics?> getMetrics(
final int serverId,
final DateTime start,
final DateTime end,
) async {
ServerMetrics? metrics;
final Map<String, dynamic> rawCpuMetrics = await requestRawMetrics(
serverId,
start,
end,
'cpu',
);
final Map<String, dynamic> rawNetworkMetrics = await requestRawMetrics(
serverId,
start,
end,
'network',
);
if (rawNetworkMetrics.isEmpty || rawCpuMetrics.isEmpty) {
return metrics;
}
metrics = ServerMetrics(
cpu: serializeTimeSeries(
rawCpuMetrics,
'cpu',
),
bandwidthIn: serializeTimeSeries(
rawNetworkMetrics,
'network.0.bandwidth.in',
),
bandwidthOut: serializeTimeSeries(
rawNetworkMetrics,
'network.0.bandwidth.out',
),
end: end,
start: start,
stepsInSecond: rawCpuMetrics['step'],
);
return metrics;
}
@override
Future<List<ServerMetadataEntity>> getMetadata(final int serverId) async {
List<ServerMetadataEntity> metadata = [];
final Dio client = await getClient();
try {
final Response response = await client.get('/servers/$serverId');
final hetznerInfo = HetznerServerInfo.fromJson(response.data!['server']);
metadata = [
ServerMetadataEntity(
type: MetadataType.id,
name: 'server.server_id'.tr(),
value: hetznerInfo.id.toString(),
),
ServerMetadataEntity(
type: MetadataType.status,
name: 'server.status'.tr(),
value: hetznerInfo.status.toString().split('.')[1].capitalize(),
),
ServerMetadataEntity(
type: MetadataType.cpu,
name: 'server.cpu'.tr(),
value: 'server.core_count'.plural(hetznerInfo.serverType.cores),
),
ServerMetadataEntity(
type: MetadataType.ram,
name: 'server.ram'.tr(),
value: '${hetznerInfo.serverType.memory.toString()} GB',
),
ServerMetadataEntity(
type: MetadataType.cost,
name: 'server.monthly_cost'.tr(),
value: hetznerInfo.serverType.prices[1].monthly.toStringAsFixed(2),
),
ServerMetadataEntity(
type: MetadataType.location,
name: 'server.location'.tr(),
value:
'${hetznerInfo.location.city}, ${hetznerInfo.location.country}',
),
ServerMetadataEntity(
type: MetadataType.other,
name: 'server.provider'.tr(),
value: displayProviderName,
),
];
} catch (e) {
print(e);
} finally {
close(client);
}
return metadata;
}
@override
Future<List<ServerBasicInfo>> getServers() async {
List<ServerBasicInfo> servers = [];
Future<GenericResult<List<HetznerServerInfo>>> getServers() async {
List<HetznerServerInfo> servers = [];
final Dio client = await getClient();
try {
@ -691,53 +581,22 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
.map<HetznerServerInfo>(
(final e) => HetznerServerInfo.fromJson(e),
)
.toList()
.where(
(final server) => server.publicNet.ipv4 != null,
)
.map<ServerBasicInfo>(
(final server) => ServerBasicInfo(
id: server.id,
name: server.name,
ip: server.publicNet.ipv4.ip,
reverseDns: server.publicNet.ipv4.reverseDns,
created: server.created,
),
)
.toList();
} catch (e) {
print(e);
return GenericResult(
success: false,
data: [],
message: e.toString(),
);
} finally {
close(client);
}
print(servers);
return servers;
return GenericResult(data: servers, success: true);
}
String? getEmojiFlag(final String query) {
String? emoji;
switch (query.toLowerCase()) {
case 'de':
emoji = '🇩🇪';
break;
case 'fi':
emoji = '🇫🇮';
break;
case 'us':
emoji = '🇺🇸';
break;
}
return emoji;
}
@override
Future<APIGenericResult<List<ServerProviderLocation>>>
getAvailableLocations() async {
Future<GenericResult<List>> getAvailableLocations() async {
List<ServerProviderLocation> locations = [];
final Dio client = await getClient();
@ -746,19 +605,10 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
'/locations',
);
locations = response.data!['locations']
.map<ServerProviderLocation>(
(final location) => ServerProviderLocation(
title: location['city'],
description: location['description'],
flag: getEmojiFlag(location['country']),
identifier: location['name'],
),
)
.toList();
locations = response.data!['locations'];
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: [],
message: e.toString(),
@ -767,44 +617,21 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(success: true, data: locations);
return GenericResult(success: true, data: locations);
}
@override
Future<APIGenericResult<List<ServerType>>> getServerTypesByLocation({
required final ServerProviderLocation location,
}) async {
final List<ServerType> types = [];
Future<GenericResult<List>> getAvailableServerTypes() async {
List types = [];
final Dio client = await getClient();
try {
final Response response = await client.get(
'/server_types',
);
final rawTypes = response.data!['server_types'];
for (final rawType in rawTypes) {
for (final rawPrice in rawType['prices']) {
if (rawPrice['location'].toString() == location.identifier) {
types.add(
ServerType(
title: rawType['description'],
identifier: rawType['name'],
ram: rawType['memory'],
cores: rawType['cores'],
disk: DiskSize(byte: rawType['disk'] * 1024 * 1024 * 1024),
price: Price(
value: double.parse(rawPrice['price_monthly']['gross']),
currency: 'EUR',
),
location: location,
),
);
}
}
}
types = response.data!['server_types'];
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
data: [],
success: false,
message: e.toString(),
@ -813,26 +640,26 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(data: types, success: true);
return GenericResult(data: types, success: true);
}
@override
Future<APIGenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails,
required final ServerDomain domain,
Future<GenericResult<void>> createReverseDns({
required final int serverId,
required final String ip4,
required final String dnsPtr,
}) async {
final Dio client = await getClient();
try {
await client.post(
'/servers/${serverDetails.id}/actions/change_dns_ptr',
'/servers/$serverId/actions/change_dns_ptr',
data: {
'ip': serverDetails.ip4,
'dns_ptr': domain.domainName,
'ip': ip4,
'dns_ptr': dnsPtr,
},
);
} catch (e) {
print(e);
return APIGenericResult(
return GenericResult(
success: false,
data: null,
message: e.toString(),
@ -841,6 +668,6 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
close(client);
}
return APIGenericResult(success: true, data: null);
return GenericResult(success: true, data: null);
}
}

View File

@ -1,15 +1,6 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/hive/user.dart';
import 'package:selfprivacy/logic/models/metrics.dart';
import 'package:selfprivacy/logic/models/server_basic_info.dart';
import 'package:selfprivacy/logic/models/server_metadata.dart';
import 'package:selfprivacy/logic/models/server_provider_location.dart';
import 'package:selfprivacy/logic/models/server_type.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
class ProviderApiTokenValidation {
ProviderApiTokenValidation({
@ -21,40 +12,6 @@ class ProviderApiTokenValidation {
}
abstract class ServerProviderApi extends ApiMap {
Future<List<ServerBasicInfo>> getServers();
Future<APIGenericResult<List<ServerProviderLocation>>>
getAvailableLocations();
Future<APIGenericResult<List<ServerType>>> getServerTypesByLocation({
required final ServerProviderLocation location,
});
Future<ServerHostingDetails> restart();
Future<ServerHostingDetails> powerOn();
Future<APIGenericResult<bool>> deleteServer({
required final String domainName,
});
Future<APIGenericResult<ServerHostingDetails?>> createServer({
required final String dnsApiToken,
required final User rootUser,
required final String domainName,
required final String serverType,
required final DnsProviderType dnsProvider,
});
Future<APIGenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails,
required final ServerDomain domain,
});
Future<APIGenericResult<bool>> isApiTokenValid(final String token);
ProviderApiTokenValidation getApiTokenValidation();
Future<List<ServerMetadataEntity>> getMetadata(final int serverId);
Future<ServerMetrics?> getMetrics(
final int serverId,
final DateTime start,
final DateTime end,
);
String dnsProviderToInfectName(final DnsProviderType dnsProvider) {
String dnsProviderType;
switch (dnsProvider) {

View File

@ -1,20 +1,5 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/price.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
mixin VolumeProviderApi on ApiMap {
Future<APIGenericResult<ServerVolume?>> createVolume();
Future<List<ServerVolume>> getVolumes({final String? status});
Future<APIGenericResult<bool>> attachVolume(
final ServerVolume volume,
final int serverId,
);
Future<bool> detachVolume(final ServerVolume volume);
Future<bool> resizeVolume(final ServerVolume volume, final DiskSize size);
Future<void> deleteVolume(final ServerVolume volume);
Future<Price?> getPricePerGb();
}
mixin VolumeProviderApi on ApiMap {}

View File

@ -35,7 +35,7 @@ class ApiDevicesCubit
}
Future<List<ApiToken>?> _getApiTokens() async {
final APIGenericResult<List<ApiToken>> response = await api.getApiTokens();
final GenericResult<List<ApiToken>> response = await api.getApiTokens();
if (response.success) {
return response.data;
} else {
@ -44,8 +44,7 @@ class ApiDevicesCubit
}
Future<void> deleteDevice(final ApiToken device) async {
final APIGenericResult<void> response =
await api.deleteApiToken(device.name);
final GenericResult<void> response = await api.deleteApiToken(device.name);
if (response.success) {
emit(
ApiDevicesState(
@ -60,7 +59,7 @@ class ApiDevicesCubit
}
Future<String?> getNewDeviceKey() async {
final APIGenericResult<String> response = await api.createDeviceToken();
final GenericResult<String> response = await api.createDeviceToken();
if (response.success) {
return response.data;
} else {

View File

@ -40,7 +40,7 @@ class BackblazeFormCubit extends FormCubit {
@override
FutureOr<bool> asyncValidation() async {
late APIGenericResult<bool> backblazeResponse;
late GenericResult<bool> backblazeResponse;
final BackblazeApi apiClient = BackblazeApi(isWithToken: false);
try {
@ -51,7 +51,7 @@ class BackblazeFormCubit extends FormCubit {
backblazeResponse = await apiClient.isApiTokenValid(encodedApiKey);
} catch (e) {
addError(e);
backblazeResponse = APIGenericResult(
backblazeResponse = GenericResult(
success: false,
data: false,
message: e.toString(),

View File

@ -32,7 +32,7 @@ class RecoveryKeyCubit
}
Future<RecoveryKeyStatus?> _getRecoveryKeyStatus() async {
final APIGenericResult<RecoveryKeyStatus?> response =
final GenericResult<RecoveryKeyStatus?> response =
await api.getRecoveryTokenStatus();
if (response.success) {
return response.data;
@ -57,7 +57,7 @@ class RecoveryKeyCubit
final DateTime? expirationDate,
final int? numberOfUses,
}) async {
final APIGenericResult<String> response =
final GenericResult<String> response =
await api.generateRecoveryToken(expirationDate, numberOfUses);
if (response.success) {
refresh();

View File

@ -77,8 +77,8 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
Future<bool?> isServerProviderApiTokenValid(
final String providerToken,
) async {
final APIGenericResult<bool> apiResponse =
await ProvidersController.currentServerProvider!.isApiTokenValid(
final GenericResult<bool> apiResponse =
await ProvidersController.currentServerProvider!.tryInitApiByToken(
providerToken,
);
@ -95,7 +95,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
Future<bool?> isDnsProviderApiTokenValid(
final String providerToken,
) async {
final APIGenericResult<bool> apiResponse =
final GenericResult<bool> apiResponse =
await ApiController.currentDnsProviderApiFactory!
.getDnsProvider(
settings: const DnsProviderApiSettings(isWithToken: false),
@ -117,7 +117,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
return [];
}
final APIGenericResult apiResponse = await ProvidersController
final GenericResult apiResponse = await ProvidersController
.currentServerProvider!
.getAvailableLocations();
@ -137,7 +137,7 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
return [];
}
final APIGenericResult apiResult = await ProvidersController
final GenericResult apiResult = await ProvidersController
.currentServerProvider!
.getServerTypes(location: location);
@ -173,21 +173,8 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
void setServerType(final ServerType serverType) async {
await repository.saveServerType(serverType);
ApiController.initServerProviderApiFactory(
ServerProviderSettings(
provider: getIt<ApiConfigModel>().serverProvider!,
location: serverType.location.identifier,
),
);
// All server providers support volumes for now,
// so it's safe to initialize.
ApiController.initVolumeProviderApiFactory(
ServerProviderSettings(
provider: getIt<ApiConfigModel>().serverProvider!,
location: serverType.location.identifier,
),
);
await ProvidersController.currentServerProvider!
.trySetServerType(serverType);
emit(
(state as ServerInstallationNotFinished).copyWith(

View File

@ -259,7 +259,7 @@ class ServerInstallationRepository {
actionButtonOnPressed: () async {
ServerHostingDetails? serverDetails;
try {
final APIGenericResult createResult = await api.createServer(
final GenericResult createResult = await api.createServer(
dnsProvider: getIt<ApiConfigModel>().dnsProvider!,
dnsApiToken: cloudFlareKey,
rootUser: rootUser,
@ -283,7 +283,7 @@ class ServerInstallationRepository {
}
try {
final APIGenericResult<ServerHostingDetails?> createServerResult =
final GenericResult<ServerHostingDetails?> createServerResult =
await api.createServer(
dnsProvider: getIt<ApiConfigModel>().dnsProvider!,
dnsApiToken: cloudFlareKey,
@ -309,7 +309,7 @@ class ServerInstallationRepository {
ServerHostingDetails? serverDetails;
try {
final APIGenericResult createResult = await api.createServer(
final GenericResult createResult = await api.createServer(
dnsProvider: getIt<ApiConfigModel>().dnsProvider!,
dnsApiToken: cloudFlareKey,
rootUser: rootUser,
@ -366,7 +366,7 @@ class ServerInstallationRepository {
);
}
final APIGenericResult removingResult =
final GenericResult removingResult =
await dnsProviderApi.removeSimilarRecords(
ip4: serverDetails.ip4,
domain: domain,
@ -380,7 +380,7 @@ class ServerInstallationRepository {
bool createdSuccessfully = false;
String errorMessage = 'domain.error'.tr();
try {
final APIGenericResult createResult =
final GenericResult createResult =
await dnsProviderApi.createMultipleDnsRecords(
ip4: serverDetails.ip4,
domain: domain,
@ -397,8 +397,7 @@ class ServerInstallationRepository {
return false;
}
final APIGenericResult createReverseResult =
await serverApi.createReverseDns(
final GenericResult createReverseResult = await serverApi.createReverseDns(
serverDetails: serverDetails,
domain: domain,
);
@ -520,7 +519,7 @@ class ServerInstallationRepository {
overrideDomain: serverDomain.domainName,
);
final String serverIp = await getServerIpFromDomain(serverDomain);
final APIGenericResult<String> result = await serverApi.authorizeDevice(
final GenericResult<String> result = await serverApi.authorizeDevice(
DeviceToken(device: await getDeviceName(), token: newDeviceKey),
);
@ -557,7 +556,7 @@ class ServerInstallationRepository {
overrideDomain: serverDomain.domainName,
);
final String serverIp = await getServerIpFromDomain(serverDomain);
final APIGenericResult<String> result = await serverApi.useRecoveryToken(
final GenericResult<String> result = await serverApi.useRecoveryToken(
DeviceToken(device: await getDeviceName(), token: recoveryKey),
);
@ -618,9 +617,9 @@ class ServerInstallationRepository {
);
}
}
final APIGenericResult<String> deviceAuthKey =
final GenericResult<String> deviceAuthKey =
await serverApi.createDeviceToken();
final APIGenericResult<String> result = await serverApi.authorizeDevice(
final GenericResult<String> result = await serverApi.authorizeDevice(
DeviceToken(device: await getDeviceName(), token: deviceAuthKey.data),
);
@ -771,7 +770,7 @@ class ServerInstallationRepository {
}
Future<bool> deleteServer(final ServerDomain serverDomain) async {
final APIGenericResult<bool> deletionResult = await ApiController
final GenericResult<bool> deletionResult = await ApiController
.currentServerProviderApiFactory!
.getServerProvider()
.deleteServer(
@ -797,7 +796,7 @@ class ServerInstallationRepository {
await box.put(BNames.isLoading, false);
await box.put(BNames.serverDetails, null);
final APIGenericResult<void> removalResult = await ApiController
final GenericResult<void> removalResult = await ApiController
.currentDnsProviderApiFactory!
.getDnsProvider()
.removeSimilarRecords(domain: serverDomain);

View File

@ -78,7 +78,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
return;
}
// If API returned error, do nothing
final APIGenericResult<User?> result =
final GenericResult<User?> result =
await api.createUser(user.login, password);
if (result.data == null) {
getIt<NavigationService>()
@ -101,7 +101,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
return;
}
final List<User> loadedUsers = List<User>.from(state.users);
final APIGenericResult result = await api.deleteUser(user.login);
final GenericResult result = await api.deleteUser(user.login);
if (result.success && result.data) {
loadedUsers.removeWhere((final User u) => u.login == user.login);
await box.clear();
@ -128,7 +128,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
.showSnackBar('users.could_not_change_password'.tr());
return;
}
final APIGenericResult<User?> result =
final GenericResult<User?> result =
await api.updateUser(user.login, newPassword);
if (result.data == null) {
getIt<NavigationService>().showSnackBar(
@ -138,7 +138,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
}
Future<void> addSshKey(final User user, final String publicKey) async {
final APIGenericResult<User?> result =
final GenericResult<User?> result =
await api.addSshKey(user.login, publicKey);
if (result.data != null) {
final User updatedUser = result.data!;
@ -157,7 +157,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
}
Future<void> deleteSshKey(final User user, final String publicKey) async {
final APIGenericResult<User?> result =
final GenericResult<User?> result =
await api.removeSshKey(user.login, publicKey);
if (result.data != null) {
final User updatedUser = result.data!;

View File

@ -19,11 +19,11 @@ enum MetadataType {
class ServerMetadataEntity {
ServerMetadataEntity({
required this.name,
required this.trId,
required this.value,
this.type = MetadataType.other,
});
final MetadataType type;
final String name;
final String trId;
final String value;
}

View File

@ -1,12 +1,16 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/generic_result.dart';
import 'package:selfprivacy/logic/models/server_provider_location.dart';
import 'package:selfprivacy/logic/models/server_type.dart';
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
abstract class ServerProvider {
Future<APIGenericResult<bool>> isApiTokenValid(final String apiToken);
Future<APIGenericResult<List<ServerProviderLocation>>>
getAvailableLocations();
Future<APIGenericResult<List<ServerType>>> getServerTypes({
Future<GenericResult<bool>> trySetServerType(final ServerType type);
Future<GenericResult<bool>> tryInitApiByToken(final String token);
Future<GenericResult<List<ServerProviderLocation>>> getAvailableLocations();
Future<GenericResult<List<ServerType>>> getServerTypes({
required final ServerProviderLocation location,
});
GenericResult<bool> get success => GenericResult(success: true, data: true);
}

View File

@ -1,3 +1,390 @@
import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/json/hetzner_server_info.dart';
import 'package:selfprivacy/logic/models/metrics.dart';
import 'package:selfprivacy/logic/models/price.dart';
import 'package:selfprivacy/logic/models/server_basic_info.dart';
import 'package:selfprivacy/logic/models/server_metadata.dart';
import 'package:selfprivacy/logic/models/server_provider_location.dart';
import 'package:selfprivacy/logic/models/server_type.dart';
import 'package:selfprivacy/logic/providers/server_provider.dart';
import 'package:selfprivacy/utils/extensions/string_extensions.dart';
class HetznerServerProvider extends ServerProvider {}
class ApiAdapter {
ApiAdapter({final String? region, final bool isWithToken = true})
: _api = HetznerApi(
region: region,
isWithToken: isWithToken,
);
HetznerApi api({final bool getInitialized = true}) => getInitialized
? _api
: HetznerApi(
region: _api.region,
isWithToken: false,
);
final HetznerApi _api;
}
class HetznerServerProvider extends ServerProvider {
HetznerServerProvider() : _adapter = ApiAdapter();
HetznerServerProvider.load(
final ServerType serverType,
final bool isAuthotized,
) : _adapter = ApiAdapter(
isWithToken: isAuthotized,
region: serverType.location.identifier,
);
ApiAdapter _adapter;
@override
Future<GenericResult<bool>> trySetServerType(final ServerType type) async {
final bool apiInitialized = _adapter.api().isWithToken;
if (!apiInitialized) {
return GenericResult(
success: true,
data: false,
message: 'Not authorized!',
);
}
_adapter = ApiAdapter(
isWithToken: true,
region: type.location.identifier,
);
return success;
}
@override
Future<GenericResult<bool>> tryInitApiByToken(final String token) async {
final api = _adapter.api(getInitialized: false);
final result = await api.isApiTokenValid(token);
if (!result.data || !result.success) {
return result;
}
_adapter = ApiAdapter(region: api.region, isWithToken: true);
return result;
}
String? getEmojiFlag(final String query) {
String? emoji;
switch (query.toLowerCase()) {
case 'de':
emoji = '🇩🇪';
break;
case 'fi':
emoji = '🇫🇮';
break;
case 'us':
emoji = '🇺🇸';
break;
}
return emoji;
}
@override
Future<GenericResult<List<ServerProviderLocation>>>
getAvailableLocations() async {
final List<ServerProviderLocation> locations = [];
final result = await _adapter.api().getAvailableLocations();
if (result.data.isEmpty || !result.success) {
return GenericResult(
success: result.success,
data: locations,
code: result.code,
message: result.message,
);
}
final List rawLocations = result.data;
for (final rawLocation in rawLocations) {
ServerProviderLocation? location;
try {
location = ServerProviderLocation(
title: rawLocation['city'],
description: rawLocation['description'],
flag: getEmojiFlag(rawLocation['country']),
identifier: rawLocation['name'],
);
} catch (e) {
continue;
}
locations.add(location);
}
return GenericResult(success: true, data: locations);
}
@override
Future<GenericResult<List<ServerType>>> getServerTypes({
required final ServerProviderLocation location,
}) async {
final List<ServerType> types = [];
final result = await _adapter.api().getAvailableServerTypes();
if (result.data.isEmpty || !result.success) {
return GenericResult(
success: result.success,
data: types,
code: result.code,
message: result.message,
);
}
final List rawTypes = result.data;
for (final rawType in rawTypes) {
for (final rawPrice in rawType['prices']) {
if (rawPrice['location'].toString() == location.identifier) {
types.add(
ServerType(
title: rawType['description'],
identifier: rawType['name'],
ram: rawType['memory'],
cores: rawType['cores'],
disk: DiskSize(byte: rawType['disk'] * 1024 * 1024 * 1024),
price: Price(
value: double.parse(rawPrice['price_monthly']['gross']),
currency: 'EUR',
),
location: location,
),
);
}
}
}
return GenericResult(success: true, data: types);
}
Future<GenericResult<void>> createReverseDns({
required final ServerHostingDetails serverDetails,
required final ServerDomain domain,
}) async =>
_adapter.api().createReverseDns(
serverId: serverDetails.id,
ip4: serverDetails.ip4,
dnsPtr: domain.domainName,
);
Future<GenericResult<List<ServerBasicInfo>>> getServers() async {
final List<ServerBasicInfo> servers = [];
final result = await _adapter.api().getServers();
if (result.data.isEmpty || !result.success) {
return GenericResult(
success: result.success,
data: servers,
code: result.code,
message: result.message,
);
}
final List<HetznerServerInfo> hetznerServers = result.data;
for (final hetznerServer in hetznerServers) {
if (hetznerServer.publicNet.ipv4 == null) {
continue;
}
ServerBasicInfo? server;
try {
server = ServerBasicInfo(
id: hetznerServer.id,
name: hetznerServer.name,
ip: hetznerServer.publicNet.ipv4!.ip,
reverseDns: hetznerServer.publicNet.ipv4!.reverseDns,
created: hetznerServer.created,
);
} catch (e) {
continue;
}
servers.add(server);
}
return GenericResult(success: true, data: servers);
}
Future<GenericResult<List<ServerMetadataEntity>>> getMetadata(
final int serverId,
) async {
List<ServerMetadataEntity> metadata = [];
final result = await _adapter.api().getServers();
if (result.data.isEmpty || !result.success) {
return GenericResult(
success: false,
data: metadata,
code: result.code,
message: result.message,
);
}
final List<HetznerServerInfo> servers = result.data;
try {
final HetznerServerInfo server = servers.firstWhere(
(final server) => server.id == serverId,
);
metadata = [
ServerMetadataEntity(
type: MetadataType.id,
trId: 'server.server_id',
value: server.id.toString(),
),
ServerMetadataEntity(
type: MetadataType.status,
trId: 'server.status',
value: server.status.toString().split('.')[1].capitalize(),
),
ServerMetadataEntity(
type: MetadataType.cpu,
trId: 'server.cpu',
value: server.serverType.cores.toString(),
),
ServerMetadataEntity(
type: MetadataType.ram,
trId: 'server.ram',
value: '${server.serverType.memory.toString()} GB',
),
ServerMetadataEntity(
type: MetadataType.cost,
trId: 'server.monthly_cost',
value: server.serverType.prices[1].monthly.toStringAsFixed(2),
),
ServerMetadataEntity(
type: MetadataType.location,
trId: 'server.location',
value: '${server.location.city}, ${server.location.country}',
),
ServerMetadataEntity(
type: MetadataType.other,
trId: 'server.provider',
value: _adapter.api().displayProviderName,
),
];
} catch (e) {
return GenericResult(
success: false,
data: [],
message: e.toString(),
);
}
return GenericResult(success: true, data: metadata);
}
Future<GenericResult<ServerMetrics?>> getMetrics(
final int serverId,
final DateTime start,
final DateTime end,
) async {
ServerMetrics? metrics;
List<TimeSeriesData> serializeTimeSeries(
final Map<String, dynamic> json,
final String type,
) {
final List list = json['time_series'][type]['values'];
return list
.map((final el) => TimeSeriesData(el[0], double.parse(el[1])))
.toList();
}
final cpuResult = await _adapter.api().getMetrics(
serverId,
start,
end,
'cpu',
);
if (cpuResult.data.isEmpty || !cpuResult.success) {
return GenericResult(
success: false,
data: metrics,
code: cpuResult.code,
message: cpuResult.message,
);
}
final netResult = await _adapter.api().getMetrics(
serverId,
start,
end,
'network',
);
if (cpuResult.data.isEmpty || !netResult.success) {
return GenericResult(
success: false,
data: metrics,
code: netResult.code,
message: netResult.message,
);
}
metrics = ServerMetrics(
cpu: serializeTimeSeries(
cpuResult.data,
'cpu',
),
bandwidthIn: serializeTimeSeries(
netResult.data,
'network.0.bandwidth.in',
),
bandwidthOut: serializeTimeSeries(
netResult.data,
'network.0.bandwidth.out',
),
end: end,
start: start,
stepsInSecond: cpuResult.data['step'],
);
return GenericResult(data: metrics, success: true);
}
Future<GenericResult<DateTime?>> restart(final int serverId) async {
DateTime? timestamp;
final result = await _adapter.api().restart(serverId);
if (!result.success) {
return GenericResult(
success: false,
data: timestamp,
code: result.code,
message: result.message,
);
}
timestamp = DateTime.now();
return GenericResult(
success: true,
data: timestamp,
);
}
Future<GenericResult<DateTime?>> powerOn(final int serverId) async {
DateTime? timestamp;
final result = await _adapter.api().powerOn(serverId);
if (!result.success) {
return GenericResult(
success: false,
data: timestamp,
code: result.code,
message: result.message,
);
}
timestamp = DateTime.now();
return GenericResult(
success: true,
data: timestamp,
);
}
}

View File

@ -27,7 +27,7 @@ class _TextDetails extends StatelessWidget {
.map(
(final metadata) => ListTileOnSurfaceVariant(
leadingIcon: metadata.type.icon,
title: metadata.name,
title: metadata.trId.tr(),
subtitle: metadata.value,
),
)