From 97edf22efb556630a85d33c7b52c077a807b57aa Mon Sep 17 00:00:00 2001 From: pe1hvh Date: Thu, 12 Mar 2026 16:00:26 +0100 Subject: [PATCH] HotFixRoomServer --- CHANGELOG.md | 57 ++++++++++++++++-------------------- meshcore_gui/ble/commands.py | 1 + meshcore_gui/ble/events.py | 17 +++++++---- meshcore_gui/ble/worker.py | 12 ++++++++ meshcore_gui/config.py | 2 +- 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2c9131..e79ede2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,28 @@ # CHANGELOG - - All notable changes to MeshCore GUI are documented in this file. Format follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Versioning](https://semver.org/). --- -<<<<<<< HEAD +## [1.13.4] - 2026-03-12 — Room Server Login & Receive Reliability + +### Changed +- 🔄 `meshcore_gui/ble/commands.py` — Room login success now refreshes archived room history immediately after `LOGIN_SUCCESS`, so the room panel is populated deterministically right after a successful login +- 🔄 `meshcore_gui/ble/events.py` — `CONTACT_MSG_RECV` with `txt_type == 2` is now always treated as a Room Server message, even when the `signature` field is absent; the author name falls back gracefully instead of routing the message through the normal DM path +- 🔄 `meshcore_gui/ble/worker.py` — The global `LOGIN_SUCCESS` subscriber now also synchronizes room login state into `SharedData` and refreshes room history, so UI state no longer depends solely on the command-side waiter winning the event timing race +- 🔄 `meshcore_gui/config.py` — Version bumped to `1.13.4` + +### Fixed +- 🛠 **Initial room login could remain pending or feel unreliable** — UI state now also updates from the subscribed `LOGIN_SUCCESS` event, not only from the command coroutine waiting for the same event +- 🛠 **Room messages could be missed when `txt_type == 2` arrived without `signature`** — such packets are now still classified as room traffic and shown in the Room Server panel +- 🛠 **Room history refresh after login was timing-sensitive** — history is now reloaded both from the command success path and from the subscribed login-success callback + +### Impact +- More reliable first login behaviour for Room Server panels +- Better chance that room history and newly arriving room messages show up immediately after login +- No intended breaking changes outside the Room Server receive/login flow + +--- ## [1.13.3] - 2026-03-12 — Active Panel Timer Gating ### Changed @@ -32,34 +47,15 @@ Format follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Ver ## [1.13.2] - 2026-03-11 — Map Display Bugfix ### Fixed -- 🛠 **MAP panel blank when contacts list is empty at startup** — dashboard update loop - had two separate conditional map-update blocks that both silently stopped firing after - tick 1 when `data['contacts']` was empty. Map panel received no further snapshots and - remained blank indefinitely. -- 🛠 **Leaflet map initialized on hidden (zero-size) container** — `processPending` in - the browser runtime called `L.map()` on the host element while it was still - `display:none` (Vue v-show, panel not yet visible). This produced a broken 0×0 map - that never recovered because `ensureMap` returned the cached broken state on all - subsequent calls. Fixed by adding a `clientWidth/clientHeight` guard in `ensureMap`: - initialization is deferred until the host has real dimensions. -- 🛠 **Route map container had no height** — `route_page.py` used the Tailwind class - `h-96` for the Leaflet host `
`. NiceGUI/Quasar does not include Tailwind CSS, - so `h-96` had no effect and the container rendered at height 0. Leaflet initialized - on a zero-height element and produced a blank map. -- 🛠 **Route map not rendered when no node has GPS coordinates** — `_render_map` - returned early before creating the Leaflet container when `payload['nodes']` was - empty. Fixed: container is always created; a notice label is shown instead. +- 🛠 **MAP panel blank when contacts list is empty at startup** — dashboard update loop had two separate conditional map-update blocks that both silently stopped firing after tick 1 when `data['contacts']` was empty. Map panel received no further snapshots and remained blank indefinitely. +- 🛠 **Leaflet map initialized on hidden (zero-size) container** — `processPending` in the browser runtime called `L.map()` on the host element while it was still `display:none` (Vue v-show, panel not yet visible). This produced a broken 0×0 map that never recovered because `ensureMap` returned the cached broken state on all subsequent calls. Fixed by adding a `clientWidth/clientHeight` guard in `ensureMap`: initialization is deferred until the host has real dimensions. +- 🛠 **Route map container had no height** — `route_page.py` used the Tailwind class `h-96` for the Leaflet host `
`. NiceGUI/Quasar does not include Tailwind CSS, so `h-96` had no effect and the container rendered at height 0. Leaflet initialized on a zero-height element and produced a blank map. +- 🛠 **Route map not rendered when no node has GPS coordinates** — `_render_map` returned early before creating the Leaflet container when `payload['nodes']` was empty. Fixed: container is always created; a notice label is shown instead. ### Changed -- 🔄 `meshcore_gui/static/leaflet_map_panel.js` — Added size guard in `ensureMap`: - returns `null` when host has `clientWidth === 0 && clientHeight === 0` and no map - state exists yet. `processPending` retries on the next tick once the panel is visible. -- 🔄 `meshcore_gui/gui/dashboard.py` — Consolidated two conditional map-update blocks - into a single unconditional update while the MAP panel is active. Added `h-96` to the - DOMCA CSS height overrides for consistency with the route page map container. -- 🔄 `meshcore_gui/gui/route_page.py` — Replaced `h-96` Tailwind class on the route - map host `
` with an explicit inline `style` (height: 24rem). Removed early - `return` guard so the Leaflet container is always created. +- 🔄 `meshcore_gui/static/leaflet_map_panel.js` — Added size guard in `ensureMap`: returns `null` when host has `clientWidth === 0 && clientHeight === 0` and no map state exists yet. `processPending` retries on the next tick once the panel is visible. +- 🔄 `meshcore_gui/gui/dashboard.py` — Consolidated two conditional map-update blocks into a single unconditional update while the MAP panel is active. Added `h-96` to the DOMCA CSS height overrides for consistency with the route page map container. +- 🔄 `meshcore_gui/gui/route_page.py` — Replaced `h-96` Tailwind class on the route map host `
` with an explicit inline `style` (height: 24rem). Removed early `return` guard so the Leaflet container is always created. ### Impact - MAP panel now renders reliably on first open regardless of contact/GPS availability @@ -67,7 +63,6 @@ Format follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Ver - No breaking changes outside the three files listed above --- ->>>>>>> b76eacf1119026c49c25d2811a6d713da8f8e01b ## [1.13.0] - 2026-03-09 — Leaflet Map Runtime Stabilization ### Added diff --git a/meshcore_gui/ble/commands.py b/meshcore_gui/ble/commands.py index 9203d93..6858f85 100644 --- a/meshcore_gui/ble/commands.py +++ b/meshcore_gui/ble/commands.py @@ -406,6 +406,7 @@ class CommandHandler: pubkey, 'ok', f"admin={is_admin}", ) + self._shared.load_room_history(pubkey) self._shared.set_status( f"✅ Room login OK: {room_name} — " f"history arriving over RF…" diff --git a/meshcore_gui/ble/events.py b/meshcore_gui/ble/events.py index 8fbf16f..65ca5c5 100644 --- a/meshcore_gui/ble/events.py +++ b/meshcore_gui/ble/events.py @@ -319,11 +319,18 @@ class EventHandler: path_len = len(path_hashes) # --- Room Server message (txt_type 2) --- - if txt_type == 2 and signature: - # Resolve actual author from signature (author pubkey prefix) - author = self._shared.get_contact_name_by_prefix(signature) + if txt_type == 2: + # Prefer the embedded author signature when available. + # Some room-history / server-side messages arrive without a + # signature; those still belong to the room and must not fall + # through to the regular DM path. + author = '' + if signature: + author = self._shared.get_contact_name_by_prefix(signature) + if not author: + author = signature[:8] if not author: - author = signature[:8] if signature else '?' + author = pubkey[:8] if pubkey else '?' self._shared.add_message(Message.incoming( author, @@ -337,7 +344,7 @@ class EventHandler: message_hash=msg_hash, )) debug_print( - f"Room msg from {author} (sig={signature}) " + f"Room msg from {author} (sig={signature or '-'}) " f"via room {pubkey[:12]}: " f"{payload.get('text', '')[:30]}" ) diff --git a/meshcore_gui/ble/worker.py b/meshcore_gui/ble/worker.py index 6aac002..7ed1751 100644 --- a/meshcore_gui/ble/worker.py +++ b/meshcore_gui/ble/worker.py @@ -258,10 +258,22 @@ class _BaseWorker(abc.ABC): # ── LOGIN_SUCCESS handler (Room Server) ─────────────────────── def _on_login_success(self, event) -> None: + """Synchronise Room Server login success into SharedData. + + This callback is intentionally independent from the command-side + ``wait_for_event(LOGIN_SUCCESS)`` path. If the library delivers the + event to subscribers before or instead of the waiter, the UI must + still transition to the logged-in state and refresh room history. + """ payload = event.payload or {} pubkey = payload.get("pubkey_prefix", "") is_admin = payload.get("is_admin", False) + detail = f"admin={is_admin}" + debug_print(f"LOGIN_SUCCESS received: pubkey={pubkey}, admin={is_admin}") + self.shared.set_room_login_state(pubkey, 'ok', detail) + if pubkey: + self.shared.load_room_history(pubkey) self.shared.set_status("✅ Room login OK — messages arriving over RF…") # ── apply cache ─────────────────────────────────────────────── diff --git a/meshcore_gui/config.py b/meshcore_gui/config.py index 941b0ec..cfe4d5b 100644 --- a/meshcore_gui/config.py +++ b/meshcore_gui/config.py @@ -25,7 +25,7 @@ from typing import Any, Dict, List # ============================================================================== -VERSION: str = "1.13.3" +VERSION: str = "1.13.4" # ==============================================================================