1use serde::{Serialize, Deserialize};
2use std::collections::HashMap;
3
4pub mod browser;
5pub mod browsing_context;
6pub mod emulation;
7pub mod input;
8pub mod log;
9pub mod network;
10pub mod script;
11pub mod session;
12pub mod storage;
13pub mod web_extension;
14
15pub use browser::commands::BrowserCommand;
16pub use browser::commands::BrowserResult;
17pub use browsing_context::commands::BrowsingContextCommand;
18pub use browsing_context::commands::BrowsingContextResult;
19pub use browsing_context::events::BrowsingContextEvent;
20pub use emulation::commands::EmulationCommand;
21pub use emulation::commands::EmulationResult;
22pub use input::commands::InputCommand;
23pub use input::commands::InputResult;
24pub use input::events::InputEvent;
25pub use log::events::LogEvent;
26pub use network::commands::NetworkCommand;
27pub use network::commands::NetworkResult;
28pub use network::events::NetworkEvent;
29pub use script::commands::ScriptCommand;
30pub use script::commands::ScriptResult;
31pub use script::events::ScriptEvent;
32pub use session::commands::SessionCommand;
33pub use session::commands::SessionResult;
34pub use storage::commands::StorageCommand;
35pub use storage::commands::StorageResult;
36pub use web_extension::commands::WebExtensionCommand;
37pub use web_extension::commands::WebExtensionResult;
38
39use serde::Deserializer;
40
41fn float_or_int_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
42where
43 D: Deserializer<'de>,
44{
45 let value = serde_json::Value::deserialize(deserializer)?;
46
47 match value {
48 serde_json::Value::Number(num) => {
49 if let Some(i) = num.as_u64() {
50 Ok(i)
51 } else if let Some(f) = num.as_f64() {
52 Ok(f as u64)
53 } else {
54 Err(serde::de::Error::custom("Invalid number"))
55 }
56 }
57 _ => Err(serde::de::Error::custom("Expected a number")),
58 }
59}
60
61fn option_float_or_int_to_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
62where
63 D: Deserializer<'de>,
64{
65 let value = serde_json::Value::deserialize(deserializer)?;
66
67 if value.is_null() {
68 return Ok(None);
69 }
70
71 match value {
72 serde_json::Value::Number(num) => {
73 if let Some(i) = num.as_u64() {
74 Ok(Some(i))
75 } else if let Some(f) = num.as_f64() {
76 Ok(Some(f as u64))
77 } else {
78 Err(serde::de::Error::custom("Invalid number"))
79 }
80 }
81 _ => Err(serde::de::Error::custom("Expected a number")),
82 }
83}
84
85fn deserialize_empty_map<'de, D>(deserializer: D) -> Result<Extensible, D::Error>
86where
87 D: serde::Deserializer<'de>,
88{
89 let map = Extensible::deserialize(deserializer)?;
90
91 if map.is_empty() {
92 Ok(map)
93 } else {
94 Err(serde::de::Error::custom("expected empty object"))
95 }
96}
97
98pub type Extensible = HashMap<String, serde_json::Value>;
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct Command {
102 #[serde(rename = "id")]
103 pub id: u64,
104 #[serde(flatten)]
105 pub command_data: CommandData,
106 #[serde(flatten)]
107 pub extensible: Extensible,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
111#[serde(untagged)]
112pub enum CommandData {
113 BrowserCommand(BrowserCommand),
114 BrowsingContextCommand(BrowsingContextCommand),
115 EmulationCommand(EmulationCommand),
116 InputCommand(InputCommand),
117 NetworkCommand(NetworkCommand),
118 ScriptCommand(ScriptCommand),
119 SessionCommand(SessionCommand),
120 StorageCommand(StorageCommand),
121 WebExtensionCommand(WebExtensionCommand),
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct EmptyParams {
126 #[serde(flatten, deserialize_with = "deserialize_empty_map")]
127 pub extensible: Extensible,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131#[serde(untagged)]
132pub enum Message {
133 ErrorResponse(ErrorResponse),
134 CommandResponse(CommandResponse),
135 Event(Event),
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct CommandResponse {
140 #[serde(rename = "type")]
141 pub r#type: SuccessEnum,
142 #[serde(rename = "id")]
143 #[serde(deserialize_with = "float_or_int_to_u64")]
144 pub id: u64,
145 #[serde(rename = "result")]
146 pub result: ResultData,
147 #[serde(flatten)]
148 pub extensible: Extensible,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct ErrorResponse {
153 #[serde(rename = "type")]
154 pub r#type: ErrorEnum,
155 #[serde(rename = "id")]
156 #[serde(deserialize_with = "option_float_or_int_to_u64")]
157 pub id: Option<u64>,
158 #[serde(rename = "error")]
159 pub error: ErrorCode,
160 #[serde(rename = "message")]
161 pub message: String,
162 #[serde(rename = "stacktrace")]
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub stacktrace: Option<String>,
165 #[serde(flatten)]
166 pub extensible: Extensible,
167}
168
169impl std::fmt::Display for ErrorResponse {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 write!(
172 f,
173 "Error[{}]: {} (ID: {}){}",
174 self.error,
175 self.message,
176 self.id.map_or("None".to_string(), |id| id.to_string()),
177 self.stacktrace.as_ref().map_or("".to_string(), |st| format!("\nStacktrace:\n{}", st))
178 )
179 }
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183#[serde(untagged)]
184pub enum ResultData {
185 EmptyResult(EmptyResult),
186 BrowserResult(BrowserResult),
187 BrowsingContextResult(BrowsingContextResult),
188 EmulationResult(EmulationResult),
189 InputResult(InputResult),
190 NetworkResult(NetworkResult),
191 ScriptResult(ScriptResult),
192 SessionResult(SessionResult),
193 StorageResult(StorageResult),
194 WebExtensionResult(WebExtensionResult),
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct EmptyResult {
199 #[serde(flatten, deserialize_with = "deserialize_empty_map")]
200 pub extensible: Extensible,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct Event {
205 #[serde(rename = "type")]
206 pub r#type: EventEnum,
207 #[serde(flatten)]
208 pub event_data: EventData,
209 #[serde(flatten)]
210 pub extensible: Extensible,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
214#[serde(untagged)]
215pub enum EventData {
216 BrowsingContextEvent(BrowsingContextEvent),
217 InputEvent(InputEvent),
218 LogEvent(LogEvent),
219 NetworkEvent(NetworkEvent),
220 ScriptEvent(ScriptEvent),
221}
222
223#[derive(Debug, Clone, Serialize, Deserialize)]
224pub enum ErrorCode {
225 #[serde(rename = "invalid argument")]
226 InvalidArgument,
227 #[serde(rename = "invalid selector")]
228 InvalidSelector,
229 #[serde(rename = "invalid session id")]
230 InvalidSessionId,
231 #[serde(rename = "invalid web extension")]
232 InvalidWebExtension,
233 #[serde(rename = "move target out of bounds")]
234 MoveTargetOutOfBounds,
235 #[serde(rename = "no such alert")]
236 NoSuchAlert,
237 #[serde(rename = "no such network collector")]
238 NoSuchNetworkCollector,
239 #[serde(rename = "no such element")]
240 NoSuchElement,
241 #[serde(rename = "no such frame")]
242 NoSuchFrame,
243 #[serde(rename = "no such handle")]
244 NoSuchHandle,
245 #[serde(rename = "no such history entry")]
246 NoSuchHistoryEntry,
247 #[serde(rename = "no such intercept")]
248 NoSuchIntercept,
249 #[serde(rename = "no such network data")]
250 NoSuchNetworkData,
251 #[serde(rename = "no such node")]
252 NoSuchNode,
253 #[serde(rename = "no such request")]
254 NoSuchRequest,
255 #[serde(rename = "no such script")]
256 NoSuchScript,
257 #[serde(rename = "no such storage partition")]
258 NoSuchStoragePartition,
259 #[serde(rename = "no such user context")]
260 NoSuchUserContext,
261 #[serde(rename = "no such web extension")]
262 NoSuchWebExtension,
263 #[serde(rename = "session not created")]
264 SessionNotCreated,
265 #[serde(rename = "unable to capture screen")]
266 UnableToCaptureScreen,
267 #[serde(rename = "unable to close drivers")]
268 UnableToCloseBrowser,
269 #[serde(rename = "unable to set cookie")]
270 UnableToSetCookie,
271 #[serde(rename = "unable to set file input")]
272 UnableToSetFileInput,
273 #[serde(rename = "unavailable network data")]
274 UnavailableNetworkData,
275 #[serde(rename = "underspecified storage partition")]
276 UnderspecifiedStoragePartition,
277 #[serde(rename = "unknown command")]
278 UnknownCommand,
279 #[serde(rename = "unknown error")]
280 UnknownError,
281 #[serde(rename = "unsupported operation")]
282 UnsupportedOperation,
283}
284
285impl std::fmt::Display for ErrorCode {
286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287 match self {
288 ErrorCode::InvalidArgument => write!(f, "invalid argument"),
289 ErrorCode::InvalidSelector => write!(f, "invalid selector"),
290 ErrorCode::InvalidSessionId => write!(f, "invalid session id"),
291 ErrorCode::InvalidWebExtension => write!(f, "invalid web extension"),
292 ErrorCode::MoveTargetOutOfBounds => write!(f, "move target out of bounds"),
293 ErrorCode::NoSuchAlert => write!(f, "no such alert"),
294 ErrorCode::NoSuchNetworkCollector => write!(f, "no such network collector"),
295 ErrorCode::NoSuchElement => write!(f, "no such element"),
296 ErrorCode::NoSuchFrame => write!(f, "no such frame"),
297 ErrorCode::NoSuchHandle => write!(f, "no such handle"),
298 ErrorCode::NoSuchHistoryEntry => write!(f, "no such history entry"),
299 ErrorCode::NoSuchIntercept => write!(f, "no such intercept"),
300 ErrorCode::NoSuchNetworkData => write!(f, "no such network data"),
301 ErrorCode::NoSuchNode => write!(f, "no such node"),
302 ErrorCode::NoSuchRequest => write!(f, "no such request"),
303 ErrorCode::NoSuchScript => write!(f, "no such script"),
304 ErrorCode::NoSuchStoragePartition => write!(f, "no such storage partition"),
305 ErrorCode::NoSuchUserContext => write!(f, "no such user context"),
306 ErrorCode::NoSuchWebExtension => write!(f, "no such web extension"),
307 ErrorCode::SessionNotCreated => write!(f, "session not created"),
308 ErrorCode::UnableToCaptureScreen => write!(f, "unable to capture screen"),
309 ErrorCode::UnableToCloseBrowser => write!(f, "unable to close drivers"),
310 ErrorCode::UnableToSetCookie => write!(f, "unable to set cookie"),
311 ErrorCode::UnableToSetFileInput => write!(f, "unable to set file input"),
312 ErrorCode::UnavailableNetworkData => write!(f, "unavailable network data"),
313 ErrorCode::UnderspecifiedStoragePartition => write!(f, "underspecified storage partition"),
314 ErrorCode::UnknownCommand => write!(f, "unknown command"),
315 ErrorCode::UnknownError => write!(f, "unknown error"),
316 ErrorCode::UnsupportedOperation => write!(f, "unsupported operation"),
317 }
318 }
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub enum SuccessEnum {
323 #[serde(rename = "success")]
324 Success,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub enum ErrorEnum {
329 #[serde(rename = "error")]
330 Error,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
334pub enum EventEnum {
335 #[serde(rename = "event")]
336 Event,
337}
338