Skip to content

Fix connection-status, drawing-tool and node-tracking defects - #176

Merged
amorfinv merged 7 commits into
mainfrom
fix/connection-status-drawing-tools-and-node-tracking
Aug 13, 2026
Merged

Fix connection-status, drawing-tool and node-tracking defects#176
amorfinv merged 7 commits into
mainfrom
fix/connection-status-drawing-tools-and-node-tracking

Conversation

@amorfinv

Copy link
Copy Markdown
Collaborator

Seven commits, each a self-contained fix (plus one no-behaviour-change cleanup at the end).

Backend (proxy)

  • Activate a newly discovered node when the active one is dead. The network client auto-selects only the first node it ever sees, and removal-failover needs a survivor. When the last node vanished, act_id kept pointing at the dead node, the actonly subscriptions (ACDATA/ROUTEDATA) never moved, and the data-flow timeout tore down a live connection.
  • Serialize node_info in the initial_data snapshot. It was built straight from the internal stores, which hold binary node/server IDs — unusable by the frontend NodeData type. Both paths now share NodeManager.serialize_node_info().

Frontend

  • Connection status after a disconnect. A deliberate disconnect left the no-data timer armed (spurious "connection may be lost" warning 5s later) and left receivingData stale after a WebSocket drop; in-flight data events flipped the status straight back to connected. Adds a short expectDisconnect() grace window, and drops the ConnectionState fields that merely mirrored the booleans. SettingsModal now propagates the configured host so the header stops reporting localhost.
  • Mutually exclusive drawing tools. Starting one click-to-draw tool while another was active left both listening, so a single click was consumed twice. A small drawingExclusion module holds the single active claim. Empty-map clicks during shape/aircraft drawing no longer deselect the aircraft, and teardown with the map already gone no longer strands document-level listeners.
  • 3D scene origin vs invalid coordinates. NaN or out-of-range lat/lon (e.g. after MOVE past lat 90) poisoned the shared scene origin, making MercatorCoordinate.fromLngLat throw on every tick and frame.
  • GLB loads completing after teardown. They resurrected the caches clearAll() had just dropped and leaked geometry/materials.

New tests cover each fix.

🤖 Generated with Claude Code

amorfinv and others added 7 commits August 13, 2026 22:25
The network client auto-selects only the very first node it ever sees, and
removal-failover needs a surviving node to switch to. When the last node
vanishes (e.g. its process crashes) act_id keeps pointing at the dead node,
so a node added afterwards was never activated: the actonly subscriptions
(ACDATA/ROUTEDATA) stayed bound to the dead node, no traffic flowed, and the
data-flow timeout tore down an otherwise live connection.

_on_node_added now re-activates when the client's active node is gone, and
the local `import traceback` calls are hoisted to a module-level import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
get_current_data() built its own node_info payload straight from the internal
stores, which keep binary node/server IDs. Socket.IO ships those as binary
attachments and the frontend NodeData type can't read them, so a client that
joined between node_info events saw unusable node data.

The serialization used by the node_info event is extracted into
NodeManager.serialize_node_info() and both paths now go through it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…disconnect

Three related connection-status defects:

- A deliberate disconnect (QUIT, server_disconnected, Stop in the integrated
  build) left the armed no-data timer running, so it fired up to 5s later and
  echoed a spurious "No data received - connection may be lost" warning.
  setBlueSkyConnected(false) now cancels the timer and clears receivingData,
  which also fixes receivingData sticking true forever after a WebSocket drop.
- Data events already in flight when the disconnect landed flipped the status
  straight back to connected, re-arming that timer and flashing a phantom
  "Connected". expectDisconnect() opens a short grace window in which data is
  ignored; SocketManager also drops in-flight siminfo/acdata frames so they
  can't repaint traffic the disconnect just cleared. Data still arriving after
  the window (i.e. the disconnect request failed) reconnects as usual.
- SettingsModal never propagated the configured host, so the header status
  string reported its 'localhost' default forever.

Also drops the unused ConnectionState duplication (webSocketState /
blueSkyState mirrored the booleans) and dead accessors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Starting shape drawing while a route draw was in progress (or either while
placing an aircraft) left both tools listening, so one map click was consumed
twice: waypoints landed in a route the user thought they had left, and the
shared drawing banner showed whichever tool started last.

A small drawingExclusion module holds the single active claim; claiming
cancels the previous owner's draw. Route and shape drawing claim the map
before showing their banner so the outgoing tool's teardown can't hide it.

Alongside:
- AircraftInteractionManager's route-only predicate becomes a general
  setDrawingToolActiveCheck, so empty-map clicks during shape drawing and
  aircraft placement no longer deselect the selected aircraft.
- Teardown no longer bails out when the map is already gone, which used to
  strand the document-level keydown/Escape listener and the navaid highlight.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BlueSky can deliver NaN or out-of-range lat/lon (e.g. after a MOVE past
lat 90). The scene origin was seeded from — and recentred on — every record,
so one bad aircraft poisoned the origin shared by all mesh transforms and the
mercator camera matrix, and MercatorCoordinate.fromLngLat then threw on every
data tick and every frame.

updateSceneOrigin now filters through isValidCoordinate before seeding or
recentring, mirroring the per-aircraft guard the renderers already apply.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A model request still in flight when clearAll() ran resurrected the caches it
had just dropped: the model was cached and onModelLoaded fired against a torn
down renderer, leaking the GLB's geometry and materials. The load callback now
checks that its entry is still registered and disposes the result otherwise.

clearCache() also dropped its recorded raw dimensions, which previously
survived the models they described.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Aircraft3DFleet repeated the globe/mercator transform branch in four places;
it now goes through one applyTransform helper. MapControlsPanel's three
near-identical button handlers collapse into a withManager helper, and the
zoom/reset paths lose their duplicated null checks and narration-only logs.

No behaviour change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@amorfinv
amorfinv merged commit fc37c79 into main Aug 13, 2026
2 checks passed
@amorfinv
amorfinv deleted the fix/connection-status-drawing-tools-and-node-tracking branch August 13, 2026 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant