From 2f41a2c2d4fde04e1028c5675748a18f395390aa Mon Sep 17 00:00:00 2001 From: Hackermon Date: Sat, 4 Nov 2023 12:51:44 +0000 Subject: [PATCH 1/2] feat(browser): fetch existing targets(pages) --- src/browser.rs | 22 ++++++++++++++++++++- src/handler/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/browser.rs b/src/browser.rs index a896b79a..f6e1257c 100644 --- a/src/browser.rs +++ b/src/browser.rs @@ -12,7 +12,7 @@ use futures::select; use futures::SinkExt; use chromiumoxide_cdp::cdp::browser_protocol::target::{ - CreateBrowserContextParams, CreateTargetParams, DisposeBrowserContextParams, TargetId, + CreateBrowserContextParams, CreateTargetParams, DisposeBrowserContextParams, TargetId, TargetInfo, }; use chromiumoxide_cdp::cdp::{CdpEventMessage, IntoEventKind}; use chromiumoxide_types::*; @@ -177,6 +177,26 @@ impl Browser { Ok((browser, fut)) } + /// Request to fetch all existing browser targets. + /// + /// By default, only targets launched after the browser connection are tracked + /// when connecting to a existing browser instance with the devtools websocket url + /// This function fetches existing targets on the browser and adds them as pages internally + /// + /// The pages are not guaranteed to be ready as soon as the function returns + /// You should wait a few millis if you need to use a page + /// Returns [TargetInfo] + pub async fn fetch_targets(&mut self) -> Result> { + let (tx, rx) = oneshot_channel(); + + self.sender + .clone() + .send(HandlerMessage::FetchTargets(tx)) + .await?; + + rx.await? + } + /// Request for the browser to close completely. /// /// If the browser was spawned by [`Browser::launch`], it is recommended to wait for the diff --git a/src/handler/mod.rs b/src/handler/mod.rs index 36cd7df6..60d0c887 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -213,6 +213,30 @@ impl Handler { } } } + PendingRequest::GetTargets(tx) => { + match to_command_response::(resp, method) { + Ok(resp) => { + let targets: Vec = resp.result.target_infos; + let results = targets.clone(); + for target_info in targets { + let target_id = target_info.target_id.clone(); + let event: EventTargetCreated = EventTargetCreated { target_info }; + self.on_target_created(event); + let attach = AttachToTargetParams::new(target_id); + let _ = self.conn.submit_command( + attach.identifier(), + None, + serde_json::to_value(attach).unwrap(), + ); + } + + let _ = tx.send(Ok(results)).ok(); + } + Err(err) => { + let _ = tx.send(Err(err)).ok(); + } + } + } PendingRequest::Navigate(id) => { self.on_navigation_response(id, resp); } @@ -266,6 +290,22 @@ impl Handler { Ok(()) } + fn submit_fetch_targets(&mut self, tx: OneshotSender>>, now: Instant) { + let msg = GetTargetsParams { filter: None }; + let method = msg.identifier(); + let call_id = self.conn.submit_command( + method.clone(), + None, + serde_json::to_value(msg).unwrap(), + ) + .unwrap(); + + self.pending_commands.insert( + call_id, + (PendingRequest::GetTargets(tx), method, now), + ); + } + /// Send the Request over to the server and store its identifier to handle /// the response once received. fn submit_navigation(&mut self, id: NavigationId, req: CdpRequest, now: Instant) { @@ -456,6 +496,9 @@ impl Handler { PendingRequest::CreateTarget(tx) => { let _ = tx.send(Err(CdpError::Timeout)); } + PendingRequest::GetTargets(tx) => { + let _ = tx.send(Err(CdpError::Timeout)); + } PendingRequest::Navigate(nav) => { if let Some(nav) = self.navigations.remove(&nav) { match nav { @@ -498,6 +541,9 @@ impl Stream for Handler { HandlerMessage::Command(cmd) => { pin.submit_external_command(cmd, now)?; } + HandlerMessage::FetchTargets(tx) => { + pin.submit_fetch_targets(tx, now); + } HandlerMessage::CloseBrowser(tx) => { pin.submit_close(tx, now); } @@ -679,6 +725,8 @@ enum PendingRequest { /// A Request to create a new `Target` that results in the creation of a /// `Page` that represents a browser page. CreateTarget(OneshotSender>), + /// A Request to fetch old `Target`s created before connection + GetTargets(OneshotSender>>), /// A Request to navigate a specific `Target`. /// /// Navigation requests are not automatically completed once the response to @@ -701,6 +749,7 @@ enum PendingRequest { #[derive(Debug)] pub(crate) enum HandlerMessage { CreatePage(CreateTargetParams, OneshotSender>), + FetchTargets(OneshotSender>>), InsertContext(BrowserContext), DisposeContext(BrowserContext), GetPages(OneshotSender>), From e9026fe7e28a88711475664b142be24439b2c5fa Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Mon, 6 Nov 2023 14:54:53 +0100 Subject: [PATCH 2/2] rustfmt --- src/browser.rs | 5 +++-- src/handler/mod.rs | 16 ++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/browser.rs b/src/browser.rs index f6e1257c..f605367c 100644 --- a/src/browser.rs +++ b/src/browser.rs @@ -12,7 +12,8 @@ use futures::select; use futures::SinkExt; use chromiumoxide_cdp::cdp::browser_protocol::target::{ - CreateBrowserContextParams, CreateTargetParams, DisposeBrowserContextParams, TargetId, TargetInfo, + CreateBrowserContextParams, CreateTargetParams, DisposeBrowserContextParams, TargetId, + TargetInfo, }; use chromiumoxide_cdp::cdp::{CdpEventMessage, IntoEventKind}; use chromiumoxide_types::*; @@ -182,7 +183,7 @@ impl Browser { /// By default, only targets launched after the browser connection are tracked /// when connecting to a existing browser instance with the devtools websocket url /// This function fetches existing targets on the browser and adds them as pages internally - /// + /// /// The pages are not guaranteed to be ready as soon as the function returns /// You should wait a few millis if you need to use a page /// Returns [TargetInfo] diff --git a/src/handler/mod.rs b/src/handler/mod.rs index 60d0c887..c781de43 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -293,17 +293,13 @@ impl Handler { fn submit_fetch_targets(&mut self, tx: OneshotSender>>, now: Instant) { let msg = GetTargetsParams { filter: None }; let method = msg.identifier(); - let call_id = self.conn.submit_command( - method.clone(), - None, - serde_json::to_value(msg).unwrap(), - ) - .unwrap(); + let call_id = self + .conn + .submit_command(method.clone(), None, serde_json::to_value(msg).unwrap()) + .unwrap(); - self.pending_commands.insert( - call_id, - (PendingRequest::GetTargets(tx), method, now), - ); + self.pending_commands + .insert(call_id, (PendingRequest::GetTargets(tx), method, now)); } /// Send the Request over to the server and store its identifier to handle