use crate::browser::{Browser, BrowserConfig};
use crate::cdp::CdpError;
use crate::element::Element;
use crate::frame::Frame;
use crate::listener::{DataPacket, Listener};
use crate::page::{Cookie, Page};
use crate::stealth;
use serde_json::Value;
use std::time::Duration;
pub struct ChromiumPage {
pub(crate) browser: Browser,
pub(crate) page: Page,
}
impl ChromiumPage {
pub fn new(config: BrowserConfig) -> Result<Self, CdpError> {
let browser = Browser::connect_or_launch(config)?;
let page = browser.tabs()?.into_iter().next().unwrap_or_else(|| {
browser
.new_tab()
.expect("Failed to create a new tab. The browser may have been closed")
});
stealth::inject(&page)?;
Ok(Self { browser, page })
}
pub fn connect(endpoint: &str) -> Result<Self, CdpError> {
let browser = Browser::connect(endpoint)?;
let page = browser.tabs()?.into_iter().next().unwrap_or_else(|| {
browser
.new_tab()
.expect("Failed to create a new tab. The browser may have been closed")
});
Ok(Self { browser, page })
}
pub fn get(&self, url: &str) -> Result<(), CdpError> {
self.page.goto(url)
}
pub fn refresh(&self) -> Result<(), CdpError> {
self.page.reload()
}
pub fn back(&self) -> Result<(), CdpError> {
self.page.back()
}
pub fn forward(&self) -> Result<(), CdpError> {
self.page.forward()
}
pub fn title(&self) -> Result<String, CdpError> {
self.page.title()
}
pub fn url(&self) -> Result<String, CdpError> {
self.page.url()
}
pub fn html(&self) -> Result<String, CdpError> {
self.page.html()
}
pub fn run_js(&self, script: &str) -> Result<Value, CdpError> {
self.page.run_js(script)
}
pub fn run_js_await(&self, script: &str) -> Result<Value, CdpError> {
self.page.run_js_await(script)
}
pub fn ele(&self, locator: &str) -> Result<Option<Element>, CdpError> {
self.page.ele(locator)
}
pub fn eles(&self, locator: &str) -> Result<Vec<Element>, CdpError> {
self.page.eles(locator)
}
pub fn click(&self, locator: &str) -> Result<(), CdpError> {
self.page.click(locator)
}
pub fn input(&self, locator: &str, text: &str) -> Result<(), CdpError> {
self.page.input(locator, text)
}
pub fn wait(&self, locator: &str, timeout: Duration) -> Result<Element, CdpError> {
self.page.wait(locator, timeout)
}
pub fn cookies(&self, urls: Option<&[String]>) -> Result<Vec<Cookie>, CdpError> {
self.page.cookies(urls)
}
pub fn screenshot(&self, path: &str) -> Result<(), CdpError> {
self.page.screenshot(path)
}
pub fn new_tab(&self, url: Option<&str>) -> Result<Page, CdpError> {
let tab = self.browser.new_tab()?;
if let Some(u) = url {
tab.goto(u)?;
}
Ok(tab)
}
pub fn tabs(&self) -> Result<Vec<Page>, CdpError> {
self.browser.tabs()
}
pub fn close(&self) -> Result<(), CdpError> {
self.page.close()
}
pub fn close_tab(&self) -> Result<(), CdpError> {
self.page.close()
}
pub fn close_browser(&mut self) {
self.browser.close()
}
pub fn browser(&self) -> &Browser {
&self.browser
}
pub fn tab(&self) -> &Page {
&self.page
}
pub fn into_parts(self) -> (Browser, Page) {
(self.browser, self.page)
}
pub fn get_iframe(&self, locator: &str) -> Result<Option<Frame>, CdpError> {
self.page.get_frame(locator)
}
pub fn get_iframes(&self, locator: Option<&str>) -> Result<Vec<Frame>, CdpError> {
self.page.get_frames(locator)
}
pub fn listen(&self) -> Result<Listener, CdpError> {
self.page.listen()
}
pub fn listen_url(&self, url_contains: &str) -> Result<Listener, CdpError> {
let listener = self.page.listen()?;
Ok(Listener::filter_url(listener, url_contains.to_string()))
}
pub fn listen_resource_type(&self, resource_type: &str) -> Result<Listener, CdpError> {
let listener = self.page.listen()?;
Ok(Listener::filter_resource_type(listener, resource_type.to_string()))
}
pub fn listen_collect<F>(
&self,
listener: &Listener,
timeout: Duration,
on_packet: F,
) -> Result<Vec<DataPacket>, CdpError>
where
F: FnMut(&DataPacket) -> bool,
{
listener.collect(timeout, on_packet)
}
}