Add semantic validate() checks for server/client config models and fail fast on invalid ranges, field combinations, and auth token values before runtime startup.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add coordinated shutdown signaling and task supervision for long-running server and client tasks to avoid detached runtimes on Ctrl+C.
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Replace legacy global FrontendRegistry with bootstrap context adapter that
maintains backward compatibility while delegating to explicit context.
Changes:
- Create BOOTSTRAP_CONTEXT: OnceLock<Arc<Mutex<FrontendRegistrationContext>>>
- register_frontend(): delegates to bootstrap context
- is_frontend_registered(): reads from bootstrap context
- registered_frontends(): reads from bootstrap context
- spawn_frontend(): reads from bootstrap context
Result: Plugins continue calling global functions, but all operations
now route through the bootstrap context. Frontends receive context
parameter explicitly, enabling multiple concurrent instances.
Complete de-globalization achieved with full backward compatibility.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Create FrontendRuntimeContext as Arc during async_init and pass it to all
spawn_frontend calls, enabling explicit context-based initialization.
Changes:
- Create frontend_runtime_ctx as Arc<FrontendRuntimeContext>
- Pass context to all spawn_frontend invocations in the frontend loop
- Update comment to reflect Phase 3C completion
This completes the threading of context through the client bootstrap,
moving away from global mutable state for audio channels, decode channels,
and authentication tokens.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Update all three built-in frontends to accept Arc<FrontendRuntimeContext>
parameter in their spawn_frontend implementations:
- trx-frontend-http: passes context to serve function
- trx-frontend-http-json: passes context to serve function
- trx-frontend-rigctl: accepts context (minimal impact, no globals used)
Frontends are now ready to use context for audio channels, decode
channels, and auth tokens instead of accessing globals directly.
This completes the trait signature change for all frontends.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Update FrontendSpawner trait and related functions to accept and pass
Arc<FrontendRuntimeContext> parameter instead of relying on global
accessors for audio channels, decode channels, and auth tokens.
Changes:
- FrontendSpawner::spawn_frontend now accepts context parameter
- FrontendSpawnFn type signature includes context parameter
- FrontendRegistrationContext::spawn_frontend passes context to spawner
- Global spawn_frontend function accepts and passes context
This enables frontends to receive runtime data explicitly without
accessing globals, improving testability and supporting multiple
concurrent frontends with different contexts.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Demonstrate context-based frontend initialization in async_init.
Creates FrontendRegistrationContext and FrontendRuntimeContext at bootstrap
to establish the pattern for explicit frontend management instead of globals.
Full threading of context through spawn_frontend would require changing the
frontend trait signature and updating all frontend implementations - planned
for Phase 3C.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Create explicit context types for frontend registration and runtime:
FrontendRegistrationContext:
- register_frontend(name, spawner) - register a frontend
- is_frontend_registered(name) - check if registered
- registered_frontends() -> Vec<String> - list all frontends
- spawn_frontend(name, ...) -> DynResult - spawn a frontend
FrontendRuntimeContext (NEW):
- audio_rx: broadcast channel for audio RX
- audio_tx: mpsc channel for audio TX
- audio_info: watch channel for audio stream metadata
- decode_rx: broadcast channel for decoded messages
- aprs_history: Arc<Mutex<VecDeque>> for APRS decode history
- cw_history: Arc<Mutex<VecDeque>> for CW decode history
- ft8_history: Arc<Mutex<VecDeque>> for FT8 decode history
- auth_tokens: HashSet for authentication
Replaces global mutable state with explicit context that can be
threaded through bootstrap. Maintains global API for compatibility.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Replace client's local implementations with unified trx-app utilities.
Changes:
- Use trx_app::normalize_name() instead of local fn
- Depend on trx-app crate
This eliminates the client's copy of the normalize_name logic and ensures
both server and client use the same implementation.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Replace duplicated RigState initialization with new constructor methods.
Changes:
- Use RigState::new_uninitialized() in main.rs
- Use RigState::from_snapshot() in remote_client.rs
- Remove standalone state_from_snapshot() function
These constructors eliminate 155 lines of duplicated struct literals
and provide clear semantics for different initialization contexts.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Use centralized trx-protocol crate for:
- parse_mode and envelope parsing
- command mapping (ClientCommand -> RigCommand)
- token validation via RegistryTokenValidator wrapper
RegistryTokenValidator maintains compatibility with global auth
registry pattern while leveraging shared protocol logic from
trx-protocol. Removes duplicate auth and codec functions.
No behavior changes, all tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Use centralized trx-protocol::rig_command_to_client for command
conversion, eliminating 62 lines of duplicate code in mode handling
and command mapping logic.
Updates remote_client to delegate to trx-protocol for bidirectional
command conversion. No behavior changes, all tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Remove macOS AppKit frontend (trx-frontend-appkit) and related code:
- Delete appkit crate directory
- Remove appkit dependency and feature from Cargo.toml
- Remove appkit imports, main thread handling, and config from main.rs
- Remove AppKit config struct from config.rs
- Remove appkit section from example config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add POST endpoints for toggle_aprs_decode, toggle_cw_decode,
clear_aprs_decode, and clear_cw_decode. Add toggle buttons in APRS
and CW tabs. Render decoder enabled state from SSE updates. Clear
button now also resets server-side decoder state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add SetAprsDecodeEnabled, SetCwDecodeEnabled, ResetAprsDecoder, and
ResetCwDecoder to the JSON TCP frontend command mapping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Initialize decoder state fields and map new RigCommand/ClientCommand
variants through the remote client TCP bridge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Replace HEAD probe with EventSource readyState check to properly
detect 404 vs connection drop. HEAD requests to SSE endpoints may
not behave reliably across all setups.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Log whether audio/decode is enabled at startup and warn when
/decode is requested but the decode channel was not set. Helps
diagnose broken decode pipelines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
The decode EventSource silently retried on 404 leaving the status
stuck on "Waiting for server decode". Probe /decode first to
distinguish 404 (audio disabled) from real SSE errors and update
the APRS/CW status text accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Server-side decoding makes client-side decoders redundant. Remove
~1000 lines of browser-side Bell 202 AFSK, AX.25/APRS parsing, and
Goertzel CW decoding. The frontend now relies solely on the /decode
SSE endpoint for decoded data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Clears the packet list, map markers are unaffected. Also wipes
the persisted packet history from localStorage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Add /decode SSE endpoint streaming decoded messages from the server.
Add decode channel OnceLock with set/subscribe pattern.
In the browser, connect to /decode EventSource and dispatch to
onServerAprs/onServerCw handlers. APRS and CW plugins now receive
server-decoded data automatically while keeping browser-side decoding
as a fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
Handle APRS/CW decode message types (0x03/0x04) in audio_client,
deserialize and forward via broadcast channel. Create decode channel
and pass to audio client and HTTP frontend.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>