feat(extension-health): cache results, force refresh, treat lookup errors as transient

Cache health results after each check, add a force flag to bypass the cache when the download picker opens or a service is selected, guard stale concurrent results via a per-extension request serial, and treat DNS lookup failures as indeterminate/transient.
This commit is contained in:
zarzet
2026-06-28 06:05:48 +07:00
parent 21fe047e00
commit ce813bc216
4 changed files with 68 additions and 28 deletions
+16 -3
View File
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -74,7 +75,9 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
ref.read(extensionProvider.notifier).refreshEnabledExtensionHealth();
ref
.read(extensionProvider.notifier)
.refreshEnabledExtensionHealth(force: true);
});
final downloadExtensions = _downloadExtensions();
final recommended = widget.recommendedService;
@@ -102,6 +105,17 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
return const [];
}
void _selectService(Extension extension) {
setState(() => _selectedService = extension.id);
if (extension.hasServiceHealth) {
unawaited(
ref
.read(extensionProvider.notifier)
.checkExtensionHealth(extension.id, force: true),
);
}
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
@@ -166,8 +180,7 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
? extensionState.healthStatuses[ext.id]?.status
: null,
isSelected: _selectedService == ext.id,
onTap: () =>
setState(() => _selectedService = ext.id),
onTap: () => _selectService(ext),
iconPath: ext.iconPath,
),
],