From a366e8ff399fe399a6dade708edbdfac5fe505f9 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Mon, 24 Nov 2025 21:24:10 +1300 Subject: [PATCH] add ability to enable/disable telephone --- meshchat.py | 59 ++++++++++++++++++++++++++++++--- src/frontend/components/App.vue | 54 +++++++++++++++++++++++++----- 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/meshchat.py b/meshchat.py index 0bd4ae0..527a20d 100644 --- a/meshchat.py +++ b/meshchat.py @@ -153,10 +153,10 @@ class ReticulumMeshChat: self.audio_call_manager = AudioCallManager(identity=self.identity) self.audio_call_manager.register_incoming_call_callback(self.on_incoming_audio_call) - # init telephone - # todo check if user wants to enable telephone + # init telephone if enabled self.telephone = None - self.init_telephone() + if self.config.telephone_enabled.get(): + self.init_telephone() # start background thread for auto announce loop thread = threading.Thread(target=asyncio.run, args=(self.announce_loop(),)) @@ -175,6 +175,32 @@ class ReticulumMeshChat: self.telephone.set_established_callback(self.on_telephone_call_established) self.telephone.set_ended_callback(self.on_telephone_call_ended) + # enable telephone + def enable_telephone(self): + + # mark as enabled in config + self.config.telephone_enabled.set(True) + + # do nothing if already enabled + if self.telephone is not None: + return + + # start instance + self.init_telephone() + + # disable telephone + def disable_telephone(self): + + # teardown telephone instance + if self.telephone is not None: + AsyncUtils.run_async(asyncio.to_thread(self.telephone.teardown)) + + # mark as disabled in config + self.config.telephone_enabled.set(False) + + # clear instance + self.telephone = None + # handle receiving a new telephone call def on_telephone_ringing(self, caller_identity: RNS.Identity): print("on_telephone_ringing: {}".format(caller_identity.hash.hex())) @@ -344,6 +370,22 @@ class ReticulumMeshChat: "status": "ok", }) + # enable telephone + @routes.get("/api/v1/telephone/enable") + async def index(request): + self.enable_telephone() + return web.json_response({ + "message": "Telephone has been enabled.", + }) + + # disable telephone + @routes.get("/api/v1/telephone/disable") + async def index(request): + self.disable_telephone() + return web.json_response({ + "message": "Telephone has been disabled.", + }) + # serve telephone status @routes.get("/api/v1/telephone/status") async def index(request): @@ -351,8 +393,9 @@ class ReticulumMeshChat: # make sure telephone is enabled if self.telephone is None: return web.json_response({ + "enabled": False, "message": "Telephone is disabled", - }, status=503) + }) # get active call info active_call = None @@ -381,6 +424,7 @@ class ReticulumMeshChat: } return web.json_response({ + "enabled": True, "is_busy": self.telephone.busy, "call_status": self.telephone.call_status, "active_call": active_call, @@ -412,6 +456,12 @@ class ReticulumMeshChat: @routes.get("/api/v1/telephone/call/{identity_hash}") async def index(request): + # make sure telephone enabled + if self.telephone is None: + return web.json_response({ + "message": "Telephone has been disabled.", + }, status=503) + # get path params identity_hash_hex = request.match_info.get("identity_hash", "") timeout_seconds = int(request.query.get("timeout", 15)) @@ -3653,6 +3703,7 @@ class Config: lxmf_user_icon_name = StringConfig("lxmf_user_icon_name", None) lxmf_user_icon_foreground_colour = StringConfig("lxmf_user_icon_foreground_colour", None) lxmf_user_icon_background_colour = StringConfig("lxmf_user_icon_background_colour", None) + telephone_enabled = BoolConfig("telephone_enabled", True) # FIXME: we should probably set this as an instance variable of ReticulumMeshChat so it has a proper home, and pass it in to the constructor? nomadnet_cached_links = {} diff --git a/src/frontend/components/App.vue b/src/frontend/components/App.vue index 3f8d5e7..86ebd52 100644 --- a/src/frontend/components/App.vue +++ b/src/frontend/components/App.vue @@ -247,12 +247,16 @@ -
Calls
-
-
+
+
+
Status
+
Disabled
+
+
+
Active Call @@ -277,7 +287,7 @@ dark:bg-zinc-800 dark:text-white dark:hover:bg-zinc-700 dark:focus-visible:outli Unknown Caller
-
Hung up, waiting for call...
+
Available. Waiting for call...
@@ -342,6 +352,7 @@ export default { config: null, appInfo: null, + telephoneEnabled: false, activeCall: null, propagationNodeStatus: null, @@ -540,6 +551,7 @@ export default { const response = await axios.get("/api/v1/telephone/status"); // update ui + this.telephoneEnabled = response.data.enabled; this.activeCall = response.data.active_call; } catch(e) { @@ -572,6 +584,32 @@ export default { // ignore error hanging up call } }, + async enableTelephone() { + try { + + // enable telephone + await axios.get(`/api/v1/telephone/enable`); + + // update ui + await this.getTelephoneStatus(); + + } catch(e) { + // ignore error + } + }, + async disableTelephone() { + try { + + // disable telephone + await axios.get(`/api/v1/telephone/disable`); + + // update ui + await this.getTelephoneStatus(); + + } catch(e) { + // ignore error + } + }, onAppNameClick() { // user may be on mobile, and is unable to scroll back to sidebar, so let them tap app name to do it this.$refs["middle"].scrollTo({