rustenium_bidi_commands/
lib.rs

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