From da073b7454415b6abbaff570e13019ebe66ee026 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Tue, 23 Jul 2024 19:56:40 +0300 Subject: [PATCH] fix: Do not remove all DNS records if server connection failed --- assets/translations/en.json | 2 + .../cubit/client_jobs/client_jobs_cubit.dart | 112 ++++++++++++------ .../get_it/api_connection_repository.dart | 1 + .../basic_string_config_item.dart | 5 +- 4 files changed, 84 insertions(+), 36 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 48dc65a0..be110df9 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -609,6 +609,8 @@ "update_dns_records": "Update DNS records", "dns_records_did_not_change": "No changes needed", "dns_records_changed": "DNS records updated", + "failed_to_load_dns_records": "Failed to load DNS records", + "ignored_due_to_failures": "Ignored due to previous failures", "change_service_settings": "Change service settings for {}" }, "validations": { diff --git a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart index 14ea6670..a9e2b065 100644 --- a/lib/logic/cubit/client_jobs/client_jobs_cubit.dart +++ b/lib/logic/cubit/client_jobs/client_jobs_cubit.dart @@ -149,6 +149,10 @@ class JobsCubit extends Cubit { await getIt().api.getDnsRecords(); for (final ClientJob job in jobs) { + if (job is UpdateDnsRecordsJob) { + continue; + } + emit( (state as JobsStateLoading) .updateJobStatus(job.id, JobStatusEnum.running), @@ -170,48 +174,30 @@ class JobsCubit extends Cubit { } } - if (dnsUpdateRequired) { - emit( - (state as JobsStateLoading).updateJobStatus( - UpdateDnsRecordsJob.jobId, - JobStatusEnum.running, - ), - ); - final List newDnsRecords = - await getIt().api.getDnsRecords(); + await Future.delayed(Duration.zero); - if (const UnorderedIterableEquality() - .equals(oldDnsRecords, newDnsRecords)) { + // If all jobs failed, do not try to change DNS records or rebuild the server + if ((state as JobsStateLoading).clientJobList.every( + (final job) => + (job.status == JobStatusEnum.error) || + (job is UpdateDnsRecordsJob), + )) { + if (dnsUpdateRequired) { emit( (state as JobsStateLoading).updateJobStatus( UpdateDnsRecordsJob.jobId, - JobStatusEnum.finished, - message: 'jobs.dns_records_did_not_change'.tr(), - ), - ); - } else { - final ServerDomain? domain = - getIt().serverDomain; - - final dnsCreateResult = - await ProvidersController.currentDnsProvider!.updateDnsRecords( - newRecords: - newDnsRecords.where((final r) => r.content != null).toList(), - oldRecords: oldDnsRecords, - domain: domain!, - ); - - emit( - (state as JobsStateLoading).updateJobStatus( - UpdateDnsRecordsJob.jobId, - dnsCreateResult.success - ? JobStatusEnum.finished - : JobStatusEnum.error, - message: - dnsCreateResult.message ?? 'jobs.dns_records_changed'.tr(), + JobStatusEnum.error, + message: 'jobs.ignored_due_to_failures'.tr(), ), ); + await Future.delayed(Duration.zero); } + emit((state as JobsStateLoading).finished()); + return; + } + + if (dnsUpdateRequired) { + await updateDnsRecords(oldDnsRecords); } if (!rebuildRequired) { @@ -234,6 +220,62 @@ class JobsCubit extends Cubit { } } + Future updateDnsRecords(final List oldDnsRecords) async { + emit( + (state as JobsStateLoading).updateJobStatus( + UpdateDnsRecordsJob.jobId, + JobStatusEnum.running, + ), + ); + final List newDnsRecords = + await getIt().api.getDnsRecords(); + + // If any of the records have a null content, we don't want to update + // the DNS records + if (newDnsRecords.isEmpty || oldDnsRecords.isEmpty) { + emit( + (state as JobsStateLoading).updateJobStatus( + UpdateDnsRecordsJob.jobId, + JobStatusEnum.error, + message: 'jobs.failed_to_load_dns_records'.tr(), + ), + ); + return; + } + + if (const UnorderedIterableEquality() + .equals(oldDnsRecords, newDnsRecords)) { + emit( + (state as JobsStateLoading).updateJobStatus( + UpdateDnsRecordsJob.jobId, + JobStatusEnum.finished, + message: 'jobs.dns_records_did_not_change'.tr(), + ), + ); + } else { + final ServerDomain? domain = + getIt().serverDomain; + + final dnsCreateResult = + await ProvidersController.currentDnsProvider!.updateDnsRecords( + newRecords: + newDnsRecords.where((final r) => r.content != null).toList(), + oldRecords: oldDnsRecords, + domain: domain!, + ); + + emit( + (state as JobsStateLoading).updateJobStatus( + UpdateDnsRecordsJob.jobId, + dnsCreateResult.success + ? JobStatusEnum.finished + : JobStatusEnum.error, + message: dnsCreateResult.message ?? 'jobs.dns_records_changed'.tr(), + ), + ); + } + } + Future collectNixGarbage() async { if (state is JobsStateEmpty) { emit( diff --git a/lib/logic/get_it/api_connection_repository.dart b/lib/logic/get_it/api_connection_repository.dart index 22edb7d9..7cce96ae 100644 --- a/lib/logic/get_it/api_connection_repository.dart +++ b/lib/logic/get_it/api_connection_repository.dart @@ -248,6 +248,7 @@ class ApiConnectionRepository { ) async { final GenericResult result = await api.setServiceConfiguration(serviceId, settings); + _apiData.services.invalidate(); if (result.success) { return (true, result.message ?? 'basis.done'.tr()); } else { diff --git a/lib/ui/pages/services/config_item_fields/basic_string_config_item.dart b/lib/ui/pages/services/config_item_fields/basic_string_config_item.dart index a14e059c..79c53ea6 100644 --- a/lib/ui/pages/services/config_item_fields/basic_string_config_item.dart +++ b/lib/ui/pages/services/config_item_fields/basic_string_config_item.dart @@ -28,7 +28,10 @@ class _BasicStringConfigItemState extends State { final String value = _controller.text; final bool isValid = _validateInput(value); if (isValid) { - widget.onChanged(value, isValid); + setState(() { + widget.onChanged(value, isValid); + _isValid = isValid; + }); } else { setState(() { widget.onChanged(widget.newValue ?? widget.configItem.value, isValid);