[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,
|
pub listen: IpAddr,
|
||||||
/// Listen port
|
/// Listen port
|
||||||
pub port: u16,
|
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
|
/// Authentication settings
|
||||||
pub auth: HttpAuthConfig,
|
pub auth: HttpAuthConfig,
|
||||||
}
|
}
|
||||||
@@ -238,6 +242,8 @@ impl Default for HttpFrontendConfig {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
listen: IpAddr::from([127, 0, 0, 1]),
|
listen: IpAddr::from([127, 0, 0, 1]),
|
||||||
port: 8080,
|
port: 8080,
|
||||||
|
default_rig_id: None,
|
||||||
|
show_sdr_gain_control: true,
|
||||||
auth: HttpAuthConfig::default(),
|
auth: HttpAuthConfig::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,6 +335,11 @@ impl ClientConfig {
|
|||||||
if self.frontends.http.enabled && self.frontends.http.port == 0 {
|
if self.frontends.http.enabled && self.frontends.http.port == 0 {
|
||||||
return Err("[frontends.http].port must be > 0 when enabled".to_string());
|
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() {
|
if self.frontends.rigctl.enabled && self.frontends.rigctl.rig_ports.is_empty() {
|
||||||
return Err(
|
return Err(
|
||||||
"[frontends.rigctl].rig_ports must contain at least one rig when enabled"
|
"[frontends.rigctl].rig_ports must contain at least one rig when enabled"
|
||||||
@@ -420,6 +431,8 @@ impl ClientConfig {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
listen: IpAddr::from([127, 0, 0, 1]),
|
listen: IpAddr::from([127, 0, 0, 1]),
|
||||||
port: 8080,
|
port: 8080,
|
||||||
|
default_rig_id: Some("hf".to_string()),
|
||||||
|
show_sdr_gain_control: true,
|
||||||
auth: HttpAuthConfig {
|
auth: HttpAuthConfig {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
rx_passphrase: Some("rx-passphrase-example".to_string()),
|
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::Lax => "Lax".to_string(),
|
||||||
config::CookieSameSite::None => "None".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
|
// Resolve remote URL: CLI > config [remote] section > error
|
||||||
let remote_url = cli
|
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))?;
|
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_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() {
|
if let Ok(mut guard) = frontend_runtime.remote_active_rig_id.lock() {
|
||||||
*guard = remote_rig_id.clone();
|
*guard = remote_rig_id.clone();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,6 +166,8 @@ pub struct FrontendRuntimeContext {
|
|||||||
pub http_auth_cookie_secure: bool,
|
pub http_auth_cookie_secure: bool,
|
||||||
/// HTTP frontend auth cookie same-site policy
|
/// HTTP frontend auth cookie same-site policy
|
||||||
pub http_auth_cookie_same_site: String,
|
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).
|
/// Currently selected remote rig id (used by remote client routing).
|
||||||
pub remote_active_rig_id: Arc<Mutex<Option<String>>>,
|
pub remote_active_rig_id: Arc<Mutex<Option<String>>>,
|
||||||
/// Cached remote rig list from GetRigs polling.
|
/// Cached remote rig list from GetRigs polling.
|
||||||
@@ -199,6 +201,7 @@ impl FrontendRuntimeContext {
|
|||||||
http_auth_session_ttl_secs: 480 * 60,
|
http_auth_session_ttl_secs: 480 * 60,
|
||||||
http_auth_cookie_secure: false,
|
http_auth_cookie_secure: false,
|
||||||
http_auth_cookie_same_site: "Lax".to_string(),
|
http_auth_cookie_same_site: "Lax".to_string(),
|
||||||
|
http_show_sdr_gain_control: true,
|
||||||
remote_active_rig_id: Arc::new(Mutex::new(None)),
|
remote_active_rig_id: Arc::new(Mutex::new(None)),
|
||||||
remote_rigs: Arc::new(Mutex::new(Vec::new())),
|
remote_rigs: Arc::new(Mutex::new(Vec::new())),
|
||||||
owner_callsign: None,
|
owner_callsign: None,
|
||||||
|
|||||||
@@ -1281,6 +1281,9 @@ function render(update) {
|
|||||||
wfmStFlagEl.classList.toggle("wfm-st-flag-mono", !detected);
|
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") {
|
if (update.status && update.status.freq && typeof update.status.freq.hz === "number") {
|
||||||
applyLocalTunedFrequency(update.status.freq.hz, true);
|
applyLocalTunedFrequency(update.status.freq.hz, true);
|
||||||
}
|
}
|
||||||
@@ -2574,6 +2577,7 @@ const audioRow = document.getElementById("audio-row");
|
|||||||
const wfmControlsCol = document.getElementById("wfm-controls-col");
|
const wfmControlsCol = document.getElementById("wfm-controls-col");
|
||||||
const wfmDeemphasisEl = document.getElementById("wfm-deemphasis");
|
const wfmDeemphasisEl = document.getElementById("wfm-deemphasis");
|
||||||
const wfmAudioModeEl = document.getElementById("wfm-audio-mode");
|
const wfmAudioModeEl = document.getElementById("wfm-audio-mode");
|
||||||
|
const sdrGainControlsEl = document.getElementById("sdr-gain-controls");
|
||||||
const sdrGainEl = document.getElementById("sdr-gain-db");
|
const sdrGainEl = document.getElementById("sdr-gain-db");
|
||||||
const sdrGainSetBtn = document.getElementById("sdr-gain-set");
|
const sdrGainSetBtn = document.getElementById("sdr-gain-set");
|
||||||
const wfmStFlagEl = document.getElementById("wfm-st-flag");
|
const wfmStFlagEl = document.getElementById("wfm-st-flag");
|
||||||
|
|||||||
@@ -165,10 +165,12 @@
|
|||||||
<option value="mono">Mono</option>
|
<option value="mono">Mono</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="wfm-control">RF Gain
|
<div class="inline" id="sdr-gain-controls">
|
||||||
<input id="sdr-gain-db" class="status-input" type="number" min="0" max="60" step="1" inputmode="decimal">
|
<label class="wfm-control">RF Gain
|
||||||
</label>
|
<input id="sdr-gain-db" class="status-input" type="number" min="0" max="60" step="1" inputmode="decimal">
|
||||||
<button id="sdr-gain-set" type="button" class="status-input">Set</button>
|
</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">
|
<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>
|
<span id="wfm-st-flag" class="wfm-st-flag wfm-st-flag-mono">MO</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ pub async fn status_api(
|
|||||||
active_rig_id_from_context(context.get_ref().as_ref()),
|
active_rig_id_from_context(context.get_ref().as_ref()),
|
||||||
rig_ids_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()),
|
owner_callsign_from_context(context.get_ref().as_ref()),
|
||||||
|
show_sdr_gain_control_from_context(context.get_ref().as_ref()),
|
||||||
);
|
);
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok()
|
||||||
.insert_header((header::CONTENT_TYPE, "application/json"))
|
.insert_header((header::CONTENT_TYPE, "application/json"))
|
||||||
@@ -60,6 +61,7 @@ fn inject_frontend_meta(
|
|||||||
active_rig_id: Option<String>,
|
active_rig_id: Option<String>,
|
||||||
rig_ids: Vec<String>,
|
rig_ids: Vec<String>,
|
||||||
owner_callsign: Option<String>,
|
owner_callsign: Option<String>,
|
||||||
|
show_sdr_gain_control: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut value: serde_json::Value = match serde_json::from_str(json) {
|
let mut value: serde_json::Value = match serde_json::from_str(json) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
@@ -84,6 +86,10 @@ fn inject_frontend_meta(
|
|||||||
if let Some(owner) = owner_callsign {
|
if let Some(owner) = owner_callsign {
|
||||||
map.insert("owner_callsign".to_string(), serde_json::json!(owner));
|
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())
|
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()
|
context.owner_callsign.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_sdr_gain_control_from_context(context: &FrontendRuntimeContext) -> bool {
|
||||||
|
context.http_show_sdr_gain_control
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/events")]
|
#[get("/events")]
|
||||||
pub async fn events(
|
pub async fn events(
|
||||||
state: web::Data<watch::Receiver<RigState>>,
|
state: web::Data<watch::Receiver<RigState>>,
|
||||||
@@ -140,6 +150,7 @@ pub async fn events(
|
|||||||
active_rig_id_from_context(context.get_ref().as_ref()),
|
active_rig_id_from_context(context.get_ref().as_ref()),
|
||||||
rig_ids_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()),
|
owner_callsign_from_context(context.get_ref().as_ref()),
|
||||||
|
show_sdr_gain_control_from_context(context.get_ref().as_ref()),
|
||||||
);
|
);
|
||||||
let initial_stream =
|
let initial_stream =
|
||||||
once(async move { Ok::<Bytes, Error>(Bytes::from(format!("data: {initial_json}\n\n"))) });
|
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()),
|
active_rig_id_from_context(context.as_ref()),
|
||||||
rig_ids_from_context(context.as_ref()),
|
rig_ids_from_context(context.as_ref()),
|
||||||
owner_callsign_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")))
|
Ok::<Bytes, Error>(Bytes::from(format!("data: {json}\n\n")))
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user