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}