1use std::time::Duration;
4
5use serde_json::{json, Map, Value};
6
7use crate::client::Client;
8use crate::errors::{Error, Result};
9use crate::session::connect_with_retries;
10
11pub fn websocket_url_from_env() -> String {
13 crate::config::load_config_from_env().daemon_url
14}
15
16pub async fn check_daemon_status(client: &Client) -> Result<Map<String, Value>> {
18 client.fetch_daemon_status().await
19}
20
21pub async fn is_daemon_live(
23 ws_url: &str,
24 connect_timeout: Duration,
25 wait_for_ready: bool,
26 ready_timeout: Duration,
27) -> bool {
28 let client = Client::new(ws_url);
29 let connect = async { connect_with_retries(&client, 5, Duration::from_millis(200)).await };
30 if tokio::time::timeout(connect_timeout, connect)
31 .await
32 .ok()
33 .and_then(|r| r.ok())
34 .is_none()
35 {
36 return false;
37 }
38 if !wait_for_ready {
39 let _ = client.close().await;
40 return true;
41 }
42 let deadline = tokio::time::Instant::now() + ready_timeout;
43 let mut ok = false;
44 while tokio::time::Instant::now() < deadline {
45 if let Ok(status) = client.fetch_daemon_status().await {
46 let ready = status.get("readiness_state").and_then(|v| v.as_str()) == Some("ready")
47 || status.get("running").and_then(|v| v.as_bool()) == Some(true);
48 if ready {
49 ok = true;
50 break;
51 }
52 }
53 tokio::time::sleep(Duration::from_millis(100)).await;
54 }
55 let _ = client.close().await;
56 ok
57}
58
59pub async fn protocol1_rpc(
61 ws_url: &str,
62 method: &str,
63 params: Map<String, Value>,
64 mode: &str,
65 rpc_timeout: Duration,
66) -> Map<String, Value> {
67 let client = Client::new(ws_url);
68 if let Err(e) = connect_with_retries(&client, 5, Duration::from_millis(200)).await {
69 let mut m = Map::new();
70 m.insert("error".into(), json!(e.to_string()));
71 return m;
72 }
73 let out = match mode {
74 "notify" => match client.notify(method, params).await {
75 Ok(()) => Map::new(),
76 Err(e) => {
77 let mut m = Map::new();
78 m.insert("error".into(), json!(e.to_string()));
79 m
80 }
81 },
82 "subscribe" => match client.subscribe(method, params, rpc_timeout).await {
83 Ok(id) => {
84 let mut m = Map::new();
85 m.insert("subscription_id".into(), json!(id));
86 m
87 }
88 Err(e) => {
89 let mut m = Map::new();
90 m.insert("error".into(), json!(e.to_string()));
91 m
92 }
93 },
94 _ => match client.request(method, params, rpc_timeout).await {
95 Ok(r) => r,
96 Err(e) => {
97 let mut m = Map::new();
98 m.insert("error".into(), json!(e.to_string()));
99 m
100 }
101 },
102 };
103 let _ = client.close().await;
104 out
105}
106
107pub async fn request_daemon_shutdown(client: &Client) -> Result<()> {
109 let resp = client
110 .request("daemon_shutdown", Map::new(), Duration::from_secs(10))
111 .await?;
112 let status = resp.get("status").and_then(|v| v.as_str()).unwrap_or("");
113 if status != "acknowledged" && !status.is_empty() {
114 return Err(Error::msg(format!("unexpected shutdown status: {status}")));
115 }
116 Ok(())
117}
118
119pub async fn request_daemon_config_reload(client: &Client) -> Result<Map<String, Value>> {
121 client
122 .request("config_reload", Map::new(), Duration::from_secs(5))
123 .await
124}
125
126pub async fn fetch_skills_catalog(client: &Client) -> Result<Map<String, Value>> {
128 client.list_skills().await
129}
130
131pub async fn fetch_config_section(client: &Client, section: &str) -> Result<Map<String, Value>> {
133 let mut params = Map::new();
134 if !section.is_empty() {
135 params.insert("section".into(), json!(section));
136 }
137 client
138 .request("config_get", params, Duration::from_secs(10))
139 .await
140}
141
142pub async fn fetch_loop_history(client: &Client, loop_id: &str) -> Result<Map<String, Value>> {
144 client.loop_history_fetch(loop_id).await
145}
146
147pub async fn fetch_loop_cards(client: &Client, loop_id: &str) -> Result<Map<String, Value>> {
149 client.loop_cards_fetch(loop_id).await
150}
151
152pub async fn request_auth(
154 client: &Client,
155 access_key: &str,
156 secret_key: &str,
157) -> Result<Map<String, Value>> {
158 client.authenticate(access_key, secret_key).await
159}
160
161pub async fn request_auth_refresh(
163 client: &Client,
164 refresh_token: &str,
165) -> Result<Map<String, Value>> {
166 client.refresh_auth_token(refresh_token).await
167}