fix(trx-client): increase command timeouts for slow CAT responses
This commit is contained in:
@@ -21,7 +21,7 @@ use trx_protocol::{ClientCommand, ClientEnvelope, ClientResponse};
|
|||||||
|
|
||||||
const DEFAULT_REMOTE_PORT: u16 = 4530;
|
const DEFAULT_REMOTE_PORT: u16 = 4530;
|
||||||
const CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
|
const CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
const IO_TIMEOUT: Duration = Duration::from_secs(10);
|
const IO_TIMEOUT: Duration = Duration::from_secs(15);
|
||||||
const MAX_JSON_LINE_BYTES: usize = 16 * 1024;
|
const MAX_JSON_LINE_BYTES: usize = 16 * 1024;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const FAVICON_BYTES: &[u8] = include_bytes!(concat!(
|
|||||||
));
|
));
|
||||||
const LOGO_BYTES: &[u8] =
|
const LOGO_BYTES: &[u8] =
|
||||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/trx-logo.png"));
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/trx-logo.png"));
|
||||||
|
const REQUEST_TIMEOUT: Duration = Duration::from_secs(15);
|
||||||
|
|
||||||
#[get("/status")]
|
#[get("/status")]
|
||||||
pub async fn status_api(
|
pub async fn status_api(
|
||||||
@@ -714,7 +715,7 @@ async fn send_command(
|
|||||||
actix_web::error::ErrorInternalServerError(format!("failed to send to rig: {e:?}"))
|
actix_web::error::ErrorInternalServerError(format!("failed to send to rig: {e:?}"))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let resp = tokio::time::timeout(Duration::from_secs(8), resp_rx)
|
let resp = tokio::time::timeout(REQUEST_TIMEOUT, resp_rx)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| actix_web::error::ErrorGatewayTimeout("rig response timeout"))?;
|
.map_err(|_| actix_web::error::ErrorGatewayTimeout("rig response timeout"))?;
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ use std::net::SocketAddr;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio::sync::{mpsc, oneshot, watch};
|
use tokio::sync::{mpsc, oneshot, watch};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
use trx_protocol::{mode_to_string, parse_mode};
|
use trx_protocol::{mode_to_string, parse_mode};
|
||||||
|
|
||||||
@@ -130,12 +130,10 @@ async fn process_command(
|
|||||||
Err(e) => err_response(&e),
|
Err(e) => err_response(&e),
|
||||||
},
|
},
|
||||||
"F" | "\\set_freq" => match parts.next().and_then(parse_freq_hz_arg) {
|
"F" | "\\set_freq" => match parts.next().and_then(parse_freq_hz_arg) {
|
||||||
Some(freq) => {
|
Some(freq) => match send_set_freq_with_compat_retry(rig_tx, freq).await {
|
||||||
match send_set_freq_with_compat_retry(rig_tx, freq).await {
|
Ok(_) => ok_only(op, extended),
|
||||||
Ok(_) => ok_only(op, extended),
|
Err(e) => err_response(&e),
|
||||||
Err(e) => err_response(&e),
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
None => err_response("expected frequency in Hz"),
|
None => err_response("expected frequency in Hz"),
|
||||||
},
|
},
|
||||||
"l" | "\\get_level" => {
|
"l" | "\\get_level" => {
|
||||||
@@ -162,13 +160,11 @@ async fn process_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"t" | "\\get_ptt" | "get_ptt" => match request_snapshot(rig_tx).await {
|
"t" | "\\get_ptt" | "get_ptt" => match request_snapshot(rig_tx).await {
|
||||||
Ok(snapshot) => {
|
Ok(snapshot) => ok_response(
|
||||||
ok_response(
|
op,
|
||||||
op,
|
extended,
|
||||||
extended,
|
[if snapshot.status.tx_en { "1" } else { "0" }.to_string()],
|
||||||
[if snapshot.status.tx_en { "1" } else { "0" }.to_string()],
|
),
|
||||||
)
|
|
||||||
}
|
|
||||||
Err(e) => err_response(&e),
|
Err(e) => err_response(&e),
|
||||||
},
|
},
|
||||||
"T" | "\\set_ptt" | "set_ptt" => match parse_ptt_tokens(parts.collect()) {
|
"T" | "\\set_ptt" | "set_ptt" => match parse_ptt_tokens(parts.collect()) {
|
||||||
@@ -345,7 +341,7 @@ async fn send_rig_command(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| format!("failed to send to rig: {e:?}"))?;
|
.map_err(|e| format!("failed to send to rig: {e:?}"))?;
|
||||||
|
|
||||||
match timeout(Duration::from_secs(5), resp_rx).await {
|
match timeout(Duration::from_secs(15), resp_rx).await {
|
||||||
Ok(Ok(Ok(snapshot))) => Ok(snapshot),
|
Ok(Ok(Ok(snapshot))) => Ok(snapshot),
|
||||||
Ok(Ok(Err(err))) => Err(err.message),
|
Ok(Ok(Err(err))) => Err(err.message),
|
||||||
Ok(Err(e)) => Err(format!("rig response error: {e:?}")),
|
Ok(Err(e)) => Err(format!("rig response error: {e:?}")),
|
||||||
@@ -451,16 +447,8 @@ fn dump_caps_response(op: &str, extended: bool, snapshot: &RigSnapshot) -> Strin
|
|||||||
push(&mut resp, "protocol_version", "1".to_string());
|
push(&mut resp, "protocol_version", "1".to_string());
|
||||||
push(&mut resp, "rig_model", "2".to_string());
|
push(&mut resp, "rig_model", "2".to_string());
|
||||||
push(&mut resp, "model_name", snapshot.info.model.clone());
|
push(&mut resp, "model_name", snapshot.info.model.clone());
|
||||||
push(
|
push(&mut resp, "mfg_name", snapshot.info.manufacturer.clone());
|
||||||
&mut resp,
|
push(&mut resp, "backend_version", snapshot.info.revision.clone());
|
||||||
"mfg_name",
|
|
||||||
snapshot.info.manufacturer.clone(),
|
|
||||||
);
|
|
||||||
push(
|
|
||||||
&mut resp,
|
|
||||||
"backend_version",
|
|
||||||
snapshot.info.revision.clone(),
|
|
||||||
);
|
|
||||||
push(
|
push(
|
||||||
&mut resp,
|
&mut resp,
|
||||||
"vfo_count",
|
"vfo_count",
|
||||||
@@ -486,7 +474,11 @@ fn dump_caps_response(op: &str, extended: bool, snapshot: &RigSnapshot) -> Strin
|
|||||||
);
|
);
|
||||||
resp.push_str("done\n");
|
resp.push_str("done\n");
|
||||||
if extended {
|
if extended {
|
||||||
ok_response(op, true, resp.lines().map(|s| s.to_string()).collect::<Vec<_>>())
|
ok_response(
|
||||||
|
op,
|
||||||
|
true,
|
||||||
|
resp.lines().map(|s| s.to_string()).collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
@@ -514,11 +506,7 @@ async fn set_vfo_target(target: &str, rig_tx: &mpsc::Sender<RigRequest>) -> Resu
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let supports_toggle = snapshot
|
let supports_toggle = snapshot.info.capabilities.num_vfos >= 2
|
||||||
.info
|
|
||||||
.capabilities
|
|
||||||
.num_vfos
|
|
||||||
>= 2
|
|
||||||
&& snapshot
|
&& snapshot
|
||||||
.status
|
.status
|
||||||
.vfo
|
.vfo
|
||||||
@@ -681,7 +669,9 @@ mod tests {
|
|||||||
fn dump_caps_is_setting_value_and_ends_with_done() {
|
fn dump_caps_is_setting_value_and_ends_with_done() {
|
||||||
let response = dump_caps_response("dump_caps", false, &test_snapshot());
|
let response = dump_caps_response("dump_caps", false, &test_snapshot());
|
||||||
let lines: Vec<&str> = response.lines().collect();
|
let lines: Vec<&str> = response.lines().collect();
|
||||||
assert!(lines.iter().all(|line| *line == "done" || line.contains('=')));
|
assert!(lines
|
||||||
|
.iter()
|
||||||
|
.all(|line| *line == "done" || line.contains('=')));
|
||||||
assert_eq!(lines.last(), Some(&"done"));
|
assert_eq!(lines.last(), Some(&"done"));
|
||||||
assert!(response.contains("model_name=Virtual\n"));
|
assert!(response.contains("model_name=Virtual\n"));
|
||||||
assert!(response.contains("mfg_name=TRX\n"));
|
assert!(response.contains("mfg_name=TRX\n"));
|
||||||
@@ -719,10 +709,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn parse_ptt_tokens_accepts_optional_vfo_prefix() {
|
fn parse_ptt_tokens_accepts_optional_vfo_prefix() {
|
||||||
assert_eq!(parse_ptt_tokens(vec!["1"]), Some("1".to_string()));
|
assert_eq!(parse_ptt_tokens(vec!["1"]), Some("1".to_string()));
|
||||||
assert_eq!(
|
assert_eq!(parse_ptt_tokens(vec!["VFOA", "1"]), Some("1".to_string()));
|
||||||
parse_ptt_tokens(vec!["VFOA", "1"]),
|
|
||||||
Some("1".to_string())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_ptt_tokens(vec!["VFOB", "ON_DATA"]),
|
parse_ptt_tokens(vec!["VFOB", "ON_DATA"]),
|
||||||
Some("ON_DATA".to_string())
|
Some("ON_DATA".to_string())
|
||||||
|
|||||||
Reference in New Issue
Block a user