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!(context_id = context_id, "Using cached isolated world context");
112 return Ok(context_id);
113 }
114 }
115
116 debug!("Creating new isolated world");
118 let result: viewpoint_cdp::protocol::page::CreateIsolatedWorldResult = self
119 .connection
120 .send_command(
121 "Page.createIsolatedWorld",
122 Some(viewpoint_cdp::protocol::page::CreateIsolatedWorldParams {
123 frame_id: self.id.clone(),
124 world_name: Some(world_name.to_string()),
125 grant_univeral_access: Some(true),
126 }),
127 Some(&self.session_id),
128 )
129 .await?;
130
131 let context_id = result.execution_context_id;
132 debug!(context_id = context_id, "Created isolated world");
133
134 self.set_execution_context(world_name.to_string(), context_id);
136
137 Ok(context_id)
138 }
139}
140
141pub(super) fn find_child_frames(
143 tree: &viewpoint_cdp::protocol::page::FrameTree,
144 parent_id: &str,
145 connection: &Arc<CdpConnection>,
146 session_id: &str,
147) -> Vec<Frame> {
148 let mut children = Vec::new();
149
150 if tree.frame.id == parent_id {
152 if let Some(ref child_frames) = tree.child_frames {
154 for child in child_frames {
155 children.push(Frame::new(
156 connection.clone(),
157 session_id.to_string(),
158 child.frame.id.clone(),
159 Some(parent_id.to_string()),
160 child.frame.loader_id.clone(),
161 child.frame.url.clone(),
162 child.frame.name.clone().unwrap_or_default(),
163 ));
164 }
165 }
166 } else {
167 if let Some(ref child_frames) = tree.child_frames {
169 for child in child_frames {
170 let found = find_child_frames(child, parent_id, connection, session_id);
171 children.extend(found);
172 }
173 }
174 }
175
176 children
177}
178
179pub(super) fn find_parent_frame(
181 tree: &viewpoint_cdp::protocol::page::FrameTree,
182 frame_id: &str,
183 connection: &Arc<CdpConnection>,
184 session_id: &str,
185) -> Option<Frame> {
186 if let Some(ref child_frames) = tree.child_frames {
188 for child in child_frames {
189 if child.frame.id == frame_id {
190 return Some(Frame::new(
192 connection.clone(),
193 session_id.to_string(),
194 tree.frame.id.clone(),
195 tree.frame.parent_id.clone(),
196 tree.frame.loader_id.clone(),
197 tree.frame.url.clone(),
198 tree.frame.name.clone().unwrap_or_default(),
199 ));
200 }
201 }
202
203 for child in child_frames {
205 if let Some(parent) = find_parent_frame(child, frame_id, connection, session_id) {
206 return Some(parent);
207 }
208 }
209 }
210
211 None
212}