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(CloudFlareDomainAdapter());
Hive.registerAdapter(BackblazeCredentialAdapter());
Hive.registerAdapter(HetznerDataBaseAdapter());
await Hive.openBox(BNames.appSettings);
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({
required String cloudFlareKey,
required User rootUser,
@ -62,31 +75,71 @@ class HetznerApi extends ApiMap {
}) async {
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(
'''{"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 response = await client.post(
Response serverCreateResponse = await client.post(
'/servers',
data: data,
);
client.close();
return HetznerServerDetails(
id: response.data['server']['id'],
ip4: response.data['server']['public_net']['ipv4']['ip'],
id: serverCreateResponse.data['server']['id'],
ip4: serverCreateResponse.data['server']['public_net']['ipv4']['ip'],
createTime: DateTime.now(),
dataBase: HetznerDataBase(
id: dbId,
name: dbCreateResponse.data['volume']['name'],
),
);
}
Future<void> deleteSelfprivacyServer() async {
Future<void> deleteSelfprivacyServerAndAllVolumes() async {
var client = await getClient();
Response response = await client.get('/servers');
List list = response.data['servers'];
var server = list.firstWhere((el) => el['name'] == 'selfprivacy-server');
Response serversReponse = await client.get('/servers');
List servers = serversReponse.data['servers'];
var server = servers.firstWhere((el) => el['name'] == 'selfprivacy-server');
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({

View File

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

View File

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

View File

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

View File

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

View File

@ -8,14 +8,15 @@ class HetznerServerDetails {
required this.ip4,
required this.id,
required this.createTime,
required this.dataBase,
this.startTime,
});
@HiveField(0)
final String? ip4;
final String ip4;
@HiveField(1)
final int? id;
final int id;
@HiveField(3)
final DateTime? createTime;
@ -23,14 +24,31 @@ class HetznerServerDetails {
@HiveField(2)
final DateTime? startTime;
@HiveField(4)
final HetznerDataBase dataBase;
HetznerServerDetails copyWith({DateTime? startTime}) {
return HetznerServerDetails(
startTime: startTime ?? this.startTime,
createTime: createTime,
id: id,
ip4: ip4,
dataBase: dataBase,
);
}
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(),
};
return HetznerServerDetails(
ip4: fields[0] as String?,
id: fields[1] as int?,
ip4: fields[0] as String,
id: fields[1] as int,
createTime: fields[3] as DateTime?,
dataBase: fields[4] as HetznerDataBase,
startTime: fields[2] as DateTime?,
);
}
@ -27,7 +28,7 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
@override
void write(BinaryWriter writer, HetznerServerDetails obj) {
writer
..writeByte(4)
..writeByte(5)
..writeByte(0)
..write(obj.ip4)
..writeByte(1)
@ -35,7 +36,9 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
..writeByte(3)
..write(obj.createTime)
..writeByte(2)
..write(obj.startTime);
..write(obj.startTime)
..writeByte(4)
..write(obj.dataBase);
}
@override
@ -48,3 +51,40 @@ class HetznerServerDetailsAdapter extends TypeAdapter<HetznerServerDetails> {
runtimeType == other.runtimeType &&
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()),
Spacer(),
BrandButton.rised(
onPressed:
isLoading! ? null : () => appConfigCubit.createServerAndSetDnsRecords(),
onPressed: isLoading!
? null
: () => appConfigCubit.createServerAndSetDnsRecords(),
title: isLoading ? 'basis.loading'.tr() : 'initializing.11'.tr(),
),
Spacer(flex: 2),

View File

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