1use crate::config::AssistantConfig;
10use banc_icd::node::Identity;
11use banc_icd::{IdentifyEndpoint, PROTOCOL_VERSION};
12use postcard_rpc::header::VarSeqKind;
13use postcard_rpc::host_client::HostClient;
14use postcard_rpc::standard_icd::{WireError, ERROR_PATH};
15
16pub struct Node {
17 client: HostClient<WireError>,
18 pub identity: Identity,
19}
20
21impl Node {
22 pub async fn connect(cfg: &AssistantConfig, token: Option<&str>) -> anyhow::Result<Node> {
26 if let Some(addr) = &cfg.addr {
27 let token = token.ok_or_else(|| {
28 anyhow::anyhow!("node '{}' has addr but no token was resolved", cfg.name)
29 })?;
30 let client = crate::net::connect_node(addr, token).await?;
31 return Self::identify(client, &cfg.name).await;
32 }
33 let serial = cfg.serial.clone();
34 let product = cfg.product.clone();
35 let name = cfg.name.clone();
36 let client = HostClient::try_new_raw_nusb(
37 move |d| {
38 let serial_ok = serial
39 .as_deref()
40 .is_none_or(|want| d.serial_number() == Some(want));
41 let product_ok = product
42 .as_deref()
43 .is_none_or(|want| d.product_string() == Some(want));
44 serial_ok && product_ok
45 },
46 ERROR_PATH,
47 8,
48 VarSeqKind::Seq2,
49 )
50 .map_err(|e| anyhow::anyhow!("connecting to node '{name}': {e}"))?;
51 Self::identify(client, &cfg.name).await
52 }
53
54 async fn identify(client: HostClient<WireError>, name: &str) -> anyhow::Result<Node> {
55 let identity = client
56 .send_resp::<IdentifyEndpoint>(&())
57 .await
58 .map_err(|e| anyhow::anyhow!("identify on node '{name}': {e:?}"))?;
59 anyhow::ensure!(
60 identity.protocol_version == PROTOCOL_VERSION,
61 "node '{name}' speaks banc protocol v{}, host expects v{PROTOCOL_VERSION}",
62 identity.protocol_version,
63 );
64 Ok(Node { client, identity })
65 }
66
67 pub fn client(&self) -> &HostClient<WireError> {
69 &self.client
70 }
71
72 pub async fn reset(&self) -> anyhow::Result<()> {
74 self.client
75 .send_resp::<banc_icd::ResetEndpoint>(&())
76 .await
77 .map_err(|e| anyhow::anyhow!("reset: {e:?}"))?;
78 Ok(())
79 }
80}