Skip to main content

keep_running/
protocol.rs

1use serde::{Deserialize, Serialize};
2
3/// Messages sent from client to daemon
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub enum ClientMessage {
6    /// Attach to the session with terminal size
7    Attach { cols: u16, rows: u16 },
8
9    /// Input data from client's terminal
10    Input(Vec<u8>),
11
12    /// Terminal was resized
13    Resize { cols: u16, rows: u16 },
14
15    /// Client is detaching
16    Detach,
17}
18
19/// Messages sent from daemon to client
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub enum DaemonMessage {
22    /// Successfully attached
23    Attached,
24
25    /// Output data from PTY
26    Output(Vec<u8>),
27
28    /// Replay of buffered history is starting (client should suppress rendering)
29    ReplayStart,
30
31    /// Replay of buffered history is complete (client should resume rendering)
32    ReplayEnd,
33
34    /// Child process exited
35    ChildExited { code: Option<i32> },
36
37    /// Error occurred
38    Error(String),
39}
40
41/// Encode a message for wire transmission (length-prefixed bincode)
42pub fn encode_message<T: Serialize>(msg: &T) -> anyhow::Result<Vec<u8>> {
43    let payload = bincode::serde::encode_to_vec(msg, bincode::config::standard())?;
44    let len = payload.len() as u32;
45    let mut buf = len.to_be_bytes().to_vec();
46    buf.extend(payload);
47    Ok(buf)
48}
49
50/// Decode a length-prefixed message from a buffer
51/// Returns (message, bytes_consumed) or None if incomplete
52pub fn decode_message<T: for<'de> Deserialize<'de>>(
53    buf: &[u8],
54) -> anyhow::Result<Option<(T, usize)>> {
55    if buf.len() < 4 {
56        return Ok(None);
57    }
58
59    let len = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]) as usize;
60    let total = 4 + len;
61
62    if buf.len() < total {
63        return Ok(None);
64    }
65
66    let (msg, _): (T, usize) =
67        bincode::serde::decode_from_slice(&buf[4..total], bincode::config::standard())?;
68    Ok(Some((msg, total)))
69}