sync15/clients_engine/
record.rs
1use crate::error::error;
6use serde_derive::*;
7
8use super::Command;
9
10#[derive(Clone, Debug, Eq, Deserialize, Hash, PartialEq, Serialize)]
12#[serde(rename_all = "camelCase")]
13pub struct ClientRecord {
14 #[serde(rename = "id")]
15 pub id: String,
16
17 pub name: String,
18
19 #[serde(rename = "type")]
20 pub typ: crate::DeviceType,
21
22 #[serde(default, skip_serializing_if = "Vec::is_empty")]
23 pub commands: Vec<CommandRecord>,
24
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub fxa_device_id: Option<String>,
27
28 #[serde(default, skip_serializing_if = "Option::is_none")]
32 pub version: Option<String>,
33
34 #[serde(default, skip_serializing_if = "Vec::is_empty")]
35 pub protocols: Vec<String>,
36
37 #[serde(
38 default,
39 rename = "formfactor",
40 skip_serializing_if = "Option::is_none"
41 )]
42 pub form_factor: Option<String>,
43
44 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub os: Option<String>,
46
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub app_package: Option<String>,
49
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub application: Option<String>,
52
53 #[serde(default, skip_serializing_if = "Option::is_none")]
57 pub device: Option<String>,
58}
59
60impl From<&ClientRecord> for crate::RemoteClient {
61 fn from(record: &ClientRecord) -> crate::RemoteClient {
62 crate::RemoteClient {
63 fxa_device_id: record.fxa_device_id.clone(),
64 device_name: record.name.clone(),
65 device_type: record.typ,
66 }
67 }
68}
69
70#[derive(Clone, Debug, Eq, Deserialize, Hash, PartialEq, Serialize)]
72#[serde(rename_all = "camelCase")]
73pub struct CommandRecord {
74 #[serde(rename = "command")]
77 pub name: String,
78
79 #[serde(default)]
82 pub args: Vec<Option<String>>,
83
84 #[serde(default, rename = "flowID", skip_serializing_if = "Option::is_none")]
88 pub flow_id: Option<String>,
89}
90
91impl CommandRecord {
92 fn get_single_string_arg(&self) -> Option<String> {
97 let cmd_name = &self.name;
98 if self.args.len() == 1 {
99 match &self.args[0] {
100 Some(name) => Some(name.into()),
101 None => {
102 error!("Incoming '{cmd_name}' command has null argument");
103 None
104 }
105 }
106 } else {
107 error!(
108 "Incoming '{cmd_name}' command has wrong number of arguments ({})",
109 self.args.len()
110 );
111 None
112 }
113 }
114
115 pub fn as_command(&self) -> Option<Command> {
118 match self.name.as_str() {
119 "wipeEngine" => self.get_single_string_arg().map(Command::Wipe),
120 "resetEngine" => self.get_single_string_arg().map(Command::Reset),
121 "resetAll" => {
122 if self.args.is_empty() {
123 Some(Command::ResetAll)
124 } else {
125 error!("Invalid arguments for 'resetAll' command");
126 None
127 }
128 }
129 _ => None,
131 }
132 }
133}
134
135impl From<Command> for CommandRecord {
136 fn from(command: Command) -> CommandRecord {
137 match command {
138 Command::Wipe(engine) => CommandRecord {
139 name: "wipeEngine".into(),
140 args: vec![Some(engine)],
141 flow_id: None,
142 },
143 Command::Reset(engine) => CommandRecord {
144 name: "resetEngine".into(),
145 args: vec![Some(engine)],
146 flow_id: None,
147 },
148 Command::ResetAll => CommandRecord {
149 name: "resetAll".into(),
150 args: Vec::new(),
151 flow_id: None,
152 },
153 }
154 }
155}
156
157#[cfg(test)]
158mod test {
159 use super::*;
160
161 #[test]
162 fn test_valid_commands() {
163 let ser = serde_json::json!({"command": "wipeEngine", "args": ["foo"]});
164 let record: CommandRecord = serde_json::from_value(ser).unwrap();
165 assert_eq!(record.as_command(), Some(Command::Wipe("foo".to_string())));
166
167 let ser = serde_json::json!({"command": "resetEngine", "args": ["foo"]});
168 let record: CommandRecord = serde_json::from_value(ser).unwrap();
169 assert_eq!(record.as_command(), Some(Command::Reset("foo".to_string())));
170
171 let ser = serde_json::json!({"command": "resetAll"});
172 let record: CommandRecord = serde_json::from_value(ser).unwrap();
173 assert_eq!(record.as_command(), Some(Command::ResetAll));
174 }
175
176 #[test]
177 fn test_unknown_command() {
178 let ser = serde_json::json!({"command": "unknown", "args": ["foo", "bar"]});
179 let record: CommandRecord = serde_json::from_value(ser).unwrap();
180 assert_eq!(record.as_command(), None);
181 }
182
183 #[test]
184 fn test_bad_args() {
185 let ser = serde_json::json!({"command": "wipeEngine", "args": ["foo", "bar"]});
186 let record: CommandRecord = serde_json::from_value(ser).unwrap();
187 assert_eq!(record.as_command(), None);
188
189 let ser = serde_json::json!({"command": "wipeEngine"});
190 let record: CommandRecord = serde_json::from_value(ser).unwrap();
191 assert_eq!(record.as_command(), None);
192
193 let ser = serde_json::json!({"command": "resetAll", "args": ["foo"]});
194 let record: CommandRecord = serde_json::from_value(ser).unwrap();
195 assert_eq!(record.as_command(), None);
196 }
197
198 #[test]
199 fn test_null_args() {
200 let ser = serde_json::json!({"command": "unknown", "args": ["foo", null]});
201 let record: CommandRecord = serde_json::from_value(ser).unwrap();
202 assert_eq!(record.as_command(), None);
203 }
204}