use serde::{Deserialize, Serialize};
use crate::cdp::Cdp;
use crate::cdp::command::{CdpCommand, CdpEvent, Empty};
use crate::cdp::ids::{FrameId, LoaderId, ScriptId};
use crate::common::protocol::string_enum;
use crate::error::WebDriverResult;
string_enum! {
pub enum ImageFormat {
Png = "png",
Jpeg = "jpeg",
Webp = "webp",
}
}
string_enum! {
pub enum TransitionType {
Link = "link",
Typed = "typed",
AddressBar = "address_bar",
AutoBookmark = "auto_bookmark",
AutoSubframe = "auto_subframe",
ManualSubframe = "manual_subframe",
Generated = "generated",
AutoToplevel = "auto_toplevel",
FormSubmit = "form_submit",
Reload = "reload",
Keyword = "keyword",
KeywordGenerated = "keyword_generated",
Other = "other",
}
}
string_enum! {
pub enum NavigationType {
Navigation = "Navigation",
BackForwardCacheRestore = "BackForwardCacheRestore",
}
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct Enable;
impl CdpCommand for Enable {
const METHOD: &'static str = "Page.enable";
type Returns = Empty;
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct Disable;
impl CdpCommand for Disable {
const METHOD: &'static str = "Page.disable";
type Returns = Empty;
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Navigate {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub referrer: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub transition_type: Option<TransitionType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frame_id: Option<FrameId>,
}
impl Navigate {
pub fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
referrer: None,
transition_type: None,
frame_id: None,
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NavigateResult {
pub frame_id: FrameId,
pub loader_id: Option<LoaderId>,
pub error_text: Option<String>,
}
impl CdpCommand for Navigate {
const METHOD: &'static str = "Page.navigate";
type Returns = NavigateResult;
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Reload {
#[serde(skip_serializing_if = "Option::is_none")]
pub ignore_cache: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub script_to_evaluate_on_load: Option<String>,
}
impl CdpCommand for Reload {
const METHOD: &'static str = "Page.reload";
type Returns = Empty;
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CaptureScreenshot {
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<ImageFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quality: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub capture_beyond_viewport: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ScreenshotData {
pub data: String,
}
impl CdpCommand for CaptureScreenshot {
const METHOD: &'static str = "Page.captureScreenshot";
type Returns = ScreenshotData;
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PrintToPdf {
#[serde(skip_serializing_if = "Option::is_none")]
pub paper_width: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub paper_height: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub landscape: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub display_header_footer: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub print_background: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scale: Option<f64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct PdfData {
pub data: String,
}
impl CdpCommand for PrintToPdf {
const METHOD: &'static str = "Page.printToPDF";
type Returns = PdfData;
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AddScriptToEvaluateOnNewDocument {
pub source: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub world_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub include_command_line_api: Option<bool>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AddedScript {
pub identifier: ScriptId,
}
impl CdpCommand for AddScriptToEvaluateOnNewDocument {
const METHOD: &'static str = "Page.addScriptToEvaluateOnNewDocument";
type Returns = AddedScript;
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RemoveScriptToEvaluateOnNewDocument {
pub identifier: ScriptId,
}
impl CdpCommand for RemoveScriptToEvaluateOnNewDocument {
const METHOD: &'static str = "Page.removeScriptToEvaluateOnNewDocument";
type Returns = Empty;
}
#[derive(Debug, Clone, Serialize)]
pub struct SetLifecycleEventsEnabled {
pub enabled: bool,
}
impl CdpCommand for SetLifecycleEventsEnabled {
const METHOD: &'static str = "Page.setLifecycleEventsEnabled";
type Returns = Empty;
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FrameNavigated {
pub frame: serde_json::Value,
pub r#type: Option<NavigationType>,
}
impl CdpEvent for FrameNavigated {
const METHOD: &'static str = "Page.frameNavigated";
const ENABLE: Option<&'static str> = Some("Page.enable");
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LifecycleEvent {
pub frame_id: FrameId,
pub loader_id: LoaderId,
pub name: String,
pub timestamp: f64,
}
impl CdpEvent for LifecycleEvent {
const METHOD: &'static str = "Page.lifecycleEvent";
const ENABLE: Option<&'static str> = Some("Page.enable");
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LoadEventFired {
pub timestamp: f64,
}
impl CdpEvent for LoadEventFired {
const METHOD: &'static str = "Page.loadEventFired";
const ENABLE: Option<&'static str> = Some("Page.enable");
}
#[derive(Debug)]
pub struct PageDomain<'a> {
cdp: &'a Cdp,
}
impl<'a> PageDomain<'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 navigate(&self, url: impl Into<String>) -> WebDriverResult<NavigateResult> {
self.cdp.send(Navigate::new(url)).await
}
pub async fn reload(&self) -> WebDriverResult<()> {
self.cdp.send(Reload::default()).await?;
Ok(())
}
pub async fn capture_screenshot_base64(&self) -> WebDriverResult<String> {
Ok(self.cdp.send(CaptureScreenshot::default()).await?.data)
}
pub async fn print_to_pdf_base64(&self) -> WebDriverResult<String> {
Ok(self.cdp.send(PrintToPdf::default()).await?.data)
}
pub async fn add_script_to_evaluate_on_new_document(
&self,
source: impl Into<String>,
) -> WebDriverResult<ScriptId> {
Ok(self
.cdp
.send(AddScriptToEvaluateOnNewDocument {
source: source.into(),
world_name: None,
include_command_line_api: None,
})
.await?
.identifier)
}
pub async fn remove_script_to_evaluate_on_new_document(
&self,
identifier: ScriptId,
) -> WebDriverResult<()> {
self.cdp
.send(RemoveScriptToEvaluateOnNewDocument {
identifier,
})
.await?;
Ok(())
}
pub async fn set_lifecycle_events_enabled(&self, enabled: bool) -> WebDriverResult<()> {
self.cdp
.send(SetLifecycleEventsEnabled {
enabled,
})
.await?;
Ok(())
}
}