mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-08 17:11:14 +00:00
Merge pull request 'volumes-hetzner' (#97) from volumes-hetzner into develop
Reviewed-on: https://git.selfprivacy.org/kherel/selfprivacy.org.app/pulls/97
This commit is contained in:
commit
f40749ca57
|
@ -56,24 +56,174 @@ class HetznerApi extends ApiMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ServerVolume> createVolume() async {
|
Future<ServerVolume?> createVolume() async {
|
||||||
|
ServerVolume? volume;
|
||||||
|
|
||||||
|
final Response dbCreateResponse;
|
||||||
final Dio client = await getClient();
|
final Dio client = await getClient();
|
||||||
final Response dbCreateResponse = await client.post(
|
try {
|
||||||
'/volumes',
|
dbCreateResponse = await client.post(
|
||||||
data: {
|
'/volumes',
|
||||||
'size': 10,
|
data: {
|
||||||
'name': StringGenerators.dbStorageName(),
|
'size': 10,
|
||||||
'labels': {'labelkey': 'value'},
|
'name': StringGenerators.dbStorageName(),
|
||||||
'location': 'fsn1',
|
'labels': {'labelkey': 'value'},
|
||||||
'automount': false,
|
'location': 'fsn1',
|
||||||
'format': 'ext4'
|
'automount': false,
|
||||||
},
|
'format': 'ext4'
|
||||||
);
|
},
|
||||||
final dbId = dbCreateResponse.data['volume']['id'];
|
);
|
||||||
return ServerVolume(
|
final dbId = dbCreateResponse.data['volume']['id'];
|
||||||
id: dbId,
|
final dbSize = dbCreateResponse.data['volume']['size'];
|
||||||
name: dbCreateResponse.data['volume']['name'],
|
final dbServer = dbCreateResponse.data['volume']['server'];
|
||||||
);
|
final dbName = dbCreateResponse.data['volume']['name'];
|
||||||
|
volume = ServerVolume(
|
||||||
|
id: dbId,
|
||||||
|
name: dbName,
|
||||||
|
sizeByte: dbSize,
|
||||||
|
serverId: dbServer,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<ServerVolume>> getVolumes({final String? status}) async {
|
||||||
|
final List<ServerVolume> volumes = [];
|
||||||
|
|
||||||
|
final Response dbGetResponse;
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
dbGetResponse = await client.get(
|
||||||
|
'/volumes',
|
||||||
|
queryParameters: {
|
||||||
|
'status': status,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final List<dynamic> rawVolumes = dbGetResponse.data['volumes'];
|
||||||
|
for (final rawVolume in rawVolumes) {
|
||||||
|
final int dbId = rawVolume['id'];
|
||||||
|
final int dbSize = rawVolume['size'];
|
||||||
|
final dbServer = rawVolume['server'];
|
||||||
|
final String dbName = rawVolume['name'];
|
||||||
|
final volume = ServerVolume(
|
||||||
|
id: dbId,
|
||||||
|
name: dbName,
|
||||||
|
sizeByte: dbSize,
|
||||||
|
serverId: dbServer,
|
||||||
|
);
|
||||||
|
volumes.add(volume);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ServerVolume?> getVolume(final int id) async {
|
||||||
|
ServerVolume? volume;
|
||||||
|
|
||||||
|
final Response dbGetResponse;
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
dbGetResponse = await client.get('/volumes/$id');
|
||||||
|
final int dbId = dbGetResponse.data['volume']['id'];
|
||||||
|
final int dbSize = dbGetResponse.data['volume']['size'];
|
||||||
|
final int dbServer = dbGetResponse.data['volume']['server'];
|
||||||
|
final String dbName = dbGetResponse.data['volume']['name'];
|
||||||
|
volume = ServerVolume(
|
||||||
|
id: dbId,
|
||||||
|
name: dbName,
|
||||||
|
sizeByte: dbSize,
|
||||||
|
serverId: dbServer,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteVolume(final int id) async {
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
await client.delete('/volumes/$id');
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> attachVolume(final int volumeId, final int serverId) async {
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
final Response dbPostResponse;
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
dbPostResponse = await client.post(
|
||||||
|
'/volumes/$volumeId/actions/attach',
|
||||||
|
data: {
|
||||||
|
'automount': true,
|
||||||
|
'server': serverId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
success = dbPostResponse.data['action']['status'].toString() != 'error';
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> detachVolume(final int volumeId) async {
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
final Response dbPostResponse;
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
dbPostResponse = await client.post('/volumes/$volumeId/actions/detach');
|
||||||
|
success = dbPostResponse.data['action']['status'].toString() != 'error';
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> resizeVolume(final int volumeId, final int sizeGb) async {
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
final Response dbPostResponse;
|
||||||
|
final Dio client = await getClient();
|
||||||
|
try {
|
||||||
|
dbPostResponse = await client.post(
|
||||||
|
'/volumes/$volumeId/actions/resize',
|
||||||
|
data: {
|
||||||
|
'size': sizeGb,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
success = dbPostResponse.data['action']['status'].toString() != 'error';
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ServerHostingDetails?> createServer({
|
Future<ServerHostingDetails?> createServer({
|
||||||
|
|
|
@ -16,17 +16,16 @@ class ApiDevicesCubit
|
||||||
@override
|
@override
|
||||||
void load() async {
|
void load() async {
|
||||||
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
||||||
final List<ApiToken>? devices = await _getApiTokens();
|
_refetch();
|
||||||
if (devices != null) {
|
|
||||||
emit(ApiDevicesState(devices, LoadingStatus.success));
|
|
||||||
} else {
|
|
||||||
emit(const ApiDevicesState([], LoadingStatus.error));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
emit(const ApiDevicesState([], LoadingStatus.refreshing));
|
emit(const ApiDevicesState([], LoadingStatus.refreshing));
|
||||||
|
_refetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _refetch() async {
|
||||||
final List<ApiToken>? devices = await _getApiTokens();
|
final List<ApiToken>? devices = await _getApiTokens();
|
||||||
if (devices != null) {
|
if (devices != null) {
|
||||||
emit(ApiDevicesState(devices, LoadingStatus.success));
|
emit(ApiDevicesState(devices, LoadingStatus.success));
|
||||||
|
|
|
@ -491,6 +491,8 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
||||||
volume: ServerVolume(
|
volume: ServerVolume(
|
||||||
id: server.volumeId,
|
id: server.volumeId,
|
||||||
name: 'recovered_volume',
|
name: 'recovered_volume',
|
||||||
|
sizeByte: 0,
|
||||||
|
serverId: server.id,
|
||||||
),
|
),
|
||||||
apiToken: dataState.serverDetails!.apiToken,
|
apiToken: dataState.serverDetails!.apiToken,
|
||||||
provider: ServerProvider.hetzner,
|
provider: ServerProvider.hetzner,
|
||||||
|
|
|
@ -212,7 +212,13 @@ class ServerInstallationRepository {
|
||||||
late ServerVolume dataBase;
|
late ServerVolume dataBase;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dataBase = await hetznerApi.createVolume();
|
final ServerVolume? createdVolume = await hetznerApi.createVolume();
|
||||||
|
if (createdVolume == null) {
|
||||||
|
print('Volume is not created!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBase = createdVolume;
|
||||||
|
|
||||||
final ServerHostingDetails? serverDetails = await hetznerApi.createServer(
|
final ServerHostingDetails? serverDetails = await hetznerApi.createServer(
|
||||||
cloudFlareKey: cloudFlareKey,
|
cloudFlareKey: cloudFlareKey,
|
||||||
|
@ -220,6 +226,7 @@ class ServerInstallationRepository {
|
||||||
domainName: domainName,
|
domainName: domainName,
|
||||||
dataBase: dataBase,
|
dataBase: dataBase,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (serverDetails == null) {
|
if (serverDetails == null) {
|
||||||
print('Server is not initialized!');
|
print('Server is not initialized!');
|
||||||
return;
|
return;
|
||||||
|
@ -444,6 +451,8 @@ class ServerInstallationRepository {
|
||||||
volume: ServerVolume(
|
volume: ServerVolume(
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
|
sizeByte: 0,
|
||||||
|
serverId: 0,
|
||||||
),
|
),
|
||||||
provider: ServerProvider.unknown,
|
provider: ServerProvider.unknown,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -478,6 +487,8 @@ class ServerInstallationRepository {
|
||||||
volume: ServerVolume(
|
volume: ServerVolume(
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
|
sizeByte: 0,
|
||||||
|
serverId: 0,
|
||||||
),
|
),
|
||||||
provider: ServerProvider.unknown,
|
provider: ServerProvider.unknown,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -512,6 +523,8 @@ class ServerInstallationRepository {
|
||||||
volume: ServerVolume(
|
volume: ServerVolume(
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
|
serverId: 0,
|
||||||
|
sizeByte: 0,
|
||||||
),
|
),
|
||||||
provider: ServerProvider.unknown,
|
provider: ServerProvider.unknown,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -537,6 +550,8 @@ class ServerInstallationRepository {
|
||||||
volume: ServerVolume(
|
volume: ServerVolume(
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '',
|
name: '',
|
||||||
|
sizeByte: 0,
|
||||||
|
serverId: 0,
|
||||||
),
|
),
|
||||||
provider: ServerProvider.unknown,
|
provider: ServerProvider.unknown,
|
||||||
id: 0,
|
id: 0,
|
||||||
|
|
70
lib/logic/cubit/volumes/volumes_cubit.dart
Normal file
70
lib/logic/cubit/volumes/volumes_cubit.dart
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import 'package:selfprivacy/config/get_it_config.dart';
|
||||||
|
import 'package:selfprivacy/logic/api_maps/hetzner.dart';
|
||||||
|
import 'package:selfprivacy/logic/api_maps/server.dart';
|
||||||
|
import 'package:selfprivacy/logic/common_enum/common_enum.dart';
|
||||||
|
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
|
||||||
|
import 'package:selfprivacy/logic/models/hive/server_details.dart';
|
||||||
|
|
||||||
|
part 'volumes_state.dart';
|
||||||
|
|
||||||
|
class ApiVolumesCubit
|
||||||
|
extends ServerInstallationDependendCubit<ApiVolumesState> {
|
||||||
|
ApiVolumesCubit(final ServerInstallationCubit serverInstallationCubit)
|
||||||
|
: super(serverInstallationCubit, const ApiVolumesState.initial());
|
||||||
|
|
||||||
|
final ServerApi api = ServerApi();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void load() async {
|
||||||
|
if (serverInstallationCubit.state is ServerInstallationFinished) {
|
||||||
|
_refetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() async {
|
||||||
|
emit(const ApiVolumesState([], LoadingStatus.refreshing));
|
||||||
|
_refetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _refetch() async {
|
||||||
|
final List<ServerVolume> volumes = await HetznerApi().getVolumes();
|
||||||
|
if (volumes.isNotEmpty) {
|
||||||
|
emit(ApiVolumesState(volumes, LoadingStatus.success));
|
||||||
|
} else {
|
||||||
|
emit(const ApiVolumesState([], LoadingStatus.error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachVolume(final ServerVolume volume) async {
|
||||||
|
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
|
||||||
|
HetznerApi().attachVolume(volume.id, server.id);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void detachVolume(final ServerVolume volume) async {
|
||||||
|
HetznerApi().detachVolume(volume.id);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resizeVolume(final ServerVolume volume, final int newSizeGb) {
|
||||||
|
if (volume.sizeByte < newSizeGb) {
|
||||||
|
HetznerApi().resizeVolume(volume.id, newSizeGb);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createVolume() async {
|
||||||
|
HetznerApi().createVolume();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteVolume(final ServerVolume volume) async {
|
||||||
|
HetznerApi().deleteVolume(volume.id);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void clear() {
|
||||||
|
emit(const ApiVolumesState.initial());
|
||||||
|
}
|
||||||
|
}
|
23
lib/logic/cubit/volumes/volumes_state.dart
Normal file
23
lib/logic/cubit/volumes/volumes_state.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
part of 'volumes_cubit.dart';
|
||||||
|
|
||||||
|
class ApiVolumesState extends ServerInstallationDependendState {
|
||||||
|
const ApiVolumesState(this._volumes, this.status);
|
||||||
|
|
||||||
|
const ApiVolumesState.initial() : this(const [], LoadingStatus.uninitialized);
|
||||||
|
final List<ServerVolume> _volumes;
|
||||||
|
final LoadingStatus status;
|
||||||
|
|
||||||
|
List<ServerVolume> get volumes => _volumes;
|
||||||
|
|
||||||
|
ApiVolumesState copyWith({
|
||||||
|
final List<ServerVolume>? volumes,
|
||||||
|
final LoadingStatus? status,
|
||||||
|
}) =>
|
||||||
|
ApiVolumesState(
|
||||||
|
volumes ?? _volumes,
|
||||||
|
status ?? this.status,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [_volumes];
|
||||||
|
}
|
|
@ -55,12 +55,18 @@ class ServerVolume {
|
||||||
ServerVolume({
|
ServerVolume({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
required this.sizeByte,
|
||||||
|
required this.serverId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
int id;
|
int id;
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
String name;
|
String name;
|
||||||
|
@HiveField(3, defaultValue: 10737418240) // 10 Gb
|
||||||
|
int sizeByte;
|
||||||
|
@HiveField(4, defaultValue: null)
|
||||||
|
int? serverId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@HiveType(typeId: 101)
|
@HiveType(typeId: 101)
|
||||||
|
|
Loading…
Reference in a new issue