vta_cli_common/commands/
device.rs1use serde_json::{Value, json};
9use vta_sdk::client::VtaClient;
10
11use crate::render::{DIM, RESET, is_json_output, print_json};
12
13fn print_result(label: &str, value: &Value) -> Result<(), Box<dyn std::error::Error>> {
16 if is_json_output() {
17 print_json(value)?;
18 } else {
19 println!("{label}");
20 println!("{}", serde_json::to_string_pretty(value)?);
21 }
22 Ok(())
23}
24
25fn camel(value: &str) -> String {
29 let mut out = String::with_capacity(value.len());
30 let mut upper = false;
31 for ch in value.chars() {
32 match ch {
33 '-' => upper = true,
34 c if upper => {
35 out.extend(c.to_uppercase());
36 upper = false;
37 }
38 c => out.push(c),
39 }
40 }
41 out
42}
43
44pub async fn cmd_device_list(
47 client: &VtaClient,
48 service_kind: Option<String>,
49) -> Result<(), Box<dyn std::error::Error>> {
50 let mut filters = json!({});
51 if let Some(sk) = service_kind {
52 filters["consumerKindFilter"] = json!("service");
53 filters["serviceKindFilter"] = json!(camel(&sk));
54 }
55 let result = client.device_list(filters).await?;
56 print_result("Registered devices:", &result)
57}
58
59pub async fn cmd_device_register(
62 client: &VtaClient,
63 service_kind: String,
64 display_name: String,
65 platform: Option<String>,
66 hpke_public_key: Option<String>,
67) -> Result<(), Box<dyn std::error::Error>> {
68 let consumer_kind = json!({ "kind": "service", "serviceKind": camel(&service_kind) });
69 let result = client
70 .device_register(
71 consumer_kind,
72 &display_name,
73 platform.as_deref(),
74 hpke_public_key.as_deref(),
75 )
76 .await?;
77 println!("{DIM}Device registered.{RESET}");
78 print_result("Binding:", &result)
79}
80
81pub async fn cmd_device_disable(
84 client: &VtaClient,
85 device_id: String,
86) -> Result<(), Box<dyn std::error::Error>> {
87 let result = client.device_disable(&device_id).await?;
88 println!("{DIM}Device {device_id} disabled.{RESET}");
89 print_result("Result:", &result)
90}
91
92pub async fn cmd_device_wipe(
96 client: &VtaClient,
97 device_id: String,
98 reason: String,
99 scope: String,
100) -> Result<(), Box<dyn std::error::Error>> {
101 let scope = camel(&scope);
102 let result = client.device_wipe(&device_id, &reason, &scope).await?;
103 println!("{DIM}Device {device_id} wiped (scope: {scope}).{RESET}");
104 print_result("Result:", &result)
105}
106
107pub async fn cmd_device_set_wake(
110 client: &VtaClient,
111 gateway: String,
112 handle: String,
113 suggested_triggers: Vec<String>,
114) -> Result<(), Box<dyn std::error::Error>> {
115 let result = client
116 .device_set_wake(&gateway, &handle, suggested_triggers)
117 .await?;
118 print_result("Wake handle recorded:", &result)
119}
120
121pub async fn cmd_device_heartbeat(
124 client: &VtaClient,
125 platform: Option<String>,
126) -> Result<(), Box<dyn std::error::Error>> {
127 let result = client.device_heartbeat(platform.as_deref()).await?;
128 print_result("Heartbeat:", &result)
129}