[feat](trx-config): add a resolved-config validation phase
Some things can only be checked once CLI overrides have been folded in and the rig/remote lists are final, so nothing checked them at all: - The client's per-rig maps (rigctl.rig_ports, audio.rig_urls, audio.rig_ports, decode_history_retention_min_by_rig, http.default_rig_name) are keyed by a remote's short name. A typo used to spawn a rigctl listener that injected a rig_id no remote answered to, without a word in the log. - Nothing noticed two listeners claiming one socket. [listen].port and a rig's [audio].port could both be 4530; on the client, http, http_json and each rigctl rig port could collide freely. Add validate_resolved() to both configs, run after argument parsing, plus a shared socket-conflict check that treats a wildcard address as conflicting with any address on the same port and ignores port 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyX26FCpMQxiBoC7r5K1A7 Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -153,7 +153,7 @@ async fn async_init() -> DynResult<AppState> {
|
||||
}
|
||||
loaded.report_unknown_keys(cli.strict_config)?;
|
||||
|
||||
let cfg = loaded.config;
|
||||
let mut cfg = loaded.config;
|
||||
cfg.validate()
|
||||
.map_err(|e| format!("Invalid client configuration: {}", e))?;
|
||||
|
||||
@@ -269,6 +269,30 @@ async fn async_init() -> DynResult<AppState> {
|
||||
.http_json_listen
|
||||
.unwrap_or(cfg.frontends.http_json.listen);
|
||||
let http_json_port = cli.http_json_port.unwrap_or(cfg.frontends.http_json.port);
|
||||
|
||||
// Fold the CLI overrides back into the config so validation and the
|
||||
// frontends agree on what is about to be bound.
|
||||
cfg.frontends.http.enabled = frontends.iter().any(|f| f == "http");
|
||||
cfg.frontends.rigctl.enabled = frontends.iter().any(|f| f == "rigctl");
|
||||
cfg.frontends.http_json.enabled = frontends.iter().any(|f| f == "httpjson");
|
||||
cfg.frontends.http.listen = http_listen;
|
||||
cfg.frontends.http.port = http_port;
|
||||
cfg.frontends.rigctl.listen = rigctl_listen;
|
||||
cfg.frontends.http_json.listen = http_json_listen;
|
||||
cfg.frontends.http_json.port = http_json_port;
|
||||
|
||||
// Second validation phase: the per-rig maps are keyed by remote short name,
|
||||
// so they can only be checked once the remote list is final.
|
||||
if cli.url.is_none() {
|
||||
cfg.validate_resolved(&resolved_remotes)
|
||||
.map_err(|e| format!("Invalid client configuration: {}", e))?;
|
||||
} else {
|
||||
// --url replaces the configured remotes outright, so only the socket
|
||||
// checks still apply.
|
||||
trx_config::shared::check_socket_conflicts(&cfg.bound_sockets())
|
||||
.map_err(|e| format!("Invalid client configuration: {}", e))?;
|
||||
}
|
||||
|
||||
let callsign = cli
|
||||
.callsign
|
||||
.clone()
|
||||
|
||||
Reference in New Issue
Block a user