skiff_cli/session/
client.rs1use std::io::{Read, Write};
4use std::os::unix::net::UnixStream;
5use std::time::Duration;
6
7use serde_json::Value;
8
9use crate::error::{Error, Result};
10use crate::session::paths::session_sock_path;
11use crate::session::protocol::{SessionRequest, SessionResponse};
12
13const CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
14const REQUEST_TIMEOUT: Duration = Duration::from_secs(300);
15
16pub fn session_request(name: &str, method: &str, params: Value) -> Result<Value> {
18 let sock = session_sock_path(name);
19 if !sock.exists() {
20 return Err(Error::runtime(format!(
21 "session {name:?} is not running (socket missing). Start with --session-start {name}"
22 )));
23 }
24
25 let mut stream = UnixStream::connect(&sock).map_err(|e| {
26 Error::runtime(format!(
27 "cannot connect to session {name:?}: {e}. Start with --session-start {name}"
28 ))
29 })?;
30 stream
31 .set_read_timeout(Some(REQUEST_TIMEOUT))
32 .map_err(|e| Error::runtime(e.to_string()))?;
33 stream
34 .set_write_timeout(Some(CONNECT_TIMEOUT))
35 .map_err(|e| Error::runtime(e.to_string()))?;
36
37 let req = SessionRequest {
38 id: 1,
39 method: method.to_string(),
40 params,
41 };
42 let mut line = serde_json::to_string(&req)?;
43 line.push('\n');
44 stream
45 .write_all(line.as_bytes())
46 .map_err(|e| Error::runtime(format!("session write failed: {e}")))?;
47 let _ = stream.shutdown(std::net::Shutdown::Write);
48
49 let mut buf = String::new();
50 stream
51 .read_to_string(&mut buf)
52 .map_err(|e| Error::runtime(format!("session read failed: {e}")))?;
53 let line = buf.lines().next().unwrap_or("").trim();
54 if line.is_empty() {
55 return Err(Error::runtime(format!(
56 "session {name:?} closed without a response"
57 )));
58 }
59 let resp: SessionResponse = serde_json::from_str(line)
60 .map_err(|e| Error::runtime(format!("invalid session response: {e}")))?;
61 if let Some(err) = resp.error {
62 return Err(Error::runtime(err));
63 }
64 Ok(resp.result.unwrap_or(Value::Null))
65}