Implement ServerJob cubit

remotes/1708434123650076052/graphql
NaiJi ✨ 2022-08-25 02:45:02 +03:00
parent 7bbdaf2ebe
commit 37d5ee9913
11 changed files with 258 additions and 207 deletions

View File

@ -10,7 +10,7 @@ import 'package:selfprivacy/logic/cubit/jobs/jobs_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/logic/cubit/services/services_cubit.dart';
import 'package:selfprivacy/logic/cubit/users/users_cubit.dart';
import 'package:selfprivacy/logic/cubit/volumes/volumes_cubit.dart';
import 'package:selfprivacy/logic/cubit/provider_volumes/provider_volume_cubit.dart';
class BlocAndProviderConfig extends StatelessWidget {
const BlocAndProviderConfig({final super.key, this.child});
@ -27,7 +27,7 @@ class BlocAndProviderConfig extends StatelessWidget {
final dnsRecordsCubit = DnsRecordsCubit(serverInstallationCubit);
final recoveryKeyCubit = RecoveryKeyCubit(serverInstallationCubit);
final apiDevicesCubit = ApiDevicesCubit(serverInstallationCubit);
final apiVolumesCubit = ApiVolumesCubit(serverInstallationCubit);
final apiVolumesCubit = ApiProviderVolumeCubit(serverInstallationCubit);
return MultiProvider(
providers: [
BlocProvider(

View File

@ -0,0 +1,108 @@
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_creator.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider_factory.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';
import 'package:selfprivacy/logic/models/json/server_disk_volume.dart';
import 'package:selfprivacy/ui/pages/server_storage/disk_status.dart';
part 'provider_volume_state.dart';
class ApiProviderVolumeCubit
extends ServerInstallationDependendCubit<ApiProviderVolumeState> {
ApiProviderVolumeCubit(final ServerInstallationCubit serverInstallationCubit)
: super(serverInstallationCubit, const ApiProviderVolumeState.initial()) {
final serverDetails = getIt<ApiConfigModel>().serverDetails;
providerApi = serverDetails == null
? null
: VolumeApiFactoryCreator.createVolumeProviderApiFactory(
getIt<ApiConfigModel>().serverDetails!.provider,
);
}
VolumeProviderApiFactory? providerApi;
@override
Future<void> load() async {
if (serverInstallationCubit.state is ServerInstallationFinished) {
_refetch();
}
}
Future<double?> getPricePerGb() async =>
providerApi!.getVolumeProvider().getPricePerGb();
Future<void> refresh() async {
emit(const ApiProviderVolumeState([], LoadingStatus.refreshing));
_refetch();
}
Future<void> _refetch() async {
if (providerApi == null) {
return emit(const ApiProviderVolumeState([], LoadingStatus.error));
}
final List<ServerVolume> volumes =
await providerApi!.getVolumeProvider().getVolumes();
if (volumes.isEmpty) {
return emit(const ApiProviderVolumeState([], LoadingStatus.error));
}
emit(ApiProviderVolumeState(volumes, LoadingStatus.success));
}
Future<void> attachVolume(final ServerVolume volume) async {
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
await providerApi!.getVolumeProvider().attachVolume(volume.id, server.id);
refresh();
}
Future<void> detachVolume(final ServerVolume volume) async {
await providerApi!.getVolumeProvider().detachVolume(volume.id);
refresh();
}
Future<bool> resizeVolume(
final DiskVolume volume,
final int newSizeGb,
) async {
final bool resized = await providerApi!.getVolumeProvider().resizeVolume(
volume.providerVolume!.id,
newSizeGb,
);
if (!resized) {
return false;
}
await ServerApi().resizeVolume(volume.name);
refresh();
return true;
}
Future<void> createVolume() async {
final ServerVolume? volume =
await providerApi!.getVolumeProvider().createVolume();
await attachVolume(volume!);
await Future.delayed(const Duration(seconds: 10));
await ServerApi().mountVolume(volume.name);
refresh();
}
Future<void> deleteVolume(final DiskVolume volume) async {
await providerApi!
.getVolumeProvider()
.deleteVolume(volume.providerVolume!.id);
refresh();
}
@override
void clear() {
emit(const ApiProviderVolumeState.initial());
}
}

View File

@ -0,0 +1,24 @@
part of 'provider_volume_cubit.dart';
class ApiProviderVolumeState extends ServerInstallationDependendState {
const ApiProviderVolumeState(this._volumes, this.status);
const ApiProviderVolumeState.initial()
: this(const [], LoadingStatus.uninitialized);
final List<ServerVolume> _volumes;
final LoadingStatus status;
List<ServerVolume> get volumes => _volumes;
ApiProviderVolumeState copyWith({
final List<ServerVolume>? volumes,
final LoadingStatus? status,
}) =>
ApiProviderVolumeState(
volumes ?? _volumes,
status ?? this.status,
);
@override
List<Object?> get props => [_volumes];
}

View File

@ -554,9 +554,6 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
);
}
Future<List<ServerDiskVolume>> getServerDiskVolumes() async =>
ServerApi().getServerDiskVolumes();
Future<void> setAndValidateCloudflareToken(final String token) async {
final ServerInstallationRecovery dataState =
state as ServerInstallationRecovery;

View File

@ -0,0 +1,36 @@
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/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/json/server_disk_volume.dart';
part 'server_volume_state.dart';
class ApiServerVolumeCubit
extends ServerInstallationDependendCubit<ApiServerVolumeState> {
ApiServerVolumeCubit(final ServerInstallationCubit serverInstallationCubit)
: super(serverInstallationCubit, const ApiServerVolumeState.initial());
final ServerApi serverApi = ServerApi();
@override
Future<void> load() async {
if (serverInstallationCubit.state is ServerInstallationFinished) {
_refetch();
}
}
Future<void> _refetch() async {
final List<ServerDiskVolume> volumes =
await serverApi.getServerDiskVolumes();
if (volumes.isNotEmpty) {
emit(ApiServerVolumeState(volumes, LoadingStatus.success));
} else {
emit(const ApiServerVolumeState([], LoadingStatus.error));
}
}
@override
void clear() {
emit(const ApiServerVolumeState.initial());
}
}

View File

@ -0,0 +1,24 @@
part of 'server_volume_cubit.dart';
class ApiServerVolumeState extends ServerInstallationDependendState {
const ApiServerVolumeState(this._volumes, this.status);
const ApiServerVolumeState.initial()
: this(const [], LoadingStatus.uninitialized);
final List<ServerDiskVolume> _volumes;
final LoadingStatus status;
List<ServerDiskVolume> get volumes => _volumes;
ApiServerVolumeState copyWith({
final List<ServerDiskVolume>? volumes,
final LoadingStatus? status,
}) =>
ApiServerVolumeState(
volumes ?? _volumes,
status ?? this.status,
);
@override
List<Object?> get props => [_volumes];
}

View File

@ -1,160 +0,0 @@
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_factory_creator.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/server_provider_factory.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';
import 'package:selfprivacy/logic/models/json/server_disk_volume.dart';
part 'volumes_state.dart';
class ApiVolumesCubit
extends ServerInstallationDependendCubit<ApiVolumesState> {
ApiVolumesCubit(final ServerInstallationCubit serverInstallationCubit)
: super(serverInstallationCubit, const ApiVolumesState.initial()) {
final serverDetails = getIt<ApiConfigModel>().serverDetails;
providerApi = serverDetails == null
? null
: VolumeApiFactoryCreator.createVolumeProviderApiFactory(
getIt<ApiConfigModel>().serverDetails!.provider,
);
}
VolumeProviderApiFactory? providerApi;
@override
Future<void> load() async {
if (serverInstallationCubit.state is ServerInstallationFinished) {
_refetch();
}
}
Future<List<ServerVolume>> getVolumes() async {
if (providerApi == null) {
return [];
}
return providerApi!.getVolumeProvider().getVolumes();
}
Future<double?> getPricePerGb() async =>
providerApi!.getVolumeProvider().getPricePerGb();
Future<void> refresh() async {
emit(const ApiVolumesState([], LoadingStatus.refreshing));
_refetch();
}
Future<void> _refetch() async {
final List<ServerVolume> volumes = await getVolumes();
if (volumes.isNotEmpty) {
emit(ApiVolumesState(volumes, LoadingStatus.success));
} else {
emit(const ApiVolumesState([], LoadingStatus.error));
}
}
Future<void> attachVolume(final ServerVolume volume) async {
final ServerHostingDetails server = getIt<ApiConfigModel>().serverDetails!;
await providerApi!.getVolumeProvider().attachVolume(volume.id, server.id);
refresh();
}
Future<void> detachVolume(final ServerVolume volume) async {
await providerApi!.getVolumeProvider().detachVolume(volume.id);
refresh();
}
Future<bool> resizeVolume(
final ServerDiskVolume volume,
final int newSizeGb,
) async {
final ServerVolume? providerVolume = await fetchProdiverVolume(volume);
final bool resized = await providerApi!.getVolumeProvider().resizeVolume(
providerVolume!.id,
newSizeGb,
);
if (!resized) {
return false;
}
await ServerApi().resizeVolume(volume.name);
refresh();
return true;
}
Future<void> createVolume() async {
final ServerVolume? volume =
await providerApi!.getVolumeProvider().createVolume();
await attachVolume(volume!);
await Future.delayed(const Duration(seconds: 10));
final ServerDiskVolume? diskVolume = await fetchServerDiskVolume(volume);
await ServerApi().mountVolume(diskVolume!.name);
refresh();
}
Future<void> deleteVolume(final ServerDiskVolume volume) async {
final ServerVolume? providerVolume = await fetchProdiverVolume(volume);
await providerApi!.getVolumeProvider().deleteVolume(providerVolume!.id);
refresh();
}
@override
void clear() {
emit(const ApiVolumesState.initial());
}
Future<ServerVolume?> fetchProdiverVolume(
final ServerDiskVolume volume,
) async {
ServerVolume? fetchedVolume;
final List<ServerVolume> volumes =
await providerApi!.getVolumeProvider().getVolumes();
for (final ServerVolume providerVolume in volumes) {
if (providerVolume.linuxDevice == null) {
continue;
}
final String deviceId = providerVolume.linuxDevice!.split('/').last;
if (deviceId.contains(volume.model!) &&
deviceId.contains(volume.serial!)) {
fetchedVolume = providerVolume;
break;
}
}
return fetchedVolume;
}
Future<ServerDiskVolume?> fetchServerDiskVolume(
final ServerVolume volume,
) async {
ServerDiskVolume? fetchedVolume;
if (volume.linuxDevice == null) {
return fetchedVolume;
}
final List<ServerDiskVolume> volumes =
await ServerApi().getServerDiskVolumes();
for (final ServerDiskVolume serverDiskVolumes in volumes) {
if (serverDiskVolumes.model == null || serverDiskVolumes.serial == null) {
continue;
}
final String deviceId = volume.linuxDevice!.split('/').last;
if (deviceId.contains(serverDiskVolumes.model!) &&
deviceId.contains(serverDiskVolumes.serial!)) {
fetchedVolume = serverDiskVolumes;
break;
}
}
return fetchedVolume;
}
}

View File

@ -1,23 +0,0 @@
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];
}

View File

@ -5,7 +5,8 @@ import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart';
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
import 'package:selfprivacy/logic/cubit/providers/providers_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/volumes/volumes_cubit.dart';
import 'package:selfprivacy/logic/cubit/provider_volumes/provider_volume_cubit.dart';
import 'package:selfprivacy/logic/cubit/server_volumes/server_volume_cubit.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart';
import 'package:selfprivacy/logic/models/json/server_disk_volume.dart';
@ -76,22 +77,10 @@ class _ProvidersPageState extends State<ProvidersPage> {
cards.add(
Padding(
padding: const EdgeInsets.only(bottom: 30),
child: FutureBuilder(
future: Future.wait([
context.read<ServerInstallationCubit>().getServerDiskVolumes(),
context.read<ApiVolumesCubit>().getVolumes(),
]),
builder: (
final BuildContext context,
final AsyncSnapshot<List<dynamic>> snapshot,
) =>
StorageCard(
diskStatus: snapshot.hasData
? toDiskStatus(
snapshot.data![0] as List<ServerDiskVolume>,
snapshot.data![1] as List<ServerVolume>,
)
: DiskStatus(),
child: StorageCard(
diskStatus: toDiskStatus(
context.read<ApiServerVolumeCubit>().state.volumes,
context.read<ApiProviderVolumeCubit>().state.volumes,
),
),
),

View File

@ -1,7 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
import 'package:selfprivacy/logic/cubit/volumes/volumes_cubit.dart';
import 'package:selfprivacy/logic/cubit/provider_volumes/provider_volume_cubit.dart';
import 'package:selfprivacy/logic/models/disk_size.dart';
import 'package:selfprivacy/ui/components/brand_button/filled_button.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
@ -39,7 +39,7 @@ class _ExtendingVolumePageState extends State<ExtendingVolumePage> {
@override
Widget build(final BuildContext context) => FutureBuilder(
future: context.read<ApiVolumesCubit>().getPricePerGb(),
future: context.read<ApiProviderVolumeCubit>().getPricePerGb(),
builder: (
final BuildContext context,
final AsyncSnapshot<void> snapshot,

View File

@ -0,0 +1,56 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/ui/components/brand_linear_indicator/brand_linear_indicator.dart';
class ServiceStorageConsumptionListItem extends StatelessWidget {
const ServiceStorageConsumptionListItem({
required this.title,
required this.percentage,
required this.storageConsumptionText,
required this.color,
required this.icon,
final super.key,
});
final String title;
final double percentage;
final String storageConsumptionText;
final Color color;
final IconData icon;
@override
Widget build(final BuildContext context) => Row(
children: [
Icon(
icon,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: Theme.of(context).textTheme.titleMedium,
),
Text(
storageConsumptionText,
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
const SizedBox(height: 4),
BrandLinearIndicator(
value: percentage,
color: color,
backgroundColor: Theme.of(context).colorScheme.surfaceVariant,
height: 7.0,
),
],
),
),
],
);
}