viewpoint_core/page/frame/
tree.rs1use std::sync::Arc;
4
5use tracing::{debug, instrument};
6use viewpoint_cdp::CdpConnection;
7use viewpoint_cdp::protocol::runtime::ExecutionContextId;
8
9use super::Frame;
10use crate::error::PageError;
11
12impl Frame {
13 #[instrument(level = "debug", skip(self), fields(frame_id = %self.id))]
21 pub async fn child_frames(&self) -> Result<Vec<Frame>, PageError> {
22 if self.is_detached() {
23 return Err(PageError::EvaluationFailed("Frame is detached".to_string()));
24 }
25
26 let result: viewpoint_cdp::protocol::page::GetFrameTreeResult = self
28 .connection
29 .send_command("Page.getFrameTree", None::<()>, Some(&self.session_id))
30 .await?;
31
32 let children = find_child_frames(
34 &result.frame_tree,
35 &self.id,
36 &self.connection,
37 &self.session_id,
38 );
39
40 Ok(children)
41 }
42
43 #[instrument(level = "debug", skip(self), fields(frame_id = %self.id))]
51 pub async fn parent_frame(&self) -> Result<Option<Frame>, PageError> {
52 if self.is_detached() {
53 return Err(PageError::EvaluationFailed("Frame is detached".to_string()));
54 }
55
56 if self.is_main() {
58 return Ok(None);
59 }
60
61 let result: viewpoint_cdp::protocol::page::GetFrameTreeResult = self
63 .connection
64 .send_command("Page.getFrameTree", None::<()>, Some(&self.session_id))
65 .await?;
66
67 let parent = find_parent_frame(
69 &result.frame_tree,
70 &self.id,
71 &self.connection,
72 &self.session_id,
73 );
74
75 Ok(parent)
76 }
77
78 #[instrument(level = "debug", skip(self), fields(frame_id = %self.id, world_name = %world_name))]
99 pub(crate) async fn get_or_create_isolated_world(
100 &self,
101 world_name: &str,
102 ) -> Result<ExecutionContextId, PageError> {
103 if self.is_detached() {
104 return Err(PageError::EvaluationFailed("Frame is detached".to_string()));
105 }
106
107 {
109 let data = self.data.read();
110 if let Some(&context_id) = data.execution_contexts.get(world_name) {
111 debug!(
112 context_id = context_id,
113 "Using cached isolated world context"
114 );
115 return Ok(context_id);
116 }
117 }
118
119 debug!("Creating new isolated world");
121 let result: viewpoint_cdp::protocol::page::CreateIsolatedWorldResult = self
122 .connection
123 .send_command(
124 "Page.createIsolatedWorld",
125 Some(viewpoint_cdp::protocol::page::CreateIsolatedWorldParams {
126 frame_id: self.id.clone(),
127 world_name: Some(world_name.to_string()),
128 grant_univeral_access: Some(true),
129 }),
130 Some(&self.session_id),
131 )
132 .await?;
133
134 let context_id = result.execution_context_id;
135 debug!(context_id = context_id, "Created isolated world");
136
137 self.set_execution_context(world_name.to_string(), context_id);
139
140 Ok(context_id)
141 }
142}
143
144pub(super) fn find_child_frames(
146 tree: &viewpoint_cdp::protocol::page::FrameTree,
147 parent_id: &str,
148 connection: &Arc<CdpConnection>,
149 session_id: &str,
150) -> Vec<Frame> {
151 let mut children = Vec::new();
152
153 if tree.frame.id == parent_id {
155 if let Some(ref child_frames) = tree.child_frames {
157 for child in child_frames {
158 children.push(Frame::new(
159 connection.clone(),
160 session_id.to_string(),
161 child.frame.id.clone(),
162 Some(parent_id.to_string()),
163 child.frame.loader_id.clone(),
164 child.frame.url.clone(),
165 child.frame.name.clone().unwrap_or_default(),
166 ));
167 }
168 }
169 } else {
170 if let Some(ref child_frames) = tree.child_frames {
172 for child in child_frames {
173 let found = find_child_frames(child, parent_id, connection, session_id);
174 children.extend(found);
175 }
176 }
177 }
178
179 children
180}
181
182pub(super) fn find_parent_frame(
184 tree: &viewpoint_cdp::protocol::page::FrameTree,
185 frame_id: &str,
186 connection: &Arc<CdpConnection>,
187 session_id: &str,
188) -> Option<Frame> {
189 if let Some(ref child_frames) = tree.child_frames {
191 for child in child_frames {
192 if child.frame.id == frame_id {
193 return Some(Frame::new(
195 connection.clone(),
196 session_id.to_string(),
197 tree.frame.id.clone(),
198 tree.frame.parent_id.clone(),
199 tree.frame.loader_id.clone(),
200 tree.frame.url.clone(),
201 tree.frame.name.clone().unwrap_or_default(),
202 ));
203 }
204 }
205
206 for child in child_frames {
208 if let Some(parent) = find_parent_frame(child, frame_id, connection, session_id) {
209 return Some(parent);
210 }
211 }
212 }
213
214 None
215}