zeronet_protocol/message/
mod.rs

1use crate::error::Error;
2use crate::requestable::Requestable;
3use crate::util::is_default;
4use serde::de::DeserializeOwned;
5use serde::{Deserialize, Serialize};
6
7pub mod templates;
8pub mod value;
9
10use value::Value;
11
12#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
13pub struct Response {
14  pub cmd:  String,
15  pub to:   usize,
16  #[serde(flatten)]
17  response: Value,
18}
19
20impl Response {
21  pub fn body<V: DeserializeOwned + Serialize>(&self) -> Result<V, Error> {
22    let result = serde_json::to_value(&self.response)?;
23    let result = serde_json::from_value(result)?;
24    Ok(result)
25  }
26}
27
28#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
29pub struct Request {
30  pub cmd:    String,
31  pub req_id: usize,
32  #[serde(default, skip_serializing_if = "is_default")]
33  params:     Value,
34}
35
36impl Request {
37  pub fn body<V: DeserializeOwned + Serialize>(&self) -> Result<V, Error> {
38    let result = serde_json::to_value(&self.params)?;
39    let result = serde_json::from_value(result)?;
40    Ok(result)
41  }
42}
43
44#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
45#[serde(untagged, rename_all = "camelCase")]
46pub enum ZeroMessage {
47  Response(Response),
48  Request(Request),
49}
50
51impl ZeroMessage {
52  pub fn request<V: DeserializeOwned + Serialize>(
53    cmd: &str,
54    req_id: usize,
55    body: V,
56  ) -> ZeroMessage {
57    let request = Request {
58      cmd: cmd.to_string(),
59      req_id,
60      params: serde_json::from_value(serde_json::to_value(body).unwrap()).unwrap(),
61    };
62    ZeroMessage::Request(request)
63  }
64  pub fn response<V: DeserializeOwned + Serialize>(to: usize, body: V) -> ZeroMessage {
65    let response = Response {
66      cmd: "response".to_string(),
67      to,
68      response: serde_json::from_value(serde_json::to_value(body).unwrap()).unwrap(),
69    };
70    ZeroMessage::Response(response)
71  }
72  pub fn body<V: DeserializeOwned + Serialize>(self) -> Result<V, Error> {
73    match self {
74      ZeroMessage::Response(res) => res.body(),
75      ZeroMessage::Request(req) => req.body(),
76    }
77  }
78}
79
80/// ```
81/// use zeronet_protocol::message::ZeroMessage;
82/// use zeronet_protocol::requestable::Requestable;
83///
84/// let request = ZeroMessage::request("handshake", 0, "body".to_string());
85/// assert!(request.is_request());
86/// assert!(!request.is_response());
87///
88/// let response = ZeroMessage::response(0, "body".to_string());
89/// assert!(response.is_response());
90/// assert!(!response.is_request());
91/// ```
92impl Requestable for ZeroMessage {
93  type Key = usize;
94
95  fn req_id(&self) -> Option<Self::Key> {
96    match self {
97      ZeroMessage::Request(req) => Some(req.req_id),
98      _ => None,
99    }
100  }
101  fn to(&self) -> Option<Self::Key> {
102    match self {
103      ZeroMessage::Response(res) => Some(res.to),
104      _ => None,
105    }
106  }
107}
108
109#[cfg(test)]
110#[cfg_attr(tarpaulin, ignore)]
111mod tests {
112  use super::ZeroMessage;
113  use crate::requestable::Requestable;
114
115  fn des(text: &str) -> Result<ZeroMessage, serde_json::error::Error> {
116    serde_json::from_str(text)
117  }
118
119  fn rmps(msg: &ZeroMessage) -> Vec<u8> {
120    let jsoned = serde_json::to_value(&msg).unwrap();
121    rmp_serde::to_vec_named(&jsoned).unwrap()
122
123    // rmp_serde::to_vec_named(msg).unwrap()
124  }
125
126  fn rmpd(bytes: Vec<u8>) -> ZeroMessage {
127    rmp_serde::from_slice(&bytes).unwrap()
128  }
129
130  use serde::{Deserialize, Serialize};
131  #[derive(Deserialize, Serialize, Debug)]
132  struct AnnounceParams {
133    hashes:     Vec<serde_bytes::ByteBuf>,
134    port:       usize,
135    need_types: Vec<String>,
136    delete:     bool,
137  }
138
139  #[test]
140  fn test_announce() {
141    let text = r#"
142		{
143			"cmd": "announce",
144			"req_id": 0,
145			"params": {
146				"hashes": [
147					[89, 112, 7, 110, 192, 202, 246, 172, 153, 204, 68, 17, 131, 21, 113, 111, 125, 39, 66, 195, 91, 53, 41, 172, 78, 234, 146, 138, 48, 150, 109, 29],
148					[29, 193, 202, 145, 155, 127, 205, 249, 222, 181, 121, 80, 223, 86, 149, 175, 49, 199, 10, 242, 237, 120, 239, 250, 84, 225, 196, 19, 67, 54, 74, 31],
149					[154, 94, 94, 135, 80, 65, 245, 232, 228, 170, 254, 51, 215, 25, 155, 238, 32, 182, 95, 83, 131, 168, 192, 125, 22, 53, 43, 147, 91, 235, 29, 146]
150				],
151				"onion_signs": [],
152				"onion_sign_this": "",
153				"port": 15441,
154				"need_types": ["ipv4"],
155				"need_num": 20,
156				"add": ["onion", "ipv4"],
157				"delete": true
158			}
159		}"#;
160    let msg = des(text).unwrap();
161    assert!(msg.is_request());
162    assert_eq!(rmpd(rmps(&msg)), msg);
163
164    let bytes = vec![
165      131, 163, 99, 109, 100, 168, 97, 110, 110, 111, 117, 110, 99, 101, 166, 112, 97, 114, 97,
166      109, 115, 136, 163, 97, 100, 100, 146, 165, 111, 110, 105, 111, 110, 164, 105, 112, 118, 52,
167      166, 100, 101, 108, 101, 116, 101, 195, 166, 104, 97, 115, 104, 101, 115, 147, 220, 0, 32,
168      89, 112, 7, 110, 204, 192, 204, 202, 204, 246, 204, 172, 204, 153, 204, 204, 68, 17, 204,
169      131, 21, 113, 111, 125, 39, 66, 204, 195, 91, 53, 41, 204, 172, 78, 204, 234, 204, 146, 204,
170      138, 48, 204, 150, 109, 29, 220, 0, 32, 29, 204, 193, 204, 202, 204, 145, 204, 155, 127, 204,
171      205, 204, 249, 204, 222, 204, 181, 121, 80, 204, 223, 86, 204, 149, 204, 175, 49, 204, 199,
172      10, 204, 242, 204, 237, 120, 204, 239, 204, 250, 84, 204, 225, 204, 196, 19, 67, 54, 74, 31,
173      220, 0, 32, 204, 154, 94, 94, 204, 135, 80, 65, 204, 245, 204, 232, 204, 228, 204, 170, 204,
174      254, 51, 204, 215, 25, 204, 155, 204, 238, 32, 204, 182, 95, 83, 204, 131, 204, 168, 204,
175      192, 125, 22, 53, 43, 204, 147, 91, 204, 235, 29, 204, 146, 168, 110, 101, 101, 100, 95, 110,
176      117, 109, 20, 170, 110, 101, 101, 100, 95, 116, 121, 112, 101, 115, 145, 164, 105, 112, 118,
177      52, 175, 111, 110, 105, 111, 110, 95, 115, 105, 103, 110, 95, 116, 104, 105, 115, 160, 171,
178      111, 110, 105, 111, 110, 95, 115, 105, 103, 110, 115, 144, 164, 112, 111, 114, 116, 205, 60,
179      81, 166, 114, 101, 113, 95, 105, 100, 0,
180    ];
181    assert_eq!(rmpd(bytes), msg);
182
183    let params: AnnounceParams = msg.body().unwrap();
184    assert_eq!(params.port, 15441);
185  }
186
187  #[test]
188  fn test_announce_msgpack() {}
189
190  #[test]
191  fn test_get_file() {
192    let text = r#"
193		{
194			"cmd": "getFile",
195			"req_id": 0,
196			"params": {}
197		}"#;
198    let msg = des(text).unwrap();
199    assert_eq!(msg.is_request(), true);
200    assert_eq!(rmpd(rmps(&msg)), msg);
201  }
202
203  #[test]
204  fn test_get_file_response() {
205    let msg = des(
206      r#"
207		{
208			"cmd": "response",
209			"to": 1,
210			"body": "content.json content",
211			"location": 1132,
212			"size": 1132
213		}"#,
214    );
215    assert_eq!(msg.is_ok(), true, "Deserializes response");
216  }
217
218  #[test]
219  fn test_handshake() {
220    let msg = des(
221      r#"
222		{
223			"cmd": "handshake",
224			"req_id": 0,
225			"params": {
226				"crypt": null,
227				"crypt_supported": ["tls-rsa"],
228				"fileserver_port": 15441,
229				"onion": "zp2ynpztyxj2kw7x",
230				"protocol": "v2",
231				"port_opened": true,
232				"peer_id": "-ZN0056-DMK3XX30mOrw",
233				"rev": 2122,
234				"target_ip": "192.168.1.13",
235				"version": "0.5.6"
236			}
237		}"#,
238    );
239    assert_eq!(msg.is_ok(), true);
240  }
241
242  #[test]
243  fn test_handshake_response() {
244    let msg = des(
245      r#"
246		{
247			"protocol": "v2",
248			"onion": "boot3rdez4rzn36x",
249			"to": 0,
250			"crypt": null,
251			"cmd": "response",
252			"rev": 2092,
253			"crypt_supported": [],
254			"target_ip": "zp2ynpztyxj2kw7x.onion",
255			"version": "0.5.5",
256			"fileserver_port": 15441,
257			"port_opened": false,
258			"peer_id": ""
259		 }"#,
260    );
261    assert_eq!(msg.is_ok(), true);
262  }
263
264  #[test]
265  fn test_stream_file() {
266    let msg = des(
267      r#"
268		{
269			"cmd": "streamFile",
270			"req_id": 1,
271			"params": {
272				"site": "1ADDR",
273				"inner_path": "content.json",
274				"size": 1234
275			}
276		}"#,
277    );
278    assert_eq!(msg.is_ok(), true);
279  }
280
281  #[test]
282  fn test_stream_file_response() {
283    let msg = des(
284      r#"
285		{
286			"cmd": "response",
287			"to": 1,
288			"stream_bytes": 1234
289		}"#,
290    );
291    assert_eq!(msg.is_ok(), true);
292  }
293
294  #[test]
295  fn test_ping() {
296    let msg = des(
297      r#"
298		{
299			"cmd": "ping",
300			"req_id": 0
301		}"#,
302    );
303    assert_eq!(msg.is_ok(), true);
304  }
305
306  #[test]
307  fn test_pong() {
308    let msg = des(
309      r#"
310		{
311			"cmd": "response",
312			"to": 0,
313			"body": "Pong!"
314		}"#,
315    );
316    assert_eq!(msg.is_ok(), true);
317  }
318
319  #[test]
320  fn test_pex() {
321    let msg = des(
322      r#"
323		{
324			"cmd": "pex",
325			"req_id": 0,
326			"params": {
327				"site": "1ADDR"
328			}
329		}"#,
330    );
331    assert_eq!(msg.is_ok(), true);
332  }
333
334  #[test]
335  fn test_pex_response() {
336    let msg = des(
337      r#"
338		{
339			"cmd": "response",
340			"to": 0,
341			"peers": [],
342			"peers_onion": []
343		}"#,
344    );
345    assert_eq!(msg.is_ok(), true);
346  }
347}