[feat](trx-client,trx-frontend-http): add default rig and hideable rf gain
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -228,6 +228,10 @@ pub struct HttpFrontendConfig {
|
||||
pub listen: IpAddr,
|
||||
/// Listen port
|
||||
pub port: u16,
|
||||
/// Default rig selected in the web UI on startup.
|
||||
pub default_rig_id: Option<String>,
|
||||
/// Whether to expose the RF Gain control in the web UI.
|
||||
pub show_sdr_gain_control: bool,
|
||||
/// Authentication settings
|
||||
pub auth: HttpAuthConfig,
|
||||
}
|
||||
@@ -238,6 +242,8 @@ impl Default for HttpFrontendConfig {
|
||||
enabled: true,
|
||||
listen: IpAddr::from([127, 0, 0, 1]),
|
||||
port: 8080,
|
||||
default_rig_id: None,
|
||||
show_sdr_gain_control: true,
|
||||
auth: HttpAuthConfig::default(),
|
||||
}
|
||||
}
|
||||
@@ -329,6 +335,11 @@ impl ClientConfig {
|
||||
if self.frontends.http.enabled && self.frontends.http.port == 0 {
|
||||
return Err("[frontends.http].port must be > 0 when enabled".to_string());
|
||||
}
|
||||
if let Some(rig_id) = &self.frontends.http.default_rig_id {
|
||||
if rig_id.trim().is_empty() {
|
||||
return Err("[frontends.http].default_rig_id must not be empty when set".to_string());
|
||||
}
|
||||
}
|
||||
if self.frontends.rigctl.enabled && self.frontends.rigctl.rig_ports.is_empty() {
|
||||
return Err(
|
||||
"[frontends.rigctl].rig_ports must contain at least one rig when enabled"
|
||||
@@ -420,6 +431,8 @@ impl ClientConfig {
|
||||
enabled: true,
|
||||
listen: IpAddr::from([127, 0, 0, 1]),
|
||||
port: 8080,
|
||||
default_rig_id: Some("hf".to_string()),
|
||||
show_sdr_gain_control: true,
|
||||
auth: HttpAuthConfig {
|
||||
enabled: false,
|
||||
rx_passphrase: Some("rx-passphrase-example".to_string()),
|
||||
|
||||
@@ -177,6 +177,7 @@ async fn async_init() -> DynResult<AppState> {
|
||||
config::CookieSameSite::Lax => "Lax".to_string(),
|
||||
config::CookieSameSite::None => "None".to_string(),
|
||||
};
|
||||
frontend_runtime.http_show_sdr_gain_control = cfg.frontends.http.show_sdr_gain_control;
|
||||
|
||||
// Resolve remote URL: CLI > config [remote] section > error
|
||||
let remote_url = cli
|
||||
@@ -189,7 +190,11 @@ async fn async_init() -> DynResult<AppState> {
|
||||
parse_remote_url(&remote_url).map_err(|e| format!("Invalid remote URL: {}", e))?;
|
||||
|
||||
let remote_token = cli.token.clone().or_else(|| cfg.remote.auth.token.clone());
|
||||
let remote_rig_id = cli.rig_id.clone().or_else(|| cfg.remote.rig_id.clone());
|
||||
let remote_rig_id = cli
|
||||
.rig_id
|
||||
.clone()
|
||||
.or_else(|| cfg.frontends.http.default_rig_id.clone())
|
||||
.or_else(|| cfg.remote.rig_id.clone());
|
||||
if let Ok(mut guard) = frontend_runtime.remote_active_rig_id.lock() {
|
||||
*guard = remote_rig_id.clone();
|
||||
}
|
||||
|
||||
@@ -166,6 +166,8 @@ pub struct FrontendRuntimeContext {
|
||||
pub http_auth_cookie_secure: bool,
|
||||
/// HTTP frontend auth cookie same-site policy
|
||||
pub http_auth_cookie_same_site: String,
|
||||
/// Whether the HTTP UI should expose the RF Gain control.
|
||||
pub http_show_sdr_gain_control: bool,
|
||||
/// Currently selected remote rig id (used by remote client routing).
|
||||
pub remote_active_rig_id: Arc<Mutex<Option<String>>>,
|
||||
/// Cached remote rig list from GetRigs polling.
|
||||
@@ -199,6 +201,7 @@ impl FrontendRuntimeContext {
|
||||
http_auth_session_ttl_secs: 480 * 60,
|
||||
http_auth_cookie_secure: false,
|
||||
http_auth_cookie_same_site: "Lax".to_string(),
|
||||
http_show_sdr_gain_control: true,
|
||||
remote_active_rig_id: Arc::new(Mutex::new(None)),
|
||||
remote_rigs: Arc::new(Mutex::new(Vec::new())),
|
||||
owner_callsign: None,
|
||||
|
||||
@@ -1281,6 +1281,9 @@ function render(update) {
|
||||
wfmStFlagEl.classList.toggle("wfm-st-flag-mono", !detected);
|
||||
}
|
||||
}
|
||||
if (sdrGainControlsEl && typeof update.show_sdr_gain_control === "boolean") {
|
||||
sdrGainControlsEl.style.display = update.show_sdr_gain_control ? "" : "none";
|
||||
}
|
||||
if (update.status && update.status.freq && typeof update.status.freq.hz === "number") {
|
||||
applyLocalTunedFrequency(update.status.freq.hz, true);
|
||||
}
|
||||
@@ -2574,6 +2577,7 @@ const audioRow = document.getElementById("audio-row");
|
||||
const wfmControlsCol = document.getElementById("wfm-controls-col");
|
||||
const wfmDeemphasisEl = document.getElementById("wfm-deemphasis");
|
||||
const wfmAudioModeEl = document.getElementById("wfm-audio-mode");
|
||||
const sdrGainControlsEl = document.getElementById("sdr-gain-controls");
|
||||
const sdrGainEl = document.getElementById("sdr-gain-db");
|
||||
const sdrGainSetBtn = document.getElementById("sdr-gain-set");
|
||||
const wfmStFlagEl = document.getElementById("wfm-st-flag");
|
||||
|
||||
@@ -165,10 +165,12 @@
|
||||
<option value="mono">Mono</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="wfm-control">RF Gain
|
||||
<input id="sdr-gain-db" class="status-input" type="number" min="0" max="60" step="1" inputmode="decimal">
|
||||
</label>
|
||||
<button id="sdr-gain-set" type="button" class="status-input">Set</button>
|
||||
<div class="inline" id="sdr-gain-controls">
|
||||
<label class="wfm-control">RF Gain
|
||||
<input id="sdr-gain-db" class="status-input" type="number" min="0" max="60" step="1" inputmode="decimal">
|
||||
</label>
|
||||
<button id="sdr-gain-set" type="button" class="status-input">Set</button>
|
||||
</div>
|
||||
<label class="wfm-control wfm-st-flag-wrap" aria-label="Stereo pilot status">
|
||||
<span id="wfm-st-flag" class="wfm-st-flag wfm-st-flag-mono">MO</span>
|
||||
</label>
|
||||
|
||||
@@ -45,6 +45,7 @@ pub async fn status_api(
|
||||
active_rig_id_from_context(context.get_ref().as_ref()),
|
||||
rig_ids_from_context(context.get_ref().as_ref()),
|
||||
owner_callsign_from_context(context.get_ref().as_ref()),
|
||||
show_sdr_gain_control_from_context(context.get_ref().as_ref()),
|
||||
);
|
||||
Ok(HttpResponse::Ok()
|
||||
.insert_header((header::CONTENT_TYPE, "application/json"))
|
||||
@@ -60,6 +61,7 @@ fn inject_frontend_meta(
|
||||
active_rig_id: Option<String>,
|
||||
rig_ids: Vec<String>,
|
||||
owner_callsign: Option<String>,
|
||||
show_sdr_gain_control: bool,
|
||||
) -> String {
|
||||
let mut value: serde_json::Value = match serde_json::from_str(json) {
|
||||
Ok(v) => v,
|
||||
@@ -84,6 +86,10 @@ fn inject_frontend_meta(
|
||||
if let Some(owner) = owner_callsign {
|
||||
map.insert("owner_callsign".to_string(), serde_json::json!(owner));
|
||||
}
|
||||
map.insert(
|
||||
"show_sdr_gain_control".to_string(),
|
||||
serde_json::json!(show_sdr_gain_control),
|
||||
);
|
||||
|
||||
serde_json::to_string(&value).unwrap_or_else(|_| json.to_string())
|
||||
}
|
||||
@@ -118,6 +124,10 @@ fn owner_callsign_from_context(context: &FrontendRuntimeContext) -> Option<Strin
|
||||
context.owner_callsign.clone()
|
||||
}
|
||||
|
||||
fn show_sdr_gain_control_from_context(context: &FrontendRuntimeContext) -> bool {
|
||||
context.http_show_sdr_gain_control
|
||||
}
|
||||
|
||||
#[get("/events")]
|
||||
pub async fn events(
|
||||
state: web::Data<watch::Receiver<RigState>>,
|
||||
@@ -140,6 +150,7 @@ pub async fn events(
|
||||
active_rig_id_from_context(context.get_ref().as_ref()),
|
||||
rig_ids_from_context(context.get_ref().as_ref()),
|
||||
owner_callsign_from_context(context.get_ref().as_ref()),
|
||||
show_sdr_gain_control_from_context(context.get_ref().as_ref()),
|
||||
);
|
||||
let initial_stream =
|
||||
once(async move { Ok::<Bytes, Error>(Bytes::from(format!("data: {initial_json}\n\n"))) });
|
||||
@@ -160,6 +171,7 @@ pub async fn events(
|
||||
active_rig_id_from_context(context.as_ref()),
|
||||
rig_ids_from_context(context.as_ref()),
|
||||
owner_callsign_from_context(context.as_ref()),
|
||||
show_sdr_gain_control_from_context(context.as_ref()),
|
||||
);
|
||||
Ok::<Bytes, Error>(Bytes::from(format!("data: {json}\n\n")))
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user