fix: force rediscover on manual reconnect
This commit is contained in:
+6
-2
@@ -551,8 +551,12 @@ class _MainAppState extends State<MainApp> with WidgetsBindingObserver {
|
||||
: const Duration(minutes: 2);
|
||||
if (now.difference(_lastResumeProbe) >= cooldown) {
|
||||
_lastResumeProbe = now;
|
||||
_serverManager.checkServerHealth();
|
||||
_serverManager.reconnectOfflineServers();
|
||||
// Await health check before reconnecting so stale "online" servers
|
||||
// get marked offline and included in the reconnection sweep.
|
||||
unawaited(() async {
|
||||
await _serverManager.checkServerHealth();
|
||||
await _serverManager.reconnectOfflineServers();
|
||||
}());
|
||||
}
|
||||
case AppLifecycleState.paused:
|
||||
case AppLifecycleState.detached:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io' show Platform, exit;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -589,13 +590,16 @@ class _MainScreenState extends State<MainScreen> with RouteAware, WindowListener
|
||||
setState(() => _isReconnecting = true);
|
||||
|
||||
final serverManager = context.read<MultiServerProvider>().serverManager;
|
||||
serverManager.checkServerHealth();
|
||||
serverManager.reconnectOfflineServers().whenComplete(() {
|
||||
// Give a moment for status updates to propagate
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
unawaited(() async {
|
||||
try {
|
||||
// Health check first so stale "online" servers get marked offline before
|
||||
// we snapshot the offline list for reconnection.
|
||||
await serverManager.checkServerHealth();
|
||||
await serverManager.reconnectOfflineServers(forceRediscovery: true);
|
||||
} finally {
|
||||
if (mounted) setState(() => _isReconnecting = false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
||||
void _handleLiveTvChanged() {
|
||||
|
||||
@@ -492,12 +492,17 @@ class MultiServerManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt reconnection for all offline servers
|
||||
Future<void> reconnectOfflineServers() async {
|
||||
/// Attempt reconnection for all offline servers.
|
||||
///
|
||||
/// When [forceRediscovery] is true, the cached endpoint is cleared before
|
||||
/// reconnecting so the fast-path is skipped and a full candidate race runs.
|
||||
/// Used by the manual reconnect button when the cached URL may be stale
|
||||
/// (e.g. after a network change while the app was backgrounded).
|
||||
Future<void> reconnectOfflineServers({bool forceRediscovery = false}) async {
|
||||
// Coalesce concurrent calls — return the in-flight future if one exists
|
||||
if (_activeReconnect != null) return _activeReconnect!;
|
||||
|
||||
_activeReconnect = _doReconnectOfflineServers();
|
||||
_activeReconnect = _doReconnectOfflineServers(forceRediscovery: forceRediscovery);
|
||||
try {
|
||||
await _activeReconnect;
|
||||
} finally {
|
||||
@@ -505,13 +510,18 @@ class MultiServerManager {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _doReconnectOfflineServers() async {
|
||||
Future<void> _doReconnectOfflineServers({required bool forceRediscovery}) async {
|
||||
final offline = offlineServerIds;
|
||||
if (offline.isEmpty) return;
|
||||
|
||||
appLogger.d('Attempting reconnection for ${offline.length} offline servers');
|
||||
Sentry.addBreadcrumb(Breadcrumb(message: 'Reconnecting ${offline.length} offline server(s)', category: 'servers'));
|
||||
|
||||
if (forceRediscovery) {
|
||||
final storage = await StorageService.getInstance();
|
||||
await Future.wait(offline.map(storage.clearServerEndpoint));
|
||||
}
|
||||
|
||||
final futures = offline.map((serverId) {
|
||||
final server = _servers[serverId];
|
||||
if (server == null) return Future<void>.value();
|
||||
|
||||
@@ -238,7 +238,7 @@ class PlexClient {
|
||||
'Switching Plex endpoint after GET failure',
|
||||
error: {'from': failedEndpoint, 'to': nextBaseUrl, 'path': path},
|
||||
);
|
||||
await _handleEndpointSwitch(nextBaseUrl);
|
||||
await _handleEndpointSwitch(nextBaseUrl, persist: false);
|
||||
final response = await _http.get(
|
||||
path,
|
||||
queryParameters: queryParameters,
|
||||
@@ -247,6 +247,7 @@ class PlexClient {
|
||||
abort: abort,
|
||||
);
|
||||
appLogger.i('Endpoint failover retry succeeded', error: {'newEndpoint': nextBaseUrl});
|
||||
await _onEndpointChanged?.call(nextBaseUrl);
|
||||
return response;
|
||||
} finally {
|
||||
_failoverSwitching = false;
|
||||
@@ -2887,7 +2888,7 @@ class PlexClient {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _handleEndpointSwitch(String newBaseUrl) async {
|
||||
Future<void> _handleEndpointSwitch(String newBaseUrl, {bool persist = true}) async {
|
||||
if (config.baseUrl == newBaseUrl) {
|
||||
return;
|
||||
}
|
||||
@@ -2897,7 +2898,7 @@ class PlexClient {
|
||||
config = config.copyWith(baseUrl: newBaseUrl);
|
||||
LogRedactionManager.registerServerUrl(newBaseUrl);
|
||||
|
||||
if (_onEndpointChanged != null) {
|
||||
if (persist && _onEndpointChanged != null) {
|
||||
await _onEndpointChanged(newBaseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user