add volume

fdroid
Kherel 2021-03-30 19:38:40 +02:00
parent 275ba21a47
commit ae3ec309cb
10 changed files with 141 additions and 27 deletions

View File

@ -16,6 +16,7 @@ class HiveConfig {
Hive.registerAdapter(HetznerServerDetailsAdapter()); Hive.registerAdapter(HetznerServerDetailsAdapter());
Hive.registerAdapter(CloudFlareDomainAdapter()); Hive.registerAdapter(CloudFlareDomainAdapter());
Hive.registerAdapter(BackblazeCredentialAdapter()); Hive.registerAdapter(BackblazeCredentialAdapter());
Hive.registerAdapter(HetznerDataBaseAdapter());
await Hive.openBox(BNames.appSettings); await Hive.openBox(BNames.appSettings);
var cipher = HiveAesCipher(await getEncriptedKey()); var cipher = HiveAesCipher(await getEncriptedKey());

View File

@ -55,6 +55,19 @@ class HetznerApi extends ApiMap {
} }
} }
Future<bool> isFreeToCreate() async {
var client = await getClient();
Response serversReponse = await client.get('/servers');
List servers = serversReponse.data['servers'];
var server = servers.firstWhere(
(el) => el['name'] == 'selfprivacy-server',
orElse: null,
);
client.close();
return server == null;
}
Future<HetznerServerDetails> createServer({ Future<HetznerServerDetails> createServer({
required String cloudFlareKey, required String cloudFlareKey,
required User rootUser, required User rootUser,
@ -62,31 +75,71 @@ class HetznerApi extends ApiMap {
}) async { }) async {
var dbPassword = getRandomString(40); var dbPassword = getRandomString(40);
const chars =
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
var dbStorageName = getRandomString(6, chars);
var client = await getClient();
Response dbCreateResponse = await client.post(
'/volumes',
data: {
"size": 10,
"name": dbStorageName,
"labels": {"labelkey": "value"},
"location": "fsn1",
"automount": false,
"format": "ext4"
},
);
var dbId = dbCreateResponse.data['volume']['id'];
var data = jsonDecode( var data = jsonDecode(
'''{"name":"selfprivacy-server","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[],"networks":[],"user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-20.09 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} HASHED_PASSWORD=${rootUser.hashPassword} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":false}''', '''{"name":"selfprivacy-server","server_type":"cx11","start_after_create":false,"image":"ubuntu-20.04", "volumes":[$dbId],"networks":[],"user_data":"#cloud-config\\nruncmd:\\n- curl https://git.selfprivacy.org/ilchub/selfprivacy-nixos-infect/raw/branch/master/nixos-infect | PROVIDER=hetzner NIX_CHANNEL=nixos-20.09 DOMAIN=$domainName LUSER=${rootUser.login} PASSWORD=${rootUser.password} HASHED_PASSWORD=${rootUser.hashPassword} CF_TOKEN=$cloudFlareKey DB_PASSWORD=$dbPassword bash 2>&1 | tee /tmp/infect.log","labels":{},"automount":true, "location": "fsn1"}''',
); );
var client = await getClient(); Response serverCreateResponse = await client.post(
Response response = await client.post(
'/servers', '/servers',
data: data, data: data,
); );
client.close(); client.close();
return HetznerServerDetails( return HetznerServerDetails(
id: response.data['server']['id'], id: serverCreateResponse.data['server']['id'],
ip4: response.data['server']['public_net']['ipv4']['ip'], ip4: serverCreateResponse.data['server']['public_net']['ipv4']['ip'],
createTime: DateTime.now(), createTime: DateTime.now(),
dataBase: HetznerDataBase(
id: dbId,
name: dbCreateResponse.data['volume']['name'],
),
); );
} }
Future<void> deleteSelfprivacyServer() async { Future<void> deleteSelfprivacyServerAndAllVolumes() async {
var client = await getClient(); var client = await getClient();
Response response = await client.get('/servers');
List list = response.data['servers']; Response serversReponse = await client.get('/servers');
var server = list.firstWhere((el) => el['name'] == 'selfprivacy-server'); List servers = serversReponse.data['servers'];
var server = servers.firstWhere((el) => el['name'] == 'selfprivacy-server');
await client.delete('/servers/${server['id']}'); await client.delete('/servers/${server['id']}');
close(client);
Response volumesReponse = await client.get('/volumes');
List volumes = volumesReponse.data['volumes'];
var laterFutures = <Future>[];
for (var volume in volumes) {
if (volume['server'] == null) {
await client.delete('/volumes/${volume['id']}');
} else {
laterFutures.add(Future.delayed(Duration(seconds: 60)).then(
(_) => client.delete('/volumes/${volume['id']}'),
));
}
}
if (laterFutures.isEmpty) {
close(client);
} else {
Future.wait(laterFutures).then((value) => close(client));
}
} }
Future<HetznerServerDetails> startServer({ Future<HetznerServerDetails> startServer({

View File

@ -202,7 +202,7 @@ class AppConfigCubit extends Cubit<AppConfigState> {
} }
void clearAppConfig() { void clearAppConfig() {
_closeTimer(); closeTimer();
repository.clearAppConfig(); repository.clearAppConfig();
emit(InitialAppConfigState()); emit(InitialAppConfigState());
} }
@ -263,17 +263,16 @@ class AppConfigCubit extends Cubit<AppConfigState> {
onSuccess: onSuccess, onSuccess: onSuccess,
); );
} catch (e) { } catch (e) {
addError(e);
emit(_stateCopy); emit(_stateCopy);
} }
} }
close() { close() {
_closeTimer(); closeTimer();
return super.close(); return super.close();
} }
void _closeTimer() { void closeTimer() {
if (timer != null && timer!.isActive) { if (timer != null && timer!.isActive) {
timer!.cancel(); timer!.cancel();
} }

View File

@ -119,7 +119,7 @@ class AppConfigRepository {
text: 'basis.delete'.tr(), text: 'basis.delete'.tr(),
isRed: true, isRed: true,
onPressed: () async { onPressed: () async {
await hetznerApi.deleteSelfprivacyServer(); await hetznerApi.deleteSelfprivacyServerAndAllVolumes();
var serverDetails = await hetznerApi.createServer( var serverDetails = await hetznerApi.createServer(
cloudFlareKey: cloudFlareKey, cloudFlareKey: cloudFlareKey,

View File

@ -92,6 +92,8 @@ class AppConfigState extends Equatable {
isServerReseted, isServerReseted,
hasFinalChecked, hasFinalChecked,
]; ];
print(res);
return res; return res;
} }
} }

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class TimerModel extends ChangeNotifier { class TimerModel extends ChangeNotifier {
DateTime _time = DateTime.now(); DateTime _time = DateTime.now();
DateTime get messages => _time; DateTime get time => _time;
void restart() { void restart() {
_time = DateTime.now(); _time = DateTime.now();

View File

@ -8,14 +8,15 @@ class HetznerServerDetails {
required this.ip4, required this.ip4,
required this.id, required this.id,
required this.createTime, required this.createTime,
required this.dataBase,
this.startTime, this.startTime,
}); });
@HiveField(0) @HiveField(0)
final String? ip4; final String ip4;
@HiveField(1) @HiveField(1)
final int? id; final int id;
@HiveField(3) @HiveField(3)
final DateTime? createTime; final DateTime? createTime;
@ -23,14 +24,31 @@ class HetznerServerDetails {
@HiveField(2) @HiveField(2)
final DateTime? startTime; final DateTime? startTime;
@HiveField(4)
final HetznerDataBase dataBase;
HetznerServerDetails copyWith({DateTime? startTime}) { HetznerServerDetails copyWith({DateTime? startTime}) {
return HetznerServerDetails( return HetznerServerDetails(
startTime: startTime ?? this.startTime, startTime: startTime ?? this.startTime,
createTime: createTime, createTime: createTime,
id: id, id: id,
ip4: ip4, ip4: ip4,
dataBase: dataBase,
); );
} }
String toString() => id.toString(); String toString() => id.toString();
} }
@HiveType(typeId: 5)
class HetznerDataBase {
HetznerDataBase({
required this.id,
required this.name,
});
@HiveField(1)
int id;
@HiveField(2)
String name;
}

View File

@ -17,9 +17,10 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
}; };
return HetznerServerDetails( return HetznerServerDetails(
ip4: fields[0] as String?, ip4: fields[0] as String,
id: fields[1] as int?, id: fields[1] as int,
createTime: fields[3] as DateTime?, createTime: fields[3] as DateTime?,
dataBase: fields[4] as HetznerDataBase,
startTime: fields[2] as DateTime?, startTime: fields[2] as DateTime?,
); );
} }
@ -27,7 +28,7 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
@override @override
void write(BinaryWriter writer, HetznerServerDetails obj) { void write(BinaryWriter writer, HetznerServerDetails obj) {
writer writer
..writeByte(4) ..writeByte(5)
..writeByte(0) ..writeByte(0)
..write(obj.ip4) ..write(obj.ip4)
..writeByte(1) ..writeByte(1)
@ -35,7 +36,9 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
..writeByte(3) ..writeByte(3)
..write(obj.createTime) ..write(obj.createTime)
..writeByte(2) ..writeByte(2)
..write(obj.startTime); ..write(obj.startTime)
..writeByte(4)
..write(obj.dataBase);
} }
@override @override
@ -48,3 +51,40 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
typeId == other.typeId; typeId == other.typeId;
} }
class HetznerDataBaseAdapter extends TypeAdapter<HetznerDataBase> {
@override
final int typeId = 5;
@override
HetznerDataBase read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return HetznerDataBase(
id: fields[1] as int,
name: fields[2] as String,
);
}
@override
void write(BinaryWriter writer, HetznerDataBase obj) {
writer
..writeByte(2)
..writeByte(1)
..write(obj.id)
..writeByte(2)
..write(obj.name);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is HetznerDataBaseAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@ -407,8 +407,9 @@ class InitializingPage extends StatelessWidget {
BrandText.body2('initializing.11'.tr()), BrandText.body2('initializing.11'.tr()),
Spacer(), Spacer(),
BrandButton.rised( BrandButton.rised(
onPressed: onPressed: isLoading!
isLoading! ? null : () => appConfigCubit.createServerAndSetDnsRecords(), ? null
: () => appConfigCubit.createServerAndSetDnsRecords(),
title: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(), title: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(),
), ),
Spacer(flex: 2), Spacer(flex: 2),

View File

@ -4,11 +4,11 @@ const _chars =
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890_'; 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890_';
Random _rnd = Random(); Random _rnd = Random();
String getRandomString(int length) => String.fromCharCodes( String getRandomString(int length, [chars = _chars]) => String.fromCharCodes(
Iterable.generate( Iterable.generate(
length, length,
(_) => _chars.codeUnitAt( (_) => chars.codeUnitAt(
_rnd.nextInt(_chars.length), _rnd.nextInt(chars.length),
), ),
), ),
); );