use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::cdp::Cdp;
use crate::cdp::command::{CdpCommand, CdpEvent, Empty};
use crate::cdp::ids::{ExecutionContextId, RemoteObjectId, ScriptId};
use crate::common::protocol::string_enum;
use crate::error::WebDriverResult;
#[derive(Debug, Clone, Default, Serialize)]
pub struct Enable;
impl CdpCommand for Enable {
const METHOD: &'static str = "Runtime.enable";
type Returns = Empty;
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct Disable;
impl CdpCommand for Disable {
const METHOD: &'static str = "Runtime.disable";
type Returns = Empty;
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoteObject {
pub r#type: String,
pub subtype: Option<String>,
pub class_name: Option<String>,
pub value: Option<Value>,
pub description: Option<String>,
pub object_id: Option<RemoteObjectId>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Evaluate {
pub expression: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub object_group: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_command_line_api: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub silent: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub context_id: Option<ExecutionContextId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_by_value: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub await_promise: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_gesture: Option<bool>,
}
impl Evaluate {
pub fn new(expression: impl Into<String>) -> Self {
Self {
expression: expression.into(),
object_group: None,
include_command_line_api: None,
silent: None,
context_id: None,
return_by_value: None,
await_promise: None,
user_gesture: None,
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExceptionDetails {
pub exception_id: i64,
pub text: String,
pub line_number: u32,
pub column_number: u32,
pub script_id: Option<ScriptId>,
pub url: Option<String>,
pub stack_trace: Option<Value>,
pub exception: Option<RemoteObject>,
pub execution_context_id: Option<ExecutionContextId>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EvaluationResult {
pub result: RemoteObject,
pub exception_details: Option<ExceptionDetails>,
}
impl CdpCommand for Evaluate {
const METHOD: &'static str = "Runtime.evaluate";
type Returns = EvaluationResult;
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CallFunctionOn {
pub function_declaration: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub object_id: Option<RemoteObjectId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<Vec<Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub execution_context_id: Option<ExecutionContextId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub await_promise: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub return_by_value: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_gesture: Option<bool>,
}
impl CdpCommand for CallFunctionOn {
const METHOD: &'static str = "Runtime.callFunctionOn";
type Returns = EvaluationResult;
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReleaseObject {
pub object_id: RemoteObjectId,
}
impl CdpCommand for ReleaseObject {
const METHOD: &'static str = "Runtime.releaseObject";
type Returns = Empty;
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReleaseObjectGroup {
pub object_group: String,
}
impl CdpCommand for ReleaseObjectGroup {
const METHOD: &'static str = "Runtime.releaseObjectGroup";
type Returns = Empty;
}
string_enum! {
pub enum ConsoleApiType {
Log = "log",
Debug = "debug",
Info = "info",
Error = "error",
Warning = "warning",
Dir = "dir",
Dirxml = "dirxml",
Table = "table",
Trace = "trace",
Clear = "clear",
StartGroup = "startGroup",
StartGroupCollapsed = "startGroupCollapsed",
EndGroup = "endGroup",
Assert = "assert",
Profile = "profile",
ProfileEnd = "profileEnd",
Count = "count",
TimeEnd = "timeEnd",
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConsoleApiCalled {
pub r#type: ConsoleApiType,
pub args: Vec<RemoteObject>,
pub execution_context_id: ExecutionContextId,
pub timestamp: f64,
#[serde(default)]
pub stack_trace: Option<Value>,
#[serde(default)]
pub context: Option<String>,
}
impl CdpEvent for ConsoleApiCalled {
const METHOD: &'static str = "Runtime.consoleAPICalled";
const ENABLE: Option<&'static str> = Some("Runtime.enable");
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExceptionThrown {
pub timestamp: f64,
pub exception_details: ExceptionDetails,
}
impl CdpEvent for ExceptionThrown {
const METHOD: &'static str = "Runtime.exceptionThrown";
const ENABLE: Option<&'static str> = Some("Runtime.enable");
}
#[derive(Debug)]
pub struct RuntimeDomain<'a> {
cdp: &'a Cdp,
}
impl<'a> RuntimeDomain<'a> {
pub(crate) fn new(cdp: &'a Cdp) -> Self {
Self {
cdp,
}
}
pub async fn enable(&self) -> WebDriverResult<()> {
self.cdp.send(Enable).await?;
Ok(())
}
pub async fn disable(&self) -> WebDriverResult<()> {
self.cdp.send(Disable).await?;
Ok(())
}
pub async fn evaluate(&self, expression: impl Into<String>) -> WebDriverResult<RemoteObject> {
let r = self.cdp.send(Evaluate::new(expression)).await?;
Ok(r.result)
}
pub async fn evaluate_value(&self, expression: impl Into<String>) -> WebDriverResult<Value> {
let mut params = Evaluate::new(expression);
params.return_by_value = Some(true);
let r = self.cdp.send(params).await?;
Ok(r.result.value.unwrap_or(Value::Null))
}
pub async fn call_function_on(
&self,
object_id: RemoteObjectId,
function_declaration: impl Into<String>,
) -> WebDriverResult<Value> {
let r = self
.cdp
.send(CallFunctionOn {
function_declaration: function_declaration.into(),
object_id: Some(object_id),
arguments: None,
execution_context_id: None,
await_promise: Some(true),
return_by_value: Some(true),
user_gesture: None,
})
.await?;
Ok(r.result.value.unwrap_or(Value::Null))
}
pub async fn release_object(&self, object_id: RemoteObjectId) -> WebDriverResult<()> {
self.cdp
.send(ReleaseObject {
object_id,
})
.await?;
Ok(())
}
}