Skip to content

Commit

Permalink
expose frame execution context, url, name, and parent (#185)
Browse files Browse the repository at this point in the history
  • Loading branch information
jvatic authored Nov 6, 2023
1 parent 88470ca commit 1b9d619
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 15 deletions.
4 changes: 4 additions & 0 deletions src/handler/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ impl Frame {
}
}

pub fn parent_id(&self) -> Option<&FrameId> {
self.parent_frame.as_ref()
}

pub fn id(&self) -> &FrameId {
&self.id
}
Expand Down
26 changes: 22 additions & 4 deletions src/handler/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use chromiumoxide_cdp::cdp::browser_protocol::input::{
MouseButton,
};
use chromiumoxide_cdp::cdp::browser_protocol::page::{
GetLayoutMetricsParams, GetLayoutMetricsReturns, Viewport,
FrameId, GetLayoutMetricsParams, GetLayoutMetricsReturns, Viewport,
};
use chromiumoxide_cdp::cdp::browser_protocol::target::{ActivateTargetParams, SessionId, TargetId};
use chromiumoxide_cdp::cdp::js_protocol::runtime::{
Expand Down Expand Up @@ -326,24 +326,42 @@ impl PageInner {
}

pub async fn execution_context(&self) -> Result<Option<ExecutionContextId>> {
self.execution_context_for_world(DOMWorldKind::Main).await
self.execution_context_for_world(None, DOMWorldKind::Main)
.await
}

pub async fn secondary_execution_context(&self) -> Result<Option<ExecutionContextId>> {
self.execution_context_for_world(DOMWorldKind::Secondary)
self.execution_context_for_world(None, DOMWorldKind::Secondary)
.await
}

pub async fn frame_execution_context(
&self,
frame_id: FrameId,
) -> Result<Option<ExecutionContextId>> {
self.execution_context_for_world(Some(frame_id), DOMWorldKind::Main)
.await
}

pub async fn frame_secondary_execution_context(
&self,
frame_id: FrameId,
) -> Result<Option<ExecutionContextId>> {
self.execution_context_for_world(Some(frame_id), DOMWorldKind::Secondary)
.await
}

pub async fn execution_context_for_world(
&self,
frame_id: Option<FrameId>,
dom_world: DOMWorldKind,
) -> Result<Option<ExecutionContextId>> {
let (tx, rx) = oneshot_channel();
self.sender
.clone()
.send(TargetMessage::GetExecutionContext(GetExecutionContext {
dom_world,
frame_id: None,
frame_id,
tx,
}))
.await?;
Expand Down
66 changes: 58 additions & 8 deletions src/handler/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,28 @@ impl Target {
.collect(),
);
}
TargetMessage::Url(tx) => {
let _ = tx.send(
self.frame_manager
.main_frame()
.and_then(|f| f.url().map(str::to_string)),
);
TargetMessage::Url(req) => {
let GetUrl { frame_id, tx } = req;
let frame = if let Some(frame_id) = frame_id {
self.frame_manager.frame(&frame_id)
} else {
self.frame_manager.main_frame()
};
let _ = tx.send(frame.and_then(|f| f.url().map(str::to_string)));
}
TargetMessage::Name(req) => {
let GetName { frame_id, tx } = req;
let frame = if let Some(frame_id) = frame_id {
self.frame_manager.frame(&frame_id)
} else {
self.frame_manager.main_frame()
};
let _ = tx.send(frame.and_then(|f| f.name().map(str::to_string)));
}
TargetMessage::Parent(req) => {
let GetParent { frame_id, tx } = req;
let frame = self.frame_manager.frame(&frame_id);
let _ = tx.send(frame.and_then(|f| f.parent_id().cloned()));
}
TargetMessage::WaitForNavigation(tx) => {
if let Some(frame) = self.frame_manager.main_frame() {
Expand Down Expand Up @@ -726,6 +742,36 @@ impl GetExecutionContext {
}
}

#[derive(Debug)]
pub struct GetUrl {
/// The id of the frame to get the url for (None = main frame)
pub frame_id: Option<FrameId>,
/// Sender half of the channel to send the response back
pub tx: Sender<Option<String>>,
}

impl GetUrl {
pub fn new(tx: Sender<Option<String>>) -> Self {
Self { frame_id: None, tx }
}
}

#[derive(Debug)]
pub struct GetName {
/// The id of the frame to get the name for (None = main frame)
pub frame_id: Option<FrameId>,
/// Sender half of the channel to send the response back
pub tx: Sender<Option<String>>,
}

#[derive(Debug)]
pub struct GetParent {
/// The id of the frame to get the parent for (None = main frame)
pub frame_id: FrameId,
/// Sender half of the channel to send the response back
pub tx: Sender<Option<FrameId>>,
}

#[derive(Debug)]
pub enum TargetMessage {
/// Execute a command within the session of this target
Expand All @@ -734,8 +780,12 @@ pub enum TargetMessage {
MainFrame(Sender<Option<FrameId>>),
/// Return all the frames of this target's page
AllFrames(Sender<Vec<FrameId>>),
/// Return the url of this target's page
Url(Sender<Option<String>>),
/// Return the url if available
Url(GetUrl),
/// Return the name if available
Name(GetName),
/// Return the parent id of a frame
Parent(GetParent),
/// A Message that resolves when the frame finished loading a new url
WaitForNavigation(Sender<ArcHttpRequest>),
/// A request to submit a new listener that gets notified with every
Expand Down
59 changes: 56 additions & 3 deletions src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::error::{CdpError, Result};
use crate::handler::commandfuture::CommandFuture;
use crate::handler::domworld::DOMWorldKind;
use crate::handler::httpfuture::HttpFuture;
use crate::handler::target::TargetMessage;
use crate::handler::target::{GetName, GetParent, GetUrl, TargetMessage};
use crate::handler::PageInner;
use crate::js::{Evaluation, EvaluationResult};
use crate::layout::Point;
Expand Down Expand Up @@ -304,13 +304,52 @@ impl Page {
self.inner.session_id()
}

/// Returns the name of the frame
pub async fn frame_name(&self, frame_id: FrameId) -> Result<Option<String>> {
let (tx, rx) = oneshot_channel();
self.inner
.sender()
.clone()
.send(TargetMessage::Name(GetName {
frame_id: Some(frame_id),
tx,
}))
.await?;
Ok(rx.await?)
}

/// Returns the current url of the page
pub async fn url(&self) -> Result<Option<String>> {
let (tx, rx) = oneshot_channel();
self.inner
.sender()
.clone()
.send(TargetMessage::Url(tx))
.send(TargetMessage::Url(GetUrl::new(tx)))
.await?;
Ok(rx.await?)
}

/// Returns the current url of the frame
pub async fn frame_url(&self, frame_id: FrameId) -> Result<Option<String>> {
let (tx, rx) = oneshot_channel();
self.inner
.sender()
.clone()
.send(TargetMessage::Url(GetUrl {
frame_id: Some(frame_id),
tx,
}))
.await?;
Ok(rx.await?)
}

/// Returns the parent id of the frame
pub async fn frame_parent(&self, frame_id: FrameId) -> Result<Option<FrameId>> {
let (tx, rx) = oneshot_channel();
self.inner
.sender()
.clone()
.send(TargetMessage::Parent(GetParent { frame_id, tx }))
.await?;
Ok(rx.await?)
}
Expand Down Expand Up @@ -1018,6 +1057,20 @@ impl Page {
self.inner.secondary_execution_context().await
}

pub async fn frame_execution_context(
&self,
frame_id: FrameId,
) -> Result<Option<ExecutionContextId>> {
self.inner.frame_execution_context(frame_id).await
}

pub async fn frame_secondary_execution_context(
&self,
frame_id: FrameId,
) -> Result<Option<ExecutionContextId>> {
self.inner.frame_secondary_execution_context(frame_id).await
}

/// Evaluates given script in every frame upon creation (before loading
/// frame's scripts)
pub async fn evaluate_on_new_document(
Expand Down Expand Up @@ -1059,7 +1112,7 @@ impl Page {

call.execution_context_id = self
.inner
.execution_context_for_world(DOMWorldKind::Secondary)
.execution_context_for_world(None, DOMWorldKind::Secondary)
.await?;

self.evaluate_function(call).await?;
Expand Down

0 comments on commit 1b9d619

Please sign in to comment.