From 0d2f7b25a371aa079b7e0581bb2e38e9b87e63cb Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Mon, 14 Jul 2025 00:11:21 +0200 Subject: [PATCH] Added service restart --- sbapp/main.py | 76 +++++++++++++++++++++++++++++-- sbapp/services/sidebandservice.py | 3 ++ sbapp/ui/layouts.py | 17 +++++++ 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/sbapp/main.py b/sbapp/main.py index 69658a0..a238ad4 100644 --- a/sbapp/main.py +++ b/sbapp/main.py @@ -461,6 +461,67 @@ class SidebandApp(MDApp): argument = self.app_dir self.android_service.start(mActivity, argument) + def stop_service(self): + RNS.log("Stopping service...") + self.sideband.setstate("wants.service_stop", True) + while self.sideband.service_available(): time.sleep(0.2) + RNS.log("Service stopped") + + def restart_service_action(self, sender): + if hasattr(self, "service_restarting") and self.service_restarting == True: + toast(f"Service restart already in progress") + else: + toast(f"Restarting RNS service...") + if hasattr(self, "connectivity_screen") and self.connectivity_screen != None: + self.connectivity_screen.ids.button_service_restart.disabled = True + def job(): + if self.restart_service(): + def tj(delta_time): + toast(f"Service restarted successfully!") + if hasattr(self, "connectivity_screen") and self.connectivity_screen != None: + self.connectivity_screen.ids.button_service_restart.disabled = False + Clock.schedule_once(tj, 0.1) + else: + def tj(delta_time): + toast(f"Service restart failed") + if hasattr(self, "connectivity_screen") and self.connectivity_screen != None: + self.connectivity_screen.ids.button_service_restart.disabled = False + Clock.schedule_once(tj, 0.1) + + threading.Thread(target=job, daemon=True).start() + + def restart_service(self): + if hasattr(self, "service_restarting") and self.service_restarting == True: + return False + else: + self.service_restarting = True + self.stop_service() + RNS.log("Waiting for service shutdown", RNS.LOG_DEBUG) + while self.sideband.service_rpc_request({"getstate": "service.heartbeat"}): + time.sleep(1) + time.sleep(4) + + self.final_load_completed = False + self.sideband.service_stopped = True + + RNS.log("Starting service...", RNS.LOG_DEBUG) + self.start_service() + RNS.log("Waiting for service restart...", RNS.LOG_DEBUG) + restart_timeout = time.time() + 45 + while not self.sideband.service_rpc_request({"getstate": "service.heartbeat"}): + self.sideband.rpc_connection = None + time.sleep(1) + if time.time() > restart_timeout: + service_restarting = False + return False + + RNS.log("Service restarted", RNS.LOG_DEBUG) + self.sideband.service_stopped = False + self.final_load_completed = True + self.service_restarting = False + + return True + def start_final(self): # Start local core instance self.sideband.start() @@ -1098,19 +1159,28 @@ class SidebandApp(MDApp): description = rnode_errors["description"] self.sideband.setpersistent("runtime.errors.rnode", None) yes_button = MDRectangleFlatButton( - text="OK", + text="Ignore", + font_size=dp(18), + ) + restart_button = MDRectangleFlatButton( + text="Restart RNS", font_size=dp(18), ) self.hw_error_dialog = MDDialog( title="Hardware Error", text="While communicating with an RNode, Reticulum reported the following error:\n\n[i]"+str(description)+"[/i]", - buttons=[ yes_button ], + buttons=[ yes_button, restart_button ], # elevation=0, ) def dl_yes(s): self.hw_error_dialog.dismiss() self.hw_error_dialog.is_open = False + def dl_restart(s): + self.hw_error_dialog.dismiss() + self.hw_error_dialog.is_open = False + self.restart_service_action(None) yes_button.bind(on_release=dl_yes) + restart_button.bind(on_release=dl_restart) self.hw_error_dialog.open() self.hw_error_dialog.is_open = True @@ -3659,7 +3729,7 @@ class SidebandApp(MDApp): else: info = "By default, Sideband will try to discover and connect to any available Reticulum networks via active WiFi and/or Ethernet interfaces. If any Reticulum Transport Instances are found, Sideband will use these to connect to wider Reticulum networks. You can disable this behaviour if you don't want it.\n\n" info += "You can also connect to a network via a remote or local Reticulum instance using TCP or I2P. [b]Please Note![/b] Connecting via I2P requires that you already have I2P running on your device, and that the SAM API is enabled.\n\n" - info += "For changes to connectivity to take effect, you must shut down and restart Sideband.\n" + info += "For changes to connectivity to take effect, you must either restart the RNS service, or completely shut down and restart Sideband.\n" self.connectivity_screen.ids.connectivity_info.text = info self.connectivity_screen.ids.connectivity_use_local.active = self.sideband.config["connect_local"] diff --git a/sbapp/services/sidebandservice.py b/sbapp/services/sidebandservice.py index e718a6f..814c2b6 100644 --- a/sbapp/services/sidebandservice.py +++ b/sbapp/services/sidebandservice.py @@ -481,6 +481,9 @@ class SidebandService(): self.sideband.cleanup() self.release_locks() + # TODO: Check if this works in all cases + self.android_service.stopSelf() + def handle_exception(exc_type, exc_value, exc_traceback): if issubclass(exc_type, KeyboardInterrupt): sys.__excepthook__(exc_type, exc_value, exc_traceback) diff --git a/sbapp/ui/layouts.py b/sbapp/ui/layouts.py index 2f27bb7..fc4d9e0 100644 --- a/sbapp/ui/layouts.py +++ b/sbapp/ui/layouts.py @@ -360,6 +360,23 @@ MDScreen: text_size: self.width, None height: self.texture_size[1] + MDBoxLayout: + id: connectivity_shared_access_fields + orientation: "vertical" + size_hint_y: None + height: self.minimum_height + padding: [0, 0, 0, dp(32)] + + MDRectangleFlatIconButton: + id: button_service_restart + icon: "restart" + text: "Restart RNS Service" + padding: [dp(0), dp(14), dp(0), dp(14)] + icon_size: dp(24) + font_size: dp(16) + size_hint: [1.0, None] + on_release: root.app.restart_service_action(self) + MDBoxLayout: orientation: "horizontal" padding: [0,0,dp(24),0]