use std::path::Path;
use std::time::Duration;
use anyhow::{anyhow, Context as _, Result};
use serde_json::{json, Value};
use trusty_common::uds::send_framed_request_capped;
use trusty_common::uds::server::RpcResponse;
use crate::transport::uds::MAX_FRAME_BYTES;
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
pub async fn call(method: &str, params: Value) -> Result<Value> {
call_with_timeout(method, params, DEFAULT_TIMEOUT).await
}
pub async fn call_with_timeout(method: &str, params: Value, timeout: Duration) -> Result<Value> {
let socket =
crate::transport::uds::socket_path().context("resolve the trusty-memory socket path")?;
call_at(&socket, method, params, timeout).await
}
pub async fn call_at(
socket: &Path,
method: &str,
params: Value,
timeout: Duration,
) -> Result<Value> {
let request = json!({
"jsonrpc": "2.0",
"id": 1,
"method": method,
"params": params,
});
let response: RpcResponse =
send_framed_request_capped(socket, &request, timeout, MAX_FRAME_BYTES)
.await
.with_context(|| {
format!(
"call {method} on the trusty-memory daemon at {}",
socket.display()
)
})?;
match (response.result, response.error) {
(Some(result), _) => Ok(result),
(None, Some(e)) => Err(anyhow!("{method} failed: {} ({})", e.message, e.code)),
(None, None) => Err(anyhow!(
"{method} answered with neither a result nor an error"
)),
}
}
pub async fn is_running() -> bool {
let Ok(socket) = crate::transport::uds::socket_path() else {
return false;
};
trusty_common::uds::socket_is_serving(&socket, Duration::from_millis(500)).await
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn client_reports_a_dead_socket_rather_than_hanging() {
let tmp = tempfile::tempdir().expect("tempdir");
let started = std::time::Instant::now();
let result = call_at(
&tmp.path().join("absent.sock"),
"memory.status",
json!({}),
Duration::from_secs(30),
)
.await;
assert!(result.is_err(), "an absent socket cannot answer");
assert!(
started.elapsed() < Duration::from_secs(5),
"a refused dial must not wait out the budget: {:?}",
started.elapsed()
);
}
}