discoverMirrors method
Discover all mirrors and their availability at runtime.
This is optimized for runtime use - it only probes each mirror for the first available snapshot (starting from today and going back). This avoids excessive network requests while still determining which mirrors are operational.
Returns a list of MirrorDiscoveryResult with status for each mirror.
Implementation
Future<List<MirrorDiscoveryResult>> discoverMirrors() async {
// Generate candidate snapshots starting from today
final candidates = generateCandidateVersions(daysToProbe: 30);
final results = <MirrorDiscoveryResult>[];
// Probe all mirrors in parallel for efficiency
await Future.wait(
mirrors.map((mirror) async {
String? latestSnapshot;
String? error;
final stopwatch = Stopwatch()..start();
try {
// First check base URL accessibility
final response = await _client
.head(Uri.parse(mirror.baseUrl))
.timeout(const Duration(seconds: 5));
stopwatch.stop();
final isAccessible = response.statusCode == 200 ||
response.statusCode == 301 ||
response.statusCode == 302;
mirror.latencyMs = stopwatch.elapsedMilliseconds;
mirror.isAvailable = isAccessible;
if (isAccessible) {
// Find the first available snapshot (newest first)
// Only check a few candidates to minimize requests
for (final version in candidates.take(14)) {
final testUrl = utils.MirrorService.buildDownloadUrl(
mirror.baseUrl, version, 'countries.txt');
try {
final snapResponse = await _client
.head(Uri.parse(testUrl))
.timeout(const Duration(seconds: 2));
if (snapResponse.statusCode == 200) {
latestSnapshot = version;
break;
}
} catch (_) {
// Continue to next snapshot
}
}
if (latestSnapshot == null) {
error = 'No snapshots available';
mirror.isAvailable = false;
}
} else {
error = 'Server not accessible (HTTP ${response.statusCode})';
}
} catch (e) {
stopwatch.stop();
mirror.latencyMs = null;
mirror.isAvailable = false;
error = 'Connection failed: ${e.toString().split(':').first}';
}
results.add(MirrorDiscoveryResult(
mirror: mirror,
latestSnapshot: latestSnapshot != null
? utils.Snapshot(version: latestSnapshot)
: null,
error: error,
));
}),
);
// Sort by: available first, then by latency
results.sort((a, b) {
if (a.isOperational && !b.isOperational) return -1;
if (!a.isOperational && b.isOperational) return 1;
final latencyA = a.mirror.latencyMs ?? 999999;
final latencyB = b.mirror.latencyMs ?? 999999;
return latencyA.compareTo(latencyB);
});
return results;
}