1#![allow(dead_code)]
2
3use crate::{Error, Result};
4use serde::Deserialize;
5use serde::Serialize;
6use serde_json::{Map, Value};
7use simple_error::bail;
8
9#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
13pub struct Message {
14    pub src: String,
15    pub dest: String,
16    pub body: MessageBody,
17}
18
19#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
21pub struct MessageBody {
22    #[serde(rename = "type", default, skip_serializing_if = "String::is_empty")]
24    pub typ: String,
25
26    #[serde(default, skip_serializing_if = "u64_zero_by_ref")]
28    pub msg_id: u64,
29
30    #[serde(default, skip_serializing_if = "u64_zero_by_ref")]
32    pub in_reply_to: u64,
33
34    #[serde(flatten)]
36    pub extra: Map<String, Value>,
37}
38
39#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
41pub struct InitMessageBody {
42    #[serde(default)]
44    pub node_id: String,
45
46    #[serde(rename = "node_ids", default)]
48    pub nodes: Vec<String>,
49}
50
51#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]
53pub struct ErrorMessageBody {
54    #[serde(rename = "type")]
56    pub typ: String,
57
58    #[serde(default)]
60    pub code: i32,
61
62    #[serde(default)]
64    pub text: String,
65}
66
67impl Message {
68    #[must_use]
69    pub fn get_type(&self) -> &str {
70        return self.body.typ.as_str();
71    }
72}
73
74impl MessageBody {
75    #[must_use]
76    pub fn new() -> Self {
77        Self::default()
78    }
79
80    #[must_use]
81    pub fn with_type(self, typ: impl Into<String>) -> Self {
82        let mut t = self;
83        t.typ = typ.into();
84        t
85    }
86
87    #[must_use]
88    pub fn with_reply_to(self, in_reply_to: u64) -> Self {
89        let mut t = self;
90        t.in_reply_to = in_reply_to;
91        t
92    }
93
94    #[must_use]
95    pub fn and_msg_id(self, msg_id: u64) -> Self {
96        let mut t = self;
97        t.msg_id = msg_id;
98        t
99    }
100
101    #[must_use]
102    pub fn from_extra(extra: Map<String, Value>) -> Self {
103        MessageBody {
104            extra,
105            ..Default::default()
106        }
107    }
108
109    #[must_use]
110    pub fn is_error(&self) -> bool {
111        self.typ == "error"
112    }
113
114    #[must_use]
126    pub fn raw(&self) -> Value {
127        let mut raw = self.extra.clone();
131        drop(raw.insert("type".to_string(), Value::String(self.typ.clone())));
132        Value::Object(raw)
133    }
134
135    pub fn as_obj<'de, T>(&self) -> Result<T>
148    where
149        T: Deserialize<'de>,
150    {
151        match T::deserialize(self.raw()) {
152            Ok(t) => Ok(t),
153            Err(e) => Err(Box::new(e)),
154        }
155    }
156}
157
158impl ErrorMessageBody {
159    pub fn new(code: i32, text: impl Into<String>) -> Self {
160        ErrorMessageBody {
161            typ: "error".to_string(),
162            code,
163            text: text.into(),
164        }
165    }
166
167    #[must_use]
168    pub fn from_error(err: Error) -> Self {
169        Self::from(err)
170    }
171}
172
173impl From<Error> for ErrorMessageBody {
174    fn from(value: Error) -> Self {
175        return ErrorMessageBody {
176            typ: "error".to_string(),
177            code: value.code(),
178            text: match value {
179                Error::NotSupported(t) => format!("{t} message type is not supported"),
180                Error::Custom(id, t) => format!("error({id}): {t}"),
181                o => o.description().to_string(),
182            },
183        };
184    }
185}
186
187pub fn message<T>(from: impl Into<String>, to: impl Into<String>, message: T) -> Result<Message>
188where
189    T: Serialize,
190{
191    let body = match serde_json::to_value(message) {
192        Ok(v) => match v {
193            Value::Object(m) => m,
194            _ => bail!("response object has invalid serde_json::Value kind"),
195        },
196        Err(e) => bail!("response object is invalid, can't convert: {}", e),
197    };
198
199    let msg = Message {
200        src: from.into(),
201        dest: to.into(),
202        body: MessageBody::from_extra(body),
203    };
204
205    Ok(msg)
206}
207
208#[allow(clippy::trivially_copy_pass_by_ref)]
209fn u64_zero_by_ref(num: &u64) -> bool {
210    *num == 0
211}
212
213#[cfg(test)]
214mod test {
215    use crate::protocol::{InitMessageBody, Message, MessageBody};
216    use crate::runtime::Result;
217    use serde_json::{Map, Value};
218
219    #[test]
220    fn parse_message() -> Result<()> {
221        let echo = r#"{ "src": "c1", "dest": "n1", "body": { "type": "echo", "msg_id": 1, "echo": "Please echo 35" }}"#;
222
223        let msg = serde_json::from_str::<Message>(&echo)?;
224        let expected = Message {
225            src: "c1".to_string(),
226            dest: "n1".to_string(),
227            body: MessageBody::from_extra(Map::from_iter([(
228                "echo".to_string(),
229                Value::String("Please echo 35".to_string()),
230            )]))
231            .with_type("echo")
232            .and_msg_id(1),
233        };
234        assert_eq!(msg, expected);
235        Ok(())
236    }
237
238    #[test]
239    fn parse_init_message() -> Result<()> {
240        let init = r#"{"type":"init","msg_id":1,"node_id":"n0","node_ids":["n0","n1"]}"#;
241        let msg: InitMessageBody = serde_json::from_str(&init)?;
242        let expect = InitMessageBody::example("n0", &["n0", "n1"]);
243        assert_eq!(msg, expect);
244        Ok(())
245    }
246
247    impl InitMessageBody {
248        fn example(n: &str, s: &[&str]) -> Self {
249            return InitMessageBody {
250                node_id: n.to_string(),
251                nodes: s.iter().map(|x| x.to_string()).collect(),
252            };
253        }
254    }
255}