Skip to main content

unifier/
envelope.rs

1//! Mailbox envelope: sender, recipient, unique id, and data packet.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use uuid::Uuid;
6
7use crate::error::Result;
8
9/// Sender used when `send` does not specify `--from`.
10pub const DEFAULT_SENDER: &str = "unifier";
11
12/// Point-to-point mailbox message stored as JSON in `mailbox/<to>/<id>.txt`.
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct Envelope {
15    pub id: Uuid,
16    pub from: String,
17    pub to: String,
18    pub payload: Value,
19}
20
21impl Envelope {
22    pub fn new(from: impl Into<String>, to: impl Into<String>, payload: Value) -> Self {
23        Self {
24            id: Uuid::new_v4(),
25            from: from.into(),
26            to: to.into(),
27            payload,
28        }
29    }
30
31    pub fn with_id(
32        id: Uuid,
33        from: impl Into<String>,
34        to: impl Into<String>,
35        payload: Value,
36    ) -> Self {
37        Self {
38            id,
39            from: from.into(),
40            to: to.into(),
41            payload,
42        }
43    }
44
45    /// Parse JSON when possible; otherwise treat the raw text as a string packet.
46    pub fn parse_payload(raw: &str) -> Value {
47        serde_json::from_str(raw).unwrap_or_else(|_| Value::String(raw.to_string()))
48    }
49
50    pub fn to_json(&self) -> Result<String> {
51        Ok(serde_json::to_string(self)?)
52    }
53
54    pub fn from_json(line: &str) -> Result<Self> {
55        Ok(serde_json::from_str(line.trim())?)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn roundtrip_json_payload() {
65        let env = Envelope::new("alice", "bob", serde_json::json!({"hello": "world"}));
66        let parsed: Envelope = serde_json::from_str(&env.to_json().unwrap()).unwrap();
67        assert_eq!(parsed.from, "alice");
68        assert_eq!(parsed.to, "bob");
69        assert_eq!(parsed.id, env.id);
70        assert_eq!(parsed.payload["hello"], "world");
71    }
72}