Staging#32
Merged
MichaelWheeley merged 17 commits intoMichaelWheeley:feature/thai-language-devfrom Apr 2, 2026
Merged
Conversation
When a cloudRelaySession is active the Cloud Relay card now shows the session status and a Disconnect button. Clicking it clears the session and immediately saves config (no manual Save required), switching RigContext back to the direct SSE connection path. Previously the only way to leave cloud-relay mode was to manually clear the hidden session field; without that the direct connection path in RigContext was never reached even after disabling the relay in rig-bridge. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of rig-bridge firing fire-and-forget HTTP POSTs to a hardcoded localhost:8080 (wrong port, always failed silently), all plugin data now flows over the same SSE /stream connection already used for freq/mode/ptt. rig-bridge changes: - state.js: add 100-entry decode ring-buffer (addToDecodeRingBuffer / getDecodeRingBuffer) so connecting browsers see recent decodes immediately - rig-bridge.js: subscribe to pluginBus after connectIntegrations() and broadcast typed plugin messages for decode/status/qso/aprs events - server.js: send plugin-init after the rig init message on /stream connect, carrying the ring-buffer replay and list of running integration plugins - aprs-tnc.js: remove forwardToLocal() call from handleKissData — SSE broadcast replaces it; fix default ohcUrl port from 8080 → 3000 - config.js: fix default aprs.ohcUrl port 8080 → 3000 Frontend changes: - RigContext.jsx: dispatch window CustomEvent 'rig-plugin-data' for type:'plugin' and type:'plugin-init' messages from local SSE - useAPRS.js: listen for rig-plugin-data aprs events, POST raw packet to /api/aprs/local (same-origin, always reachable), then refresh stations; seed tncConnected from plugin-init - useWSJTX.js: listen for decode/status events; seed decode list from plugin-init ring-buffer replay; populate clients map from status events - useDigitalModes.js: listen for status events to update plugin statuses (OHC server has no /api/mshv|jtdx|js8call/status routes, so HTTP polling was always failing silently in local mode) Cloud relay path is entirely unchanged — window events only fire when the browser is connected directly to rig-bridge's /stream. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- useWSJTX: add isLocalMode ref that stops the adaptive polling loop the moment the first rig-bridge SSE event arrives; add qso event handling; avoid setting hasDataFlowing from SSE path (prevents spurious 2 s burst) - rig-bridge/lib/aprs-parser.js: new standalone APRS position parser (!, =, /, @, ; data types) extracted so rig-bridge can produce fully- parsed station objects without a server round-trip - aprs-tnc: parse packet before bus emit; spread lat/lon/symbol/comment into the SSE payload alongside raw AX.25 fields; tag with stationSource - useAPRS: maintain separate rfStations Map fed purely by SSE events; merge RF + internet stations (RF wins on duplicate callsign); add 60-minute aging cleanup matching server APRS_MAX_AGE_MINUTES; remove server POST call entirely for local-TNC path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- APRSPanel: add distance-to-DE column using calculateDistance/formatDistance, respecting user metric/imperial setting; pass deLocation + units from DockableApp - APRSPanel: hover tooltip showing full comment, coordinates, distance, age, speed/course, altitude and symbol — fixed-position, pointer-events:none - APRSPanel: fix age display for RF stations (NaNh) by computing age from timestamp when server-provided age field is absent - APRSPanel: prevent server poll from resetting aprsEnabled to false when aprs-tnc was detected via SSE (tncDetectedViaSse ref) - CallsignLink: strip APRS SSID suffix (-0…-15) before QRZ lookup so W1ABC-9 opens QRZ as W1ABC Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add standard APRS symbol sprite sheets (hessu/aprs-symbols, 24 px) to public/ — primary table (0), alternate table (1), overlay table (2) - New src/utils/aprs-symbols.js: getAprsSymbolIcon() maps the two-char APRS symbol field to a Leaflet divIcon using CSS background-position into the sprite sheet; supports primary (/), alternate (\), and alphanumeric overlay table chars; falls back to null for unknown symbols - WorldMap.jsx: use symbol sprite icon when available, keeping the CSS triangle as fallback; colour ring (amber/green/cyan) preserved via box-shadow on the icon wrapper; watched stations rendered at 20 px, others at 16 px - WorldMap.jsx: fix age display for RF stations in popup (NaN) by falling back to timestamp when station.age is absent Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clicking an APRS station on the map or in the panel should not set the DX target — APRS is a monitoring tool, not a contact/spotting source. - WorldMap: remove onSpotClick call from APRS marker click; popup still opens via Leaflet bindPopup as before - DockableApp: stop passing onSpotClick to APRSPanel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In local/LAN mode the browser already receives all decodes via the SSE
/stream — the HTTP batch POST to /api/wsjtx/relay on the OHC server is
redundant and generates unnecessary traffic.
- config.js: add wsjtxRelay.relayToServer (default false) — false means
SSE-only, true means also POST batches to OHC server
- wsjtx-relay.js: compute willRelay flag at connect() time; gate message
queue push, scheduleBatch, heartbeat and health-check intervals behind
willRelay; SSE bus.emit paths are always active regardless of mode;
getStatus() now surfaces relayToServer and serverUrl only when active
- state.js: export getSseClientCount() so other modules can read the
number of live SSE connections
- server.js: import getSseClientCount; add GET /api/status returning
{ sseClients, uptime } — lightweight endpoint for UI health display
- SettingsPanel: add wsjtxRelayToServer toggle that immediately PATCHes
rig-bridge config; handleConfigureWsjtxRelay now also sets
relayToServer:true when pushing cloud-relay credentials; add SSE
client count badge with Refresh button so users can verify local
connections before disabling server relay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The delivery mode toggle belongs on the source side (rig-bridge) not in the OHC settings panel. rig-bridge UI (server.js): - Replace the flat wsjtx opts section with a two-option delivery mode selector: "SSE only" (local/LAN) and "Relay to OHC server" (cloud) - SSE mode shows only UDP port and multicast options — server fields (URL, relay key, session ID, batch interval) are hidden in a separate wsjtxServerOpts div that only appears in relay mode - populateIntegrations() reads relayToServer flag to set the radio - toggleWsjtxMode() shows/hides the server-specific block - saveIntegrations() writes relayToServer from the selected radio OHC SettingsPanel: - Remove wsjtxRelayToServer state, handleToggleRelayToServer handler, fetchSseClientCount handler, toggle UI block and SSE count badge — all moved to rig-bridge UI - relayToServer:true is still sent when the user clicks Configure Cloud Relay, since that action explicitly enables server delivery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nt and lib files
- Rewrite WSJT-X Relay section: document SSE-only (default) vs relay-to-server
delivery modes, three setup options, updated config reference with relayToServer
- Add GET /api/status endpoint to API reference table ({sseClients, uptime})
- Add lib/aprs-parser.js and lib/wsjtx-protocol.js to project structure tree
- Update pluginBus event docs to include status, qso and aprs events
- Add SSE ring-buffer replay note to Digital Mode Plugins section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enables rig-bridge to serve over HTTPS so browsers running OpenHamClock
on an HTTPS origin can connect without mixed-content errors.
- New core/tls.js module: generates RSA-2048 self-signed cert (10-year
validity, SAN for localhost/127.0.0.1) using node-forge; stores key+cert
in ~/.config/openhamclock/certs/; exposes ensureCerts(), loadCreds(),
getCertInfo() (fingerprint, expiry, days remaining)
- core/config.js: bump CONFIG_VERSION 7→8, add tls.{enabled,certGenerated}
defaults, export CONFIG_DIR
- core/server.js: startServer() made async, switches to https.createServer()
when tls.enabled, falls back to HTTP on failure; CORS list auto-includes
https:// variants when TLS is active; POST /api/config made async and
handles tls section with cert generation and forceRegen support; three
new routes: GET /api/tls/status, GET /api/tls/cert (download),
POST /api/tls/install (OS cert install with manual fallback)
- Setup UI: new 🔒 Security tab with HTTPS toggle, certificate fingerprint/
expiry info, download button, OS-detected install instructions, and
one-click Install Certificate button with graceful fallback to manual
command on permission error
- rig-bridge.js: wrapped startup in async IIFE so startServer() is awaited
before connectActive()/connectIntegrations()
- Add node-forge ^1.4.0 dependency (pure JS, pkg-compatible)
- Update rig-bridge-config.example.json and README with HTTPS setup docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ip clamp, config defaults - useWSJTX: reset isLocalMode after 30 s SSE silence so HTTP polling resumes if rig-bridge disconnects mid-session (was permanently latched) - APRSPanel: clamp hover tooltip to viewport bounds; remove dead onSpotClick prop - rig-bridge config: revert ohcUrl default to localhost:8080 (was 3000, dev-only port) - rig-bridge config: bump CONFIG_VERSION 7 → 8 for relayToServer key addition Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rig-bridge: Direct SSE mode, plugin data pipeline & APRS improvements
The prototype pollution guard used isValidSessionId() to validate WSJT-X client IDs, but its regex only allowed [A-Za-z0-9_\-:.]. Users with custom instance names containing spaces (e.g. "WSJT-X - FT991A") had all packets silently rejected. Add a separate isValidClientId() that only blocks __proto__, constructor, and prototype while allowing any normal characters. Closes #846 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Brings in upstream changes from Staging: - fix(wsjtx): allow spaces in WSJT-X client IDs - feat: satellite layer improvements (useSatelliteLayer) - feat: Thai language support - feat: QRZ lookup for active users - Various language key updates and corrections Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full rewrite focused on clarity and accessibility for non-IT users: - Added table of contents for easy navigation - Rewrote all sections in plain language — explains COM ports, localhost, API tokens, baud rate, and other concepts inline without jargon - Reorganised structure: Getting Started → per-radio setup → OHC connection → digital modes → APRS → rotator → HTTPS → troubleshooting → advanced - Added per-radio model setup tables (Yaesu, Icom, Kenwood, Elecraft) - Rewrote HTTPS section as a complete end-to-end walkthrough including: browser security warning steps for Chrome/Edge, Firefox and Safari, full manual cert install steps for macOS, Windows and Linux, verification checklist, and revert-to-HTTP instructions - Expanded troubleshooting table with plain-language descriptions - Moved developer content (API reference, plugin writing, build scripts, project structure) to an Advanced Topics section at the bottom Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tls.js: use random 16-byte serial number instead of hardcoded '01' so regenerated certificates are not silently returned from OS trust-store caches that key on issuer+serial (macOS Keychain, some browsers) - server.js: fix terminal banner alignment — 🔒 emoji renders as 2 display columns, so shortened the text to keep the box correctly aligned - server.js: move tls module to top-level require (tlsModule) instead of inline require() inside each route handler and startServer() - server.js: replace exec() + shell string interpolation in /api/tls/install with execFile() + explicit args array so unusual home directory characters (quotes, dollar signs) cannot affect command parsing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(rig-bridge): HTTPS/TLS support + README rewrite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Type of change
How to test
Checklist
server.js: caches have TTLs and size caps (we serve 2,000+ concurrent users)var(--accent-cyan), etc.).bak,.old,console.logdebug lines, or test scripts includedScreenshots (if visual change)