rustenium 1.1.2

A modern, robust, high-performance WebDriver BiDi automation library for Rust
Documentation
use crate::browsers::chrome::tab::ChromeTab;
use crate::conduit::cdp::adapter::CdpAdapter;
use crate::error::cdp::{CreateTabError, EmulateDeviceMetricsError, NavigateError};
use rustenium_cdp_definitions::Command;
use rustenium_cdp_definitions::base::CommandResponse;
use rustenium_cdp_definitions::browser_protocol::emulation::commands::SetDeviceMetricsOverride;
use rustenium_cdp_definitions::browser_protocol::emulation::types::ScreenOrientation;
use rustenium_cdp_definitions::browser_protocol::page::commands::Navigate;
use rustenium_cdp_definitions::browser_protocol::page::results::NavigateResult;
use rustenium_cdp_definitions::browser_protocol::page::types::{ReferrerPolicy, TransitionType, Viewport};
use rustenium_cdp_definitions::browser_protocol::target::commands::CreateTarget;
use rustenium_core::error::CdpSessionSendError;
use rustenium_core::transport::WebsocketConnectionTransport;

#[derive(Debug, Clone, Default)]
pub struct NavigateOptions {
    pub referrer: Option<String>,
    pub transition_type: Option<TransitionType>,
    pub referrer_policy: Option<ReferrerPolicy>,
}

#[derive(Default, Clone)]
pub struct NavigateOptionsBuilder {
    referrer: Option<String>,
    transition_type: Option<TransitionType>,
    referrer_policy: Option<ReferrerPolicy>,
}

impl NavigateOptionsBuilder {
    pub fn referrer(mut self, v: impl Into<String>) -> Self {
        self.referrer = Some(v.into());
        self
    }
    pub fn transition_type(mut self, v: impl Into<TransitionType>) -> Self {
        self.transition_type = Some(v.into());
        self
    }
    pub fn referrer_policy(mut self, v: impl Into<ReferrerPolicy>) -> Self {
        self.referrer_policy = Some(v.into());
        self
    }
    pub fn build(self) -> NavigateOptions {
        NavigateOptions {
            referrer: self.referrer,
            transition_type: self.transition_type,
            referrer_policy: self.referrer_policy,
        }
    }
}

pub trait CdpBrowser {
    fn adapter(&self) -> &CdpAdapter<WebsocketConnectionTransport>;

    fn adapter_mut(&mut self) -> &mut CdpAdapter<WebsocketConnectionTransport>;

    fn navigate(
        &mut self,
        url: impl Into<String>,
    ) -> impl Future<Output = Result<NavigateResult, NavigateError>> {
        self.navigate_with_options(url, NavigateOptions::default())
    }

    fn navigate_with_options(
        &mut self,
        url: impl Into<String>,
        options: NavigateOptions,
    ) -> impl Future<Output = Result<NavigateResult, NavigateError>> {
        let mut builder = Navigate::builder().url(url);
        if let Some(referrer) = options.referrer {
            builder = builder.referrer(referrer);
        }
        if let Some(transition_type) = options.transition_type {
            builder = builder.transition_type(transition_type);
        }
        if let Some(referrer_policy) = options.referrer_policy {
            builder = builder.referrer_policy(referrer_policy);
        }
        let command = builder.build().unwrap();
        let adapter = self.adapter_mut();
        async move { adapter.navigate(command).await }
    }

    fn create_tab(
        &mut self,
        url: impl Into<String>,
    ) -> impl Future<Output = Result<ChromeTab, CreateTabError>> {
        self.create_tab_with_options(url, CreateTabOptions::default())
    }

    fn create_tab_with_options(
        &mut self,
        url: impl Into<String>,
        options: CreateTabOptions,
    ) -> impl Future<Output = Result<ChromeTab, CreateTabError>> {
        let mut builder = CreateTarget::builder().url(url);
        if let Some(v) = options.left {
            builder = builder.left(v);
        }
        if let Some(v) = options.top {
            builder = builder.top(v);
        }
        if let Some(v) = options.width {
            builder = builder.width(v);
        }
        if let Some(v) = options.height {
            builder = builder.height(v);
        }
        if let Some(v) = options.window_state {
            builder = builder.window_state(v);
        }
        if let Some(v) = options.browser_context_id {
            builder = builder.browser_context_id(v);
        }
        if let Some(v) = options.enable_begin_frame_control {
            builder = builder.enable_begin_frame_control(v);
        }
        if let Some(v) = options.new_window {
            builder = builder.new_window(v);
        }
        if let Some(v) = options.background {
            builder = builder.background(v);
        }
        if let Some(v) = options.for_tab {
            builder = builder.for_tab(v);
        }
        if let Some(v) = options.hidden {
            builder = builder.hidden(v);
        }
        if let Some(v) = options.focus {
            builder = builder.focus(v);
        }
        let command = builder.build().unwrap();
        let adapter = self.adapter_mut();
        async move {
            let target_id = adapter
                .create_target(command)
                .await
                .map_err(CreateTabError::CreateTargetError)?;
            Ok(ChromeTab::new(target_id))
        }
    }

    fn emulate_device_metrics(
        &mut self,
        width: i64,
        height: i64,
        device_scale_factor: f64,
        mobile: bool,
    ) -> impl Future<Output = Result<(), EmulateDeviceMetricsError>> {
        self.emulate_device_metrics_with_options(
            width,
            height,
            device_scale_factor,
            mobile,
            EmulateDeviceMetricsOptions::default(),
        )
    }

    fn emulate_device_metrics_with_options(
        &mut self,
        width: i64,
        height: i64,
        device_scale_factor: f64,
        mobile: bool,
        options: EmulateDeviceMetricsOptions,
    ) -> impl Future<Output = Result<(), EmulateDeviceMetricsError>> {
        let mut builder = SetDeviceMetricsOverride::builder()
            .width(width)
            .height(height)
            .device_scale_factor(device_scale_factor)
            .mobile(mobile);
        if let Some(v) = options.scale { builder = builder.scale(v); }
        if let Some(v) = options.screen_width { builder = builder.screen_width(v); }
        if let Some(v) = options.screen_height { builder = builder.screen_height(v); }
        if let Some(v) = options.position_x { builder = builder.position_x(v); }
        if let Some(v) = options.position_y { builder = builder.position_y(v); }
        if let Some(v) = options.dont_set_visible_size { builder = builder.dont_set_visible_size(v); }
        if let Some(v) = options.screen_orientation { builder = builder.screen_orientation(v); }
        if let Some(v) = options.viewport { builder = builder.viewport(v); }
        if let Some(v) = options.scrollbar_type { builder = builder.scrollbar_type(v); }
        let command = builder.build().unwrap();
        let adapter = self.adapter_mut();
        async move { adapter.emulate_device_metrics(command).await }
    }

    fn send_command(
        &mut self,
        command: Command,
    ) -> impl Future<Output = Result<CommandResponse, CdpSessionSendError>> + Send {
        let adapter = self.adapter_mut();
        async move { adapter.send_command(command).await }
    }
}

#[derive(Debug, Clone, Default)]
pub struct CreateTabOptions {
    pub left: Option<i64>,
    pub top: Option<i64>,
    pub width: Option<i64>,
    pub height: Option<i64>,
    pub window_state:
        Option<rustenium_cdp_definitions::browser_protocol::target::types::WindowState>,
    pub browser_context_id:
        Option<rustenium_cdp_definitions::browser_protocol::browser::types::BrowserContextId>,
    pub enable_begin_frame_control: Option<bool>,
    pub new_window: Option<bool>,
    pub background: Option<bool>,
    pub for_tab: Option<bool>,
    pub hidden: Option<bool>,
    pub focus: Option<bool>,
}

#[derive(Default, Clone)]
pub struct CreateTabOptionsBuilder {
    left: Option<i64>,
    top: Option<i64>,
    width: Option<i64>,
    height: Option<i64>,
    window_state: Option<rustenium_cdp_definitions::browser_protocol::target::types::WindowState>,
    browser_context_id:
        Option<rustenium_cdp_definitions::browser_protocol::browser::types::BrowserContextId>,
    enable_begin_frame_control: Option<bool>,
    new_window: Option<bool>,
    background: Option<bool>,
    for_tab: Option<bool>,
    hidden: Option<bool>,
    focus: Option<bool>,
}

impl CreateTabOptionsBuilder {
    pub fn left(mut self, v: i64) -> Self {
        self.left = Some(v);
        self
    }
    pub fn top(mut self, v: i64) -> Self {
        self.top = Some(v);
        self
    }
    pub fn width(mut self, v: i64) -> Self {
        self.width = Some(v);
        self
    }
    pub fn height(mut self, v: i64) -> Self {
        self.height = Some(v);
        self
    }
    pub fn window_state(
        mut self,
        v: rustenium_cdp_definitions::browser_protocol::target::types::WindowState,
    ) -> Self {
        self.window_state = Some(v);
        self
    }
    pub fn browser_context_id(
        mut self,
        v: rustenium_cdp_definitions::browser_protocol::browser::types::BrowserContextId,
    ) -> Self {
        self.browser_context_id = Some(v);
        self
    }
    pub fn enable_begin_frame_control(mut self, v: bool) -> Self {
        self.enable_begin_frame_control = Some(v);
        self
    }
    pub fn new_window(mut self, v: bool) -> Self {
        self.new_window = Some(v);
        self
    }
    pub fn background(mut self, v: bool) -> Self {
        self.background = Some(v);
        self
    }
    pub fn for_tab(mut self, v: bool) -> Self {
        self.for_tab = Some(v);
        self
    }
    pub fn hidden(mut self, v: bool) -> Self {
        self.hidden = Some(v);
        self
    }
    pub fn focus(mut self, v: bool) -> Self {
        self.focus = Some(v);
        self
    }
    pub fn build(self) -> CreateTabOptions {
        CreateTabOptions {
            left: self.left,
            top: self.top,
            width: self.width,
            height: self.height,
            window_state: self.window_state,
            browser_context_id: self.browser_context_id,
            enable_begin_frame_control: self.enable_begin_frame_control,
            new_window: self.new_window,
            background: self.background,
            for_tab: self.for_tab,
            hidden: self.hidden,
            focus: self.focus,
        }
    }
}

use rustenium_cdp_definitions::browser_protocol::emulation::commands::SetDeviceMetricsOverrideScrollbarType;

#[derive(Debug, Clone, Default)]
pub struct EmulateDeviceMetricsOptions {
    pub scale: Option<f64>,
    pub screen_width: Option<i64>,
    pub screen_height: Option<i64>,
    pub position_x: Option<i64>,
    pub position_y: Option<i64>,
    pub dont_set_visible_size: Option<bool>,
    pub screen_orientation: Option<ScreenOrientation>,
    pub viewport: Option<Viewport>,
    pub scrollbar_type: Option<SetDeviceMetricsOverrideScrollbarType>,
}

#[derive(Default, Clone)]
pub struct EmulateDeviceMetricsOptionsBuilder {
    scale: Option<f64>,
    screen_width: Option<i64>,
    screen_height: Option<i64>,
    position_x: Option<i64>,
    position_y: Option<i64>,
    dont_set_visible_size: Option<bool>,
    screen_orientation: Option<ScreenOrientation>,
    viewport: Option<Viewport>,
    scrollbar_type: Option<SetDeviceMetricsOverrideScrollbarType>,
}

impl EmulateDeviceMetricsOptionsBuilder {
    pub fn scale(mut self, v: f64) -> Self { self.scale = Some(v); self }
    pub fn screen_width(mut self, v: i64) -> Self { self.screen_width = Some(v); self }
    pub fn screen_height(mut self, v: i64) -> Self { self.screen_height = Some(v); self }
    pub fn position_x(mut self, v: i64) -> Self { self.position_x = Some(v); self }
    pub fn position_y(mut self, v: i64) -> Self { self.position_y = Some(v); self }
    pub fn dont_set_visible_size(mut self, v: bool) -> Self { self.dont_set_visible_size = Some(v); self }
    pub fn screen_orientation(mut self, v: ScreenOrientation) -> Self { self.screen_orientation = Some(v); self }
    pub fn viewport(mut self, v: Viewport) -> Self { self.viewport = Some(v); self }
    pub fn scrollbar_type(mut self, v: SetDeviceMetricsOverrideScrollbarType) -> Self { self.scrollbar_type = Some(v); self }
    pub fn build(self) -> EmulateDeviceMetricsOptions {
        EmulateDeviceMetricsOptions {
            scale: self.scale,
            screen_width: self.screen_width,
            screen_height: self.screen_height,
            position_x: self.position_x,
            position_y: self.position_y,
            dont_set_visible_size: self.dont_set_visible_size,
            screen_orientation: self.screen_orientation,
            viewport: self.viewport,
            scrollbar_type: self.scrollbar_type,
        }
    }
}