1use serde::{Serialize, Deserialize};
4use serde_json::{self, Value};
5
6#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq)]
8pub struct Timestamp {
9 #[serde(rename="$date")]
10 millis: Option<u64>,
11}
12
13#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(tag = "msg")]
16#[serde(rename_all = "camelCase")]
17pub enum ClientMessage {
18 Connect {
20 version: String,
21 support: Vec<String>,
22 #[serde(skip_serializing_if="Option::is_none")]
23 session: Option<String>,
24 },
25
26 Ping {
27 #[serde(skip_serializing_if="Option::is_none")]
28 id: Option<String>
29 },
30 Pong {
31 #[serde(skip_serializing_if="Option::is_none")]
32 id: Option<String>
33 },
34
35 Method {
37 id: String,
38 method: String,
39 params: Vec<Value>
40 },
41
42
43 Sub {
44 id: String, name: String, params: Vec<Value>
45 },
46 Unsub {
47 id: String
48 },
49
50}
51
52#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(tag = "msg")]
55#[serde(rename_all = "camelCase")]
56pub enum ServerMessage {
57 Connected {
58 session: String,
59 },
60 Failed {
61 version: String,
62 },
63 Ping {
64 #[serde(default, skip_serializing_if="Option::is_none")]
65 id: Option<String>
66 },
67 Pong {
68 #[serde(default, skip_serializing_if="Option::is_none")]
69 id: Option<String>
70 },
71
72 Result(MethodResponse),
74
75 Nosub {
77 id: String,
78 #[serde(default, skip_serializing_if="Option::is_none")]
79 error: Option<Value>
80 },
81
82 Updated {
84 methods: Vec<String>
85 },
86
87 Added {
88 collection: String,
89 id: String,
90 fields: Option<Value>,
91 },
92 Changed {
93 collection: String,
94 id: String,
95 #[serde(default, skip_serializing_if="Option::is_none")]
96 fields: Option<Value>,
97 #[serde(default, skip_serializing_if="Option::is_none")]
98 cleared: Option<Vec<String>>,
99 },
100 Removed {
101 collection: String,
102 id: String,
103 },
104 Ready {
105 subs: Vec<String>,
106 },
107 AddedBefore {
108 collection: String,
109 id: String,
110 #[serde(default, skip_serializing_if="Option::is_none")]
111 fields: Option<Value>,
112 before: Option<String>,
113 },
114 MovedBefore {
115 before: Option<String>,
116 }
117
118}
119
120impl ServerMessage {
121
122 pub fn pretty(&self) -> String {
123 serde_json::to_value(&self)
124 .and_then(|v| serde_json::to_string_pretty(&v))
125 .unwrap_or_else(|_| "<<serialization error>>".to_string())
126 }
127
128}
129
130#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
131pub struct MethodResponse {
132 pub id: String,
133 #[serde(default, skip_serializing_if="Option::is_none")]
134 pub result: Option<Value>,
135 #[serde(default, skip_serializing_if="Option::is_none")]
136 pub error: Option<Value>,
137}
138
139
140
141#[cfg(test)]
142mod tests {
143
144 use super::*;
145
146 use serde::de::DeserializeOwned;
147
148 fn check_message<M>(msg: &M, string: &str)
149 where M: Serialize + DeserializeOwned + PartialEq + std::fmt::Debug
150 {
151 let serialized = serde_json::to_string(msg).unwrap();
152 assert_eq!(serialized, string);
153 let deserialized: M = serde_json::from_str(&string).unwrap();
154 assert_eq!(msg, &deserialized);
155
156 }
157
158 #[test]
159 fn test_method_result() {
160 check_message(&ServerMessage::Result(
161 MethodResponse {
162 id: "123".to_string(),
163 result: Some(Value::String("burp".to_string())),
164 error: None
165 }
166 ), r#"{"msg":"result","id":"123","result":"burp"}"#);
167 }
168
169 #[test]
170 fn test_method_error() {
171 check_message(&ServerMessage::Result(
172 MethodResponse {
173 id: "456:kahcubwdasd".to_string(),
174 error: Some(Value::Bool(true)),
175 result: None,
176 }
177
178 ), r#"{"msg":"result","id":"456:kahcubwdasd","error":true}"#);
179 }
180
181 #[test]
182 fn test_pingpong() {
183
184 check_message(&ServerMessage::Ping { id: None }, r#"{"msg":"ping"}"#);
185 check_message(&ServerMessage::Ping { id: Some("pingpong".to_string()) }, r#"{"msg":"ping","id":"pingpong"}"#);
186 }
187
188 #[test]
189 fn test_timestamp() {
190 check_message(&Timestamp{ millis: Some(129348109238) }, r#"{"$date":129348109238}"#);
191 }
192}