Drive MeshService through the MeshMonitor HTTP gateway (Phase 2) #56

Merged
kamilkrzywda merged 2 commits from feat/meshmonitor-connection into main 2026-10-13 03:10:15 +02:00
Owner

Rewires the bot off the raw TCP socket + codec and onto the Phase-1 MeshMonitor HTTP gateway client, preserving every public behavior.

What changed

  • MeshService is now client-driven — it takes an injectable MeshMonitorClient (HttpMeshMonitorClient in production via MESHMONITOR_API_TOKEN, FakeMeshMonitorClient in tests; no token → stays disconnected, sends 503). The net.Socket connection, frame buffer, codec framing, idle watchdog and periodic reconnect are gone.
  • Poll loops replace the socket: status every 15 s (5 s retries while down) gates everything; first success syncs nodes → channels → telemetry → messages (seen-set baseline so pre-existing traffic is not re-processed), then messages every MESH_POLL_MS (1 s) in {limit: 50} newest-first windows, nodes 30 s, channels 5 min, telemetry 60 s (long-format rows grouped per packet).
  • Outbound: broadcasts via send({text, channel}) on the pinned send channel (default 3); DMs via send({text, toNodeId: '!hex'}) on the primary channel in mesh terms. Gateway-rejected sends record a failed tx; HTTP 413 → 400, else → 503. respond() semantics unchanged (rx → DM back to sender unless the original was a broadcast; tx → its destination; injected → broadcast; always threaded via replyId).
  • All /api/ REST + MCP endpoint shapes preserved* (status/messages/nodes/channels/telemetry/send/respond/inject + the 10 MCP tools); notifier, command auto-responder, battery alerts and the weather job behave as before.
  • Tests: every consumer spec (mesh service, MCP controller, command auto-responder, battery alerts) now drives the real service through FakeMeshMonitorClient; the fake TCP bridge (src/mesh/fake-bridge.ts) is deleted. The fake client's test API was widened (constructor takes the source identity {connected, nodeNum, longName, shortName}, auto-seeds the bot's own node, pushNode upsert). Suite: 17 files / 245 tests green (baseline 234); build green.
  • Docker: compose drops MESH_HOST/MESH_PORT, adds MESHMONITOR_API_TOKEN (from .env, gitignored) / MESHMONITOR_API_BASE (default https://meshmonitor.kkhost.pl/api/v1) / MESHMONITOR_SOURCE (default default) / MESHMONITOR_TIMEOUT_MS (default 15000) / NODE_TLS_REJECT_UNAUTHORIZED=0 (self-signed cert).

Live smoke (real gateway, .env token, source default)

STATUS {"connected":true,"myNodeNum":3994646728,"longName":"SP8MK Bot","nodeResponsive":true}
NODES_COUNT 104
SMOKE_RESULT connected=true nodes=104

Caveats / degradations

  • GET /api/device is degraded: no device metadata / local+module config via the gateway (only firmwareVersion when present in the node record; empty config sections).
  • No idle watchdog / periodic reconnect anymore — steady polling replaces it (a status failure flips connected=false and retries every 5 s).
  • World state (nodes/channels/telemetry) is not cleared when the status drops; each refreshes on its own interval.

Version

0.21.12 → 0.22.0 (CHANGELOG entry v0.22.0 — 2026-10-13 00:42).

Rewires the bot off the raw TCP socket + codec and onto the Phase-1 **MeshMonitor HTTP gateway** client, preserving every public behavior. ## What changed - **MeshService is now client-driven** — it takes an injectable MeshMonitorClient (HttpMeshMonitorClient in production via MESHMONITOR_API_TOKEN, FakeMeshMonitorClient in tests; no token → stays disconnected, sends 503). The net.Socket connection, frame buffer, codec framing, idle watchdog and periodic reconnect are gone. - **Poll loops replace the socket**: status every 15 s (5 s retries while down) gates everything; first success syncs nodes → channels → telemetry → messages (seen-set baseline so pre-existing traffic is not re-processed), then messages every MESH_POLL_MS (1 s) in {limit: 50} newest-first windows, nodes 30 s, channels 5 min, telemetry 60 s (long-format rows grouped per packet). - **Outbound**: broadcasts via send({text, channel}) on the pinned send channel (default 3); DMs via send({text, toNodeId: '!hex'}) on the primary channel in mesh terms. Gateway-rejected sends record a failed tx; HTTP 413 → 400, else → 503. respond() semantics unchanged (rx → DM back to sender unless the original was a broadcast; tx → its destination; injected → broadcast; always threaded via replyId). - **All /api/* REST + MCP endpoint shapes preserved** (status/messages/nodes/channels/telemetry/send/respond/inject + the 10 MCP tools); notifier, command auto-responder, battery alerts and the weather job behave as before. - **Tests**: every consumer spec (mesh service, MCP controller, command auto-responder, battery alerts) now drives the real service through FakeMeshMonitorClient; the fake TCP bridge (src/mesh/fake-bridge.ts) is deleted. The fake client's test API was widened (constructor takes the source identity {connected, nodeNum, longName, shortName}, auto-seeds the bot's own node, pushNode upsert). Suite: 17 files / 245 tests green (baseline 234); build green. - **Docker**: compose drops MESH_HOST/MESH_PORT, adds MESHMONITOR_API_TOKEN (from .env, gitignored) / MESHMONITOR_API_BASE (default https://meshmonitor.kkhost.pl/api/v1) / MESHMONITOR_SOURCE (default default) / MESHMONITOR_TIMEOUT_MS (default 15000) / NODE_TLS_REJECT_UNAUTHORIZED=0 (self-signed cert). ## Live smoke (real gateway, .env token, source default) ``` STATUS {"connected":true,"myNodeNum":3994646728,"longName":"SP8MK Bot","nodeResponsive":true} NODES_COUNT 104 SMOKE_RESULT connected=true nodes=104 ``` ## Caveats / degradations - GET /api/device is degraded: no device metadata / local+module config via the gateway (only firmwareVersion when present in the node record; empty config sections). - No idle watchdog / periodic reconnect anymore — steady polling replaces it (a status failure flips connected=false and retries every 5 s). - World state (nodes/channels/telemetry) is not cleared when the status drops; each refreshes on its own interval. ## Version 0.21.12 → **0.22.0** (CHANGELOG entry v0.22.0 — 2026-10-13 00:42).
kamilkrzywda added 2 commits 2026-10-13 02:42:49 +02:00
Phase 1 of the MeshMonitor HTTP-gateway migration: a stateless REST client
that a later phase wires into MeshService to replace the raw
Meshtastic protobuf-over-TCP bridge.

- mesh-monitor-client.ts: MeshMonitorClient interface, HttpMeshMonitorClient
  (native fetch, Bearer auth, injectable base/source/poll params), mappers for
  the gateway's actual JSON shapes (source-scoped paths, flat node position,
  second-based node lastHeard vs ms message/telemetry timestamps, long-format
  telemetry, packet id = 3rd segment of the id string), MeshMonitorError,
  nodeNumToId/nodeIdToNum, shared assertSendTarget XOR, and
  createMeshMonitorClientFromEnv() (null when MESHMONITOR_API_TOKEN unset).
- fake-mesh-monitor-client.ts: in-memory double mirroring the client contract
  (set*/pushInbound config, sends[] recorder, outbound mirrored into
  getMessages, newest-first, limit/channel/toNodeId/fromNodeId filters).
- meshmonitor.module.ts: thin Nest provider exposing the env-built client
  (or null) under MESH_MONITOR_CLIENT for Phase 2's MeshModule.
- specs: HttpMeshMonitorClient against an in-process node:http gateway
  (raw->typed mapping per endpoint, Authorization: Bearer header, send body
  shape with channel/toNodeId XOR + replyId passthrough, 401/413/429/503
  -> MeshMonitorError); FakeMeshMonitorClient behavior.

No MeshService changes, no version bump, no changelog, no PR.
Rewire MeshService off the raw TCP socket + codec onto the Phase-1
MeshMonitorClient contract (HttpMeshMonitorClient in production,
FakeMeshMonitorClient in tests): status/messages/nodes/channels/telemetry
are polled (15s/1s/30s/5min/60s) instead of streamed, outbound broadcasts
and DMs go through client.send(), respond/inject/notifier/command/battery/
weather behavior and all /api/* + MCP endpoint shapes are preserved.
The fake TCP bridge is deleted and every consumer spec (mesh service, MCP
controller, command auto-responder, battery alerts) now drives the real
service through the widened fake client. Docker compose drops
MESH_HOST/MESH_PORT and adds the MESHMONITOR_* env (token from .env,
self-signed TLS via NODE_TLS_REJECT_UNAUTHORIZED=0).

Live smoke against https://meshmonitor.kkhost.pl: getStatus ->
{connected:true, myNodeNum:3994646728, longName:'SP8MK Bot',
nodeResponsive:true}; getNodes -> 104 nodes.

Build green, suite 17 files / 245 tests (baseline 234).
kamilkrzywda merged commit 2c4b4c5968 into main 2026-10-13 03:10:15 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OpenCode/MeshBot#56