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
80impl 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 }
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}