syspulse_core/ipc/
protocol.rs1use serde::{Deserialize, Serialize};
2use tokio::io::{AsyncReadExt, AsyncWriteExt};
3
4use crate::daemon::{DaemonInstance, DaemonSpec};
5use crate::error::SyspulseError;
6
7#[derive(Debug, Serialize, Deserialize)]
8#[serde(tag = "type", rename_all = "snake_case")]
9pub enum Request {
10 Start {
11 name: String,
12 wait: bool,
13 timeout_secs: Option<u64>,
14 },
15 Stop {
16 name: String,
17 force: bool,
18 timeout_secs: Option<u64>,
19 },
20 Restart {
21 name: String,
22 force: bool,
23 wait: bool,
24 },
25 Status {
26 name: Option<String>,
27 },
28 List,
29 Logs {
30 name: String,
31 lines: usize,
32 stderr: bool,
33 },
34 Add {
35 spec: DaemonSpec,
36 },
37 Remove {
38 name: String,
39 force: bool,
40 },
41 Shutdown,
42 Ping,
43}
44
45#[derive(Debug, Serialize, Deserialize)]
46#[serde(tag = "type", rename_all = "snake_case")]
47pub enum Response {
48 Ok { message: String },
49 Status { instance: DaemonInstance },
50 List { instances: Vec<DaemonInstance> },
51 Logs { lines: Vec<String> },
52 Pong,
53 Error { code: u32, message: String },
54}
55
56pub fn encode_message<T: Serialize>(msg: &T) -> crate::error::Result<Vec<u8>> {
58 let json = serde_json::to_vec(msg)?;
59 let len = (json.len() as u32).to_be_bytes();
60 let mut buf = Vec::with_capacity(4 + json.len());
61 buf.extend_from_slice(&len);
62 buf.extend_from_slice(&json);
63 Ok(buf)
64}
65
66pub async fn read_message<T: serde::de::DeserializeOwned>(
69 reader: &mut (impl AsyncReadExt + Unpin),
70) -> crate::error::Result<Option<T>> {
71 let mut len_buf = [0u8; 4];
72 match reader.read_exact(&mut len_buf).await {
73 Ok(_) => {}
74 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(None),
75 Err(e) => return Err(e.into()),
76 }
77 let len = u32::from_be_bytes(len_buf) as usize;
78 if len > 10 * 1024 * 1024 {
79 return Err(SyspulseError::Ipc("Message too large (>10MB)".into()));
80 }
81 let mut payload = vec![0u8; len];
82 reader.read_exact(&mut payload).await?;
83 let msg = serde_json::from_slice(&payload)?;
84 Ok(Some(msg))
85}
86
87pub async fn write_message<T: Serialize>(
89 writer: &mut (impl AsyncWriteExt + Unpin),
90 msg: &T,
91) -> crate::error::Result<()> {
92 let encoded = encode_message(msg)?;
93 writer.write_all(&encoded).await?;
94 writer.flush().await?;
95 Ok(())
96}