gioser

tawasuyu/brahman

Rust 582TOML 222Markdown 73JSON 198635 Definiciones

⎇ be4de986bef3409a6d4108ccadbcf28436c862c1 crates/runtime/sandokan-daemon/src/protocol.rs Rust · 76 líneas · 2.4 KB Historia Quién tocó qué crudo

feat(sandokan-daemon): B1.3 — DaemonEngine + protocolo wire b7d9d7abd · sergio ·

1//! Protocolo wire del daemon: requests/responses + framing.
2//!
3//! Encoding: postcard. Framing: prefijo de longitud `u32` little-endian
4//! seguido de los bytes postcard. Mismo patrón que el wire de shuma.
5
6use sandokan_core::{EngineError, ExecHandle, Intent, TelemetryFrame};
7use sandokan_lifecycle::LifecycleState;
8use serde::{Deserialize, Serialize};
9use tokio::io::{AsyncReadExt, AsyncWriteExt};
10use ulid::Ulid;
11
12/// Request del cliente al daemon. Espeja los métodos de `Engine`.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub enum DaemonRequest {
15    Run(Intent),
16    Stop { card_id: Ulid, grace_ms: u64 },
17    List,
18    Status { card_id: Ulid },
19    Telemetry { card_id: Ulid },
20}
21
22/// Response del daemon al cliente. Una variante por resultado posible.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub enum DaemonResponse {
25    Ran(ExecHandle),
26    Stopped,
27    Listed(Vec<ExecHandle>),
28    Status(LifecycleState),
29    Telemetry(TelemetryFrame),
30    Err(EngineError),
31}
32
33/// Límite defensivo de tamaño de frame (16 MiB). Un Intent con una Card
34/// grande sigue cabiendo; protege contra frames corruptos/maliciosos.
35pub const MAX_FRAME: u32 = 16 * 1024 * 1024;
36
37/// Escribe un valor serializable como frame length-prefixed.
38pub async fn write_frame<W, T>(w: &mut W, value: &T) -> std::io::Result<()>
39where
40    W: AsyncWriteExt + Unpin,
41    T: Serialize,
42{
43    let bytes = postcard::to_stdvec(value)
44        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
45    if bytes.len() as u64 > MAX_FRAME as u64 {
46        return Err(std::io::Error::new(
47            std::io::ErrorKind::InvalidData,
48            "frame excede MAX_FRAME",
49        ));
50    }
51    w.write_all(&(bytes.len() as u32).to_le_bytes()).await?;
52    w.write_all(&bytes).await?;
53    w.flush().await?;
54    Ok(())
55}
56
57/// Lee un frame length-prefixed y lo deserializa.
58pub async fn read_frame<R, T>(r: &mut R) -> std::io::Result<T>
59where
60    R: AsyncReadExt + Unpin,
61    T: for<'de> Deserialize<'de>,
62{
63    let mut len_buf = [0u8; 4];
64    r.read_exact(&mut len_buf).await?;
65    let len = u32::from_le_bytes(len_buf);
66    if len > MAX_FRAME {
67        return Err(std::io::Error::new(
68            std::io::ErrorKind::InvalidData,
69            "frame entrante excede MAX_FRAME",
70        ));
71    }
72    let mut buf = vec![0u8; len as usize];
73    r.read_exact(&mut buf).await?;
74    postcard::from_bytes(&buf)
75        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
76}