From 4acb6c74c317131484734833d2d0359ceca9061d Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 3 May 2023 10:58:31 -0500 Subject: [PATCH] handle connectivity fails (like nm being unavail on build server) more gracefully --- lib/main.dart | 75 ++++++++++++++----- .../nm/src/network_manager_client.dart | 12 +++ pubspec.yaml | 1 + 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 9515f33a..4f3ac855 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,7 +65,7 @@ class FlwtchState extends State with WindowListener { final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler'); final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler'); final MethodChannel shutdownLinuxMethodChannel = MethodChannel('im.cwtch.linux.shutdown'); - late StreamSubscription connectivityStream; + late StreamSubscription? connectivityStream; ConnectivityState connectivityState = ConnectivityState.assumed_online; final GlobalKey navKey = GlobalKey(); @@ -95,35 +95,74 @@ class FlwtchState extends State with WindowListener { shutdownLinuxMethodChannel.setMethodCallHandler(shutdownDirect); print("initState: creating cwtchnotifier, ffi"); if (Platform.isAndroid) { - var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState, globalServersList, this); + var cwtchNotifier = new CwtchNotifier( + profs, + globalSettings, + globalErrorHandler, + globalTorStatus, + NullNotificationsManager(), + globalAppState, + globalServersList, + this); cwtch = CwtchGomobile(cwtchNotifier); } else if (Platform.isLinux) { var cwtchNotifier = - new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); + new CwtchNotifier( + profs, + globalSettings, + globalErrorHandler, + globalTorStatus, + newDesktopNotificationsManager(_notificationSelectConvo), + globalAppState, + globalServersList, + this); cwtch = CwtchFfi(cwtchNotifier); } else { var cwtchNotifier = - new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(_notificationSelectConvo), globalAppState, globalServersList, this); + new CwtchNotifier( + profs, + globalSettings, + globalErrorHandler, + globalTorStatus, + newDesktopNotificationsManager(_notificationSelectConvo), + globalAppState, + globalServersList, + this); cwtch = CwtchFfi(cwtchNotifier); } - connectivityStream = Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { - // Got a new connectivity status! - if (result == ConnectivityResult.none) { - connectivityState = ConnectivityState.confirmed_offline; - } else { - // were we offline? - if (connectivityState == ConnectivityState.confirmed_offline) { - EnvironmentConfig.debugLog("Network appears to have come back online, restarting Tor"); - cwtch.ResetTor(); - } - connectivityState = ConnectivityState.confirmed_online; - } - }); + startConnectivityListener(); print("initState: invoking cwtch.Start()"); cwtch.Start(); print("initState: done!"); } + // connectivity listening is an optional enhancement feature that tries to listen for OS events about the network + // and if it detects coming back online, restarts the ACN/tor + // gracefully fails and NOPs, as it's not a required functionality + startConnectivityListener() async { + try { + connectivityStream = await Connectivity().onConnectivityChanged.listen((ConnectivityResult result) { + // Got a new connectivity status! + if (result == ConnectivityResult.none) { + connectivityState = ConnectivityState.confirmed_offline; + } else { + // were we offline? + if (connectivityState == ConnectivityState.confirmed_offline) { + EnvironmentConfig.debugLog("Network appears to have come back online, restarting Tor"); + cwtch.ResetTor(); + } + connectivityState = ConnectivityState.confirmed_online; + } + }, onError: (Object error) { + print("Error listening to connectivity for network state: {$error}"); + return null; + }, cancelOnError: true); + } catch (e) { + print("Warning: Unable to open connectivity for listening to network state: {$e}"); + connectivityStream = null; + } + } + ChangeNotifierProvider getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus); ChangeNotifierProvider getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler); ChangeNotifierProvider getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings); @@ -295,7 +334,7 @@ class FlwtchState extends State with WindowListener { cwtch.Shutdown(); windowManager.removeListener(this); cwtch.dispose(); - connectivityStream.cancel(); + connectivityStream?.cancel(); super.dispose(); } } diff --git a/lib/third_party/nm/src/network_manager_client.dart b/lib/third_party/nm/src/network_manager_client.dart index d9b9ff19..222c94bf 100644 --- a/lib/third_party/nm/src/network_manager_client.dart +++ b/lib/third_party/nm/src/network_manager_client.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:dbus/dbus.dart'; @@ -314,6 +315,17 @@ class NetworkManagerClient { return; } + // Big old grody Hack + // DBus/nm doesnt seem to offer a way to deter ine if dbus is available on system + // worse the first connections get triggered in dbus_client onListen an isn't a catahable exception so crashes the app + // this is a hacky way to force an exception on thread if dbus isn't available and bail with out crashing + try { + await _root.client.getNameOwner(_root.name); + } on SocketException catch (e) { + print("nm dbus connect/emit test threw exception, dbus likely unavailable on system, aborting connect: $e"); + return; + } + // Subscribe to changes _objectManagerSubscription = _root.signals.listen((signal) { if (signal is DBusObjectManagerInterfacesAddedSignal) { diff --git a/pubspec.yaml b/pubspec.yaml index aa609ea0..bdcf7027 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,6 +32,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.0 + # Todo: upgrade to 2.x, allow other package upgrades (dbus) ffi: ^1.2.1 path_provider: ^2.0.0 crypto: ^3.0.2