libsurfer/remote/
client.rs

1use super::HierarchyResponse;
2use bincode::Options;
3use color_eyre::eyre::{bail, eyre};
4use color_eyre::Result;
5use log::info;
6use wellen::CompressedTimeTable;
7
8use surver::{
9    Status, BINCODE_OPTIONS, HTTP_SERVER_KEY, HTTP_SERVER_VALUE_SURFER, SURFER_VERSION,
10    WELLEN_VERSION, X_SURFER_VERSION, X_WELLEN_VERSION,
11};
12
13fn check_response(server_url: &str, response: &reqwest::Response) -> Result<()> {
14    let server = response
15        .headers()
16        .get(HTTP_SERVER_KEY)
17        .ok_or(eyre!("no server header"))?
18        .to_str()?;
19    if server != HTTP_SERVER_VALUE_SURFER {
20        bail!("Unexpected server {server} from {server_url}");
21    }
22    let surfer_version = response
23        .headers()
24        .get(X_SURFER_VERSION)
25        .ok_or(eyre!("no surfer version header"))?
26        .to_str()?;
27    if surfer_version != SURFER_VERSION {
28        // this mismatch may be OK as long as the wellen version matches
29        info!("Surfer version on the server: {surfer_version} does not match client version {SURFER_VERSION}");
30    }
31    let wellen_version = response
32        .headers()
33        .get(X_WELLEN_VERSION)
34        .ok_or(eyre!("no wellen version header"))?
35        .to_str()?;
36    if wellen_version != WELLEN_VERSION {
37        bail!("Version incompatibility! The server uses wellen {wellen_version}, our client uses wellen {WELLEN_VERSION}");
38    }
39    Ok(())
40}
41
42pub async fn get_status(server: String) -> Result<Status> {
43    let client = reqwest::Client::new();
44    let response = client.get(format!("{server}/get_status")).send().await?;
45    check_response(&server, &response)?;
46    let body = response.text().await?;
47    let status = serde_json::from_str::<Status>(&body)?;
48    Ok(status)
49}
50
51pub async fn get_hierarchy(server: String) -> Result<HierarchyResponse> {
52    let client = reqwest::Client::new();
53    let response = client.get(format!("{server}/get_hierarchy")).send().await?;
54    check_response(&server, &response)?;
55    let compressed = response.bytes().await?;
56    let raw = lz4_flex::decompress_size_prepended(&compressed)?;
57    let mut reader = std::io::Cursor::new(raw);
58    // first we read a value, expecting there to be more bytes
59    let opts = BINCODE_OPTIONS.allow_trailing_bytes();
60    let file_format: wellen::FileFormat = opts.deserialize_from(&mut reader)?;
61    // the last value should consume all remaining bytes
62    let hierarchy: wellen::Hierarchy = BINCODE_OPTIONS.deserialize_from(&mut reader)?;
63    Ok(HierarchyResponse {
64        hierarchy,
65        file_format,
66    })
67}
68
69pub async fn get_time_table(server: String) -> Result<Vec<wellen::Time>> {
70    let client = reqwest::Client::new();
71    let response = client
72        .get(format!("{server}/get_time_table"))
73        .send()
74        .await?;
75    check_response(&server, &response)?;
76    let compressed_data = response.bytes().await?;
77    let compressed: CompressedTimeTable = BINCODE_OPTIONS.deserialize(&compressed_data)?;
78    let table = compressed.uncompress();
79    Ok(table)
80}
81
82pub async fn get_signals(
83    server: String,
84    signals: &[wellen::SignalRef],
85) -> Result<Vec<(wellen::SignalRef, wellen::Signal)>> {
86    let client = reqwest::Client::new();
87    let mut url = format!("{server}/get_signals");
88    for signal in signals.iter() {
89        url.push_str(&format!("/{}", signal.index()));
90    }
91
92    let response = client.get(url).send().await?;
93    check_response(&server, &response)?;
94    let data = response.bytes().await?;
95    let mut reader = std::io::Cursor::new(data);
96    let num_ids: u64 = leb128::read::unsigned(&mut reader)?;
97    if num_ids > signals.len() as u64 {
98        bail!(
99            "Too many signals in response: {num_ids}, expected {}",
100            signals.len()
101        );
102    }
103    if num_ids == 0 {
104        return Ok(vec![]);
105    }
106
107    let opts = BINCODE_OPTIONS.allow_trailing_bytes();
108    let mut out = Vec::with_capacity(num_ids as usize);
109    for _ in 0..(num_ids - 1) {
110        let compressed: wellen::CompressedSignal = opts.deserialize_from(&mut reader)?;
111        let signal = compressed.uncompress();
112        out.push((signal.signal_ref(), signal));
113    }
114    // for the final signal, we expect to consume all bytes
115    let compressed: wellen::CompressedSignal = BINCODE_OPTIONS.deserialize_from(&mut reader)?;
116    let signal = compressed.uncompress();
117    out.push((signal.signal_ref(), signal));
118    Ok(out)
119}