mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-03-11 17:24:09 +00:00
feat(region): Implement endpoints for listing available provider regions
This commit is contained in:
parent
2f59954641
commit
e032bd8a78
8 changed files with 220 additions and 21 deletions
lib/logic
api_maps/rest_maps/server_providers
cubit
hetzner_metrics
provider_volumes
server_installation
models
|
@ -11,6 +11,7 @@ import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
import 'package:selfprivacy/logic/models/price.dart';
|
import 'package:selfprivacy/logic/models/price.dart';
|
||||||
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/server_provider_location.dart';
|
||||||
import 'package:selfprivacy/utils/password_generator.dart';
|
import 'package:selfprivacy/utils/password_generator.dart';
|
||||||
|
|
||||||
class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
|
@ -538,6 +539,69 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? getEmojiFlag(final String query) {
|
||||||
|
String? emoji;
|
||||||
|
|
||||||
|
switch (query.toLowerCase().substring(0, 2)) {
|
||||||
|
case 'fra':
|
||||||
|
emoji = '🇩🇪';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ams':
|
||||||
|
emoji = '🇳🇱';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sgp':
|
||||||
|
emoji = '🇸🇬';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'lon':
|
||||||
|
emoji = '🇬🇧';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tor':
|
||||||
|
emoji = '🇨🇦';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'blr':
|
||||||
|
emoji = '🇮🇳';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'nyc':
|
||||||
|
case 'sfo':
|
||||||
|
emoji = '🇺🇸';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ServerProviderLocation>> getAvailableLocations() async {
|
||||||
|
List<ServerProviderLocation> locations = [];
|
||||||
|
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
final Response response = await client.post(
|
||||||
|
'/locations',
|
||||||
|
);
|
||||||
|
|
||||||
|
locations = response.data!['locations'].map<ServerProviderLocation>(
|
||||||
|
(final location) => ServerProviderLocation(
|
||||||
|
title: location['slug'],
|
||||||
|
description: location['name'],
|
||||||
|
flag: getEmojiFlag(location['slug']),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
close(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> createReverseDns({
|
Future<void> createReverseDns({
|
||||||
required final ServerHostingDetails serverDetails,
|
required final ServerHostingDetails serverDetails,
|
||||||
|
|
|
@ -11,10 +11,15 @@ import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
import 'package:selfprivacy/logic/models/price.dart';
|
import 'package:selfprivacy/logic/models/price.dart';
|
||||||
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/server_provider_location.dart';
|
||||||
import 'package:selfprivacy/utils/password_generator.dart';
|
import 'package:selfprivacy/utils/password_generator.dart';
|
||||||
|
|
||||||
class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
HetznerApi({required this.region, this.hasLogger = false, this.isWithToken = true,});
|
HetznerApi({
|
||||||
|
required this.region,
|
||||||
|
this.hasLogger = false,
|
||||||
|
this.isWithToken = true,
|
||||||
|
});
|
||||||
@override
|
@override
|
||||||
bool hasLogger;
|
bool hasLogger;
|
||||||
@override
|
@override
|
||||||
|
@ -536,6 +541,52 @@ class HetznerApi extends ServerProviderApi with VolumeProviderApi {
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<List<ServerProviderLocation>> getAvailableLocations() async {
|
||||||
|
List<ServerProviderLocation> locations = [];
|
||||||
|
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
final Response response = await client.post(
|
||||||
|
'/locations',
|
||||||
|
);
|
||||||
|
|
||||||
|
locations = response.data!['locations'].map<ServerProviderLocation>(
|
||||||
|
(final location) => ServerProviderLocation(
|
||||||
|
title: location['city'],
|
||||||
|
description: location['description'],
|
||||||
|
flag: getEmojiFlag(location['country']),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
close(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> createReverseDns({
|
Future<void> createReverseDns({
|
||||||
required final ServerHostingDetails serverDetails,
|
required final ServerHostingDetails serverDetails,
|
||||||
|
|
|
@ -3,9 +3,11 @@ import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||||
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
import 'package:selfprivacy/logic/models/server_basic_info.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/server_provider_location.dart';
|
||||||
|
|
||||||
abstract class ServerProviderApi extends ApiMap {
|
abstract class ServerProviderApi extends ApiMap {
|
||||||
Future<List<ServerBasicInfo>> getServers();
|
Future<List<ServerBasicInfo>> getServers();
|
||||||
|
Future<List<ServerProviderLocation>> getAvailableLocations();
|
||||||
|
|
||||||
Future<ServerHostingDetails> restart();
|
Future<ServerHostingDetails> restart();
|
||||||
Future<ServerHostingDetails> powerOn();
|
Future<ServerHostingDetails> powerOn();
|
||||||
|
|
|
@ -26,7 +26,10 @@ class HetznerMetricsRepository {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final HetznerApi api = HetznerApi(hasLogger: false, region: 'fra1',);
|
final HetznerApi api = HetznerApi(
|
||||||
|
hasLogger: false,
|
||||||
|
region: 'fra1',
|
||||||
|
);
|
||||||
|
|
||||||
final List<Map<String, dynamic>> results = await Future.wait([
|
final List<Map<String, dynamic>> results = await Future.wait([
|
||||||
api.getMetrics(start, end, 'cpu'),
|
api.getMetrics(start, end, 'cpu'),
|
||||||
|
|
|
@ -34,8 +34,13 @@ class ApiProviderVolumeCubit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Price?> getPricePerGb() async =>
|
Future<Price?> getPricePerGb() async => providerApi!
|
||||||
providerApi!.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),).getPricePerGb();
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.getPricePerGb();
|
||||||
|
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
emit(const ApiProviderVolumeState([], LoadingStatus.refreshing, false));
|
emit(const ApiProviderVolumeState([], LoadingStatus.refreshing, false));
|
||||||
|
@ -47,8 +52,13 @@ class ApiProviderVolumeCubit
|
||||||
return emit(const ApiProviderVolumeState([], LoadingStatus.error, false));
|
return emit(const ApiProviderVolumeState([], LoadingStatus.error, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ServerVolume> volumes =
|
final List<ServerVolume> volumes = await providerApi!
|
||||||
await providerApi!.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),).getVolumes();
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.getVolumes();
|
||||||
|
|
||||||
if (volumes.isEmpty) {
|
if (volumes.isEmpty) {
|
||||||
return emit(const ApiProviderVolumeState([], LoadingStatus.error, false));
|
return emit(const ApiProviderVolumeState([], LoadingStatus.error, false));
|
||||||
|
@ -60,14 +70,22 @@ class ApiProviderVolumeCubit
|
||||||
Future<void> attachVolume(final DiskVolume volume) async {
|
Future<void> attachVolume(final DiskVolume volume) async {
|
||||||
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
|
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
|
||||||
await providerApi!
|
await providerApi!
|
||||||
.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),)
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
.attachVolume(volume.providerVolume!.id.toString(), server.id);
|
.attachVolume(volume.providerVolume!.id.toString(), server.id);
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> detachVolume(final DiskVolume volume) async {
|
Future<void> detachVolume(final DiskVolume volume) async {
|
||||||
await providerApi!
|
await providerApi!
|
||||||
.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),)
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
.detachVolume(volume.providerVolume!.id.toString());
|
.detachVolume(volume.providerVolume!.id.toString());
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
@ -81,7 +99,13 @@ class ApiProviderVolumeCubit
|
||||||
'Starting resize',
|
'Starting resize',
|
||||||
);
|
);
|
||||||
emit(state.copyWith(isResizing: true));
|
emit(state.copyWith(isResizing: true));
|
||||||
final bool resized = await providerApi!.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),).resizeVolume(
|
final bool resized = await providerApi!
|
||||||
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.resizeVolume(
|
||||||
volume.providerVolume!.id.toString(),
|
volume.providerVolume!.id.toString(),
|
||||||
newSizeGb,
|
newSizeGb,
|
||||||
);
|
);
|
||||||
|
@ -117,8 +141,13 @@ class ApiProviderVolumeCubit
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createVolume() async {
|
Future<void> createVolume() async {
|
||||||
final ServerVolume? volume =
|
final ServerVolume? volume = await providerApi!
|
||||||
await providerApi!.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),).createVolume();
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.createVolume();
|
||||||
|
|
||||||
final diskVolume = DiskVolume(providerVolume: volume);
|
final diskVolume = DiskVolume(providerVolume: volume);
|
||||||
await attachVolume(diskVolume);
|
await attachVolume(diskVolume);
|
||||||
|
@ -131,7 +160,11 @@ class ApiProviderVolumeCubit
|
||||||
|
|
||||||
Future<void> deleteVolume(final DiskVolume volume) async {
|
Future<void> deleteVolume(final DiskVolume volume) async {
|
||||||
await providerApi!
|
await providerApi!
|
||||||
.getVolumeProvider(settings: const ServerProviderApiSettings(region: 'fra1',),)
|
.getVolumeProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
.deleteVolume(volume.providerVolume!.id.toString());
|
.deleteVolume(volume.providerVolume!.id.toString());
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,11 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
|
|
||||||
RegExp getServerProviderApiTokenValidation() =>
|
RegExp getServerProviderApiTokenValidation() =>
|
||||||
repository.serverProviderApiFactory!
|
repository.serverProviderApiFactory!
|
||||||
.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),)
|
.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
)
|
||||||
.getApiTokenValidation();
|
.getApiTokenValidation();
|
||||||
|
|
||||||
RegExp getDnsProviderApiTokenValidation() => repository.dnsProviderApiFactory!
|
RegExp getDnsProviderApiTokenValidation() => repository.dnsProviderApiFactory!
|
||||||
|
@ -75,7 +79,8 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
) async =>
|
) async =>
|
||||||
repository.serverProviderApiFactory!
|
repository.serverProviderApiFactory!
|
||||||
.getServerProvider(
|
.getServerProvider(
|
||||||
settings: const ServerProviderApiSettings(region: 'fra1', isWithToken: false),
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1', isWithToken: false),
|
||||||
)
|
)
|
||||||
.isApiTokenValid(providerToken);
|
.isApiTokenValid(providerToken);
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,11 @@ class ServerInstallationRepository {
|
||||||
) async {
|
) async {
|
||||||
ServerHostingDetails serverDetails;
|
ServerHostingDetails serverDetails;
|
||||||
|
|
||||||
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
serverDetails = await api.powerOn();
|
serverDetails = await api.powerOn();
|
||||||
|
|
||||||
return serverDetails;
|
return serverDetails;
|
||||||
|
@ -229,7 +233,11 @@ class ServerInstallationRepository {
|
||||||
required final Future<void> Function(ServerHostingDetails serverDetails)
|
required final Future<void> Function(ServerHostingDetails serverDetails)
|
||||||
onSuccess,
|
onSuccess,
|
||||||
}) async {
|
}) async {
|
||||||
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
final ServerHostingDetails? serverDetails = await api.createServer(
|
final ServerHostingDetails? serverDetails = await api.createServer(
|
||||||
dnsApiToken: cloudFlareKey,
|
dnsApiToken: cloudFlareKey,
|
||||||
|
@ -334,7 +342,11 @@ class ServerInstallationRepository {
|
||||||
final DnsProviderApi dnsProviderApi =
|
final DnsProviderApi dnsProviderApi =
|
||||||
dnsProviderApiFactory!.getDnsProvider();
|
dnsProviderApiFactory!.getDnsProvider();
|
||||||
final ServerProviderApi serverApi =
|
final ServerProviderApi serverApi =
|
||||||
serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
await dnsProviderApi.removeSimilarRecords(
|
await dnsProviderApi.removeSimilarRecords(
|
||||||
ip4: serverDetails.ip4,
|
ip4: serverDetails.ip4,
|
||||||
|
@ -406,12 +418,20 @@ class ServerInstallationRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ServerHostingDetails> restart() async {
|
Future<ServerHostingDetails> restart() async {
|
||||||
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
return api.restart();
|
return api.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ServerHostingDetails> powerOn() async {
|
Future<ServerHostingDetails> powerOn() async {
|
||||||
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
return api.powerOn();
|
return api.powerOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +674,11 @@ class ServerInstallationRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<ServerBasicInfo>> getServersOnProviderAccount() async {
|
Future<List<ServerBasicInfo>> getServersOnProviderAccount() async {
|
||||||
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
return api.getServers();
|
return api.getServers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +756,11 @@ class ServerInstallationRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteServer(final ServerDomain serverDomain) async {
|
Future<void> deleteServer(final ServerDomain serverDomain) async {
|
||||||
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(settings: const ServerProviderApiSettings(region: 'fra1',),);
|
final ServerProviderApi api = serverProviderApiFactory!.getServerProvider(
|
||||||
|
settings: const ServerProviderApiSettings(
|
||||||
|
region: 'fra1',
|
||||||
|
),
|
||||||
|
);
|
||||||
final DnsProviderApi dnsProviderApi =
|
final DnsProviderApi dnsProviderApi =
|
||||||
dnsProviderApiFactory!.getDnsProvider();
|
dnsProviderApiFactory!.getDnsProvider();
|
||||||
|
|
||||||
|
|
13
lib/logic/models/server_provider_location.dart
Normal file
13
lib/logic/models/server_provider_location.dart
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
class ServerProviderLocation {
|
||||||
|
ServerProviderLocation({
|
||||||
|
required this.title,
|
||||||
|
this.description,
|
||||||
|
this.flag,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final String? description;
|
||||||
|
|
||||||
|
/// as emoji
|
||||||
|
final String? flag;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue