1use crate::channel::Channel;
7use crate::channel_owner::{ChannelOwner, ChannelOwnerImpl, ParentOrConnection};
8use crate::error::{Error, Result};
9use crate::protocol::page::{GotoOptions, Response};
10use serde::Deserialize;
11use serde_json::Value;
12use std::any::Any;
13use std::sync::Arc;
14
15#[derive(Clone)]
24pub struct Frame {
25 base: ChannelOwnerImpl,
26}
27
28impl Frame {
29 pub fn new(
34 parent: Arc<dyn ChannelOwner>,
35 type_name: String,
36 guid: Arc<str>,
37 initializer: Value,
38 ) -> Result<Self> {
39 let base = ChannelOwnerImpl::new(
40 ParentOrConnection::Parent(parent),
41 type_name,
42 guid,
43 initializer,
44 );
45
46 Ok(Self { base })
47 }
48
49 fn channel(&self) -> &Channel {
51 self.base.channel()
52 }
53
54 pub async fn goto(&self, url: &str, options: Option<GotoOptions>) -> Result<Option<Response>> {
68 let mut params = serde_json::json!({
70 "url": url,
71 });
72
73 if let Some(opts) = options {
75 if let Some(timeout) = opts.timeout {
76 params["timeout"] = serde_json::json!(timeout.as_millis() as u64);
77 } else {
78 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
80 }
81 if let Some(wait_until) = opts.wait_until {
82 params["waitUntil"] = serde_json::json!(wait_until.as_str());
83 }
84 } else {
85 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
87 }
88
89 #[derive(Deserialize)]
92 struct GotoResponse {
93 response: Option<ResponseReference>,
94 }
95
96 #[derive(Deserialize)]
97 struct ResponseReference {
98 #[serde(deserialize_with = "crate::connection::deserialize_arc_str")]
99 guid: Arc<str>,
100 }
101
102 let goto_result: GotoResponse = self.channel().send("goto", params).await?;
103
104 if let Some(response_ref) = goto_result.response {
106 let response_arc = {
112 let mut attempts = 0;
113 let max_attempts = 20; loop {
115 match self.connection().get_object(&response_ref.guid).await {
116 Ok(obj) => break obj,
117 Err(_) if attempts < max_attempts => {
118 attempts += 1;
119 tokio::time::sleep(std::time::Duration::from_millis(50)).await;
120 }
121 Err(e) => return Err(e),
122 }
123 }
124 };
125
126 let initializer = response_arc.initializer();
129
130 let status = initializer["status"].as_u64().ok_or_else(|| {
132 crate::error::Error::ProtocolError("Response missing status".to_string())
133 })? as u16;
134
135 let headers = initializer["headers"]
137 .as_array()
138 .ok_or_else(|| {
139 crate::error::Error::ProtocolError("Response missing headers".to_string())
140 })?
141 .iter()
142 .filter_map(|h| {
143 let name = h["name"].as_str()?;
144 let value = h["value"].as_str()?;
145 Some((name.to_string(), value.to_string()))
146 })
147 .collect();
148
149 Ok(Some(Response {
150 url: initializer["url"]
151 .as_str()
152 .ok_or_else(|| {
153 crate::error::Error::ProtocolError("Response missing url".to_string())
154 })?
155 .to_string(),
156 status,
157 status_text: initializer["statusText"].as_str().unwrap_or("").to_string(),
158 ok: (200..300).contains(&status), headers,
160 }))
161 } else {
162 Ok(None)
165 }
166 }
167
168 pub async fn title(&self) -> Result<String> {
172 #[derive(Deserialize)]
173 struct TitleResponse {
174 value: String,
175 }
176
177 let response: TitleResponse = self.channel().send("title", serde_json::json!({})).await?;
178 Ok(response.value)
179 }
180
181 pub async fn query_selector(
185 &self,
186 selector: &str,
187 ) -> Result<Option<Arc<crate::protocol::ElementHandle>>> {
188 let response: serde_json::Value = self
189 .channel()
190 .send(
191 "querySelector",
192 serde_json::json!({
193 "selector": selector
194 }),
195 )
196 .await?;
197
198 if response.as_object().map(|o| o.is_empty()).unwrap_or(true) {
200 return Ok(None);
201 }
202
203 let element_value = if let Some(elem) = response.get("element") {
205 elem
206 } else if let Some(elem) = response.get("handle") {
207 elem
208 } else {
209 &response
211 };
212
213 if element_value.is_null() {
214 return Ok(None);
215 }
216
217 let guid = element_value["guid"].as_str().ok_or_else(|| {
219 crate::error::Error::ProtocolError("Element GUID missing".to_string())
220 })?;
221
222 let connection = self.base.connection();
224 let element = connection.get_object(guid).await?;
225
226 let handle = element
228 .as_any()
229 .downcast_ref::<crate::protocol::ElementHandle>()
230 .map(|e| Arc::new(e.clone()))
231 .ok_or_else(|| {
232 crate::error::Error::ProtocolError(format!(
233 "Object {} is not an ElementHandle",
234 guid
235 ))
236 })?;
237
238 Ok(Some(handle))
239 }
240
241 pub async fn query_selector_all(
245 &self,
246 selector: &str,
247 ) -> Result<Vec<Arc<crate::protocol::ElementHandle>>> {
248 #[derive(Deserialize)]
249 struct QueryAllResponse {
250 elements: Vec<serde_json::Value>,
251 }
252
253 let response: QueryAllResponse = self
254 .channel()
255 .send(
256 "querySelectorAll",
257 serde_json::json!({
258 "selector": selector
259 }),
260 )
261 .await?;
262
263 let connection = self.base.connection();
265 let mut handles = Vec::new();
266
267 for element_value in response.elements {
268 let guid = element_value["guid"].as_str().ok_or_else(|| {
269 crate::error::Error::ProtocolError("Element GUID missing".to_string())
270 })?;
271
272 let element = connection.get_object(guid).await?;
273
274 let handle = element
275 .as_any()
276 .downcast_ref::<crate::protocol::ElementHandle>()
277 .map(|e| Arc::new(e.clone()))
278 .ok_or_else(|| {
279 crate::error::Error::ProtocolError(format!(
280 "Object {} is not an ElementHandle",
281 guid
282 ))
283 })?;
284
285 handles.push(handle);
286 }
287
288 Ok(handles)
289 }
290
291 pub(crate) async fn locator_count(&self, selector: &str) -> Result<usize> {
296 #[derive(Deserialize)]
298 struct QueryAllResponse {
299 elements: Vec<serde_json::Value>,
300 }
301
302 let response: QueryAllResponse = self
303 .channel()
304 .send(
305 "querySelectorAll",
306 serde_json::json!({
307 "selector": selector
308 }),
309 )
310 .await?;
311
312 Ok(response.elements.len())
313 }
314
315 pub(crate) async fn locator_text_content(&self, selector: &str) -> Result<Option<String>> {
317 #[derive(Deserialize)]
318 struct TextContentResponse {
319 value: Option<String>,
320 }
321
322 let response: TextContentResponse = self
323 .channel()
324 .send(
325 "textContent",
326 serde_json::json!({
327 "selector": selector,
328 "strict": true,
329 "timeout": crate::DEFAULT_TIMEOUT_MS
330 }),
331 )
332 .await?;
333
334 Ok(response.value)
335 }
336
337 pub(crate) async fn locator_inner_text(&self, selector: &str) -> Result<String> {
339 #[derive(Deserialize)]
340 struct InnerTextResponse {
341 value: String,
342 }
343
344 let response: InnerTextResponse = self
345 .channel()
346 .send(
347 "innerText",
348 serde_json::json!({
349 "selector": selector,
350 "strict": true,
351 "timeout": crate::DEFAULT_TIMEOUT_MS
352 }),
353 )
354 .await?;
355
356 Ok(response.value)
357 }
358
359 pub(crate) async fn locator_inner_html(&self, selector: &str) -> Result<String> {
361 #[derive(Deserialize)]
362 struct InnerHTMLResponse {
363 value: String,
364 }
365
366 let response: InnerHTMLResponse = self
367 .channel()
368 .send(
369 "innerHTML",
370 serde_json::json!({
371 "selector": selector,
372 "strict": true,
373 "timeout": crate::DEFAULT_TIMEOUT_MS
374 }),
375 )
376 .await?;
377
378 Ok(response.value)
379 }
380
381 pub(crate) async fn locator_get_attribute(
383 &self,
384 selector: &str,
385 name: &str,
386 ) -> Result<Option<String>> {
387 #[derive(Deserialize)]
388 struct GetAttributeResponse {
389 value: Option<String>,
390 }
391
392 let response: GetAttributeResponse = self
393 .channel()
394 .send(
395 "getAttribute",
396 serde_json::json!({
397 "selector": selector,
398 "name": name,
399 "strict": true,
400 "timeout": crate::DEFAULT_TIMEOUT_MS
401 }),
402 )
403 .await?;
404
405 Ok(response.value)
406 }
407
408 pub(crate) async fn locator_is_visible(&self, selector: &str) -> Result<bool> {
410 #[derive(Deserialize)]
411 struct IsVisibleResponse {
412 value: bool,
413 }
414
415 let response: IsVisibleResponse = self
416 .channel()
417 .send(
418 "isVisible",
419 serde_json::json!({
420 "selector": selector,
421 "strict": true,
422 "timeout": crate::DEFAULT_TIMEOUT_MS
423 }),
424 )
425 .await?;
426
427 Ok(response.value)
428 }
429
430 pub(crate) async fn locator_is_enabled(&self, selector: &str) -> Result<bool> {
432 #[derive(Deserialize)]
433 struct IsEnabledResponse {
434 value: bool,
435 }
436
437 let response: IsEnabledResponse = self
438 .channel()
439 .send(
440 "isEnabled",
441 serde_json::json!({
442 "selector": selector,
443 "strict": true,
444 "timeout": crate::DEFAULT_TIMEOUT_MS
445 }),
446 )
447 .await?;
448
449 Ok(response.value)
450 }
451
452 pub(crate) async fn locator_is_checked(&self, selector: &str) -> Result<bool> {
454 #[derive(Deserialize)]
455 struct IsCheckedResponse {
456 value: bool,
457 }
458
459 let response: IsCheckedResponse = self
460 .channel()
461 .send(
462 "isChecked",
463 serde_json::json!({
464 "selector": selector,
465 "strict": true,
466 "timeout": crate::DEFAULT_TIMEOUT_MS
467 }),
468 )
469 .await?;
470
471 Ok(response.value)
472 }
473
474 pub(crate) async fn locator_is_editable(&self, selector: &str) -> Result<bool> {
476 #[derive(Deserialize)]
477 struct IsEditableResponse {
478 value: bool,
479 }
480
481 let response: IsEditableResponse = self
482 .channel()
483 .send(
484 "isEditable",
485 serde_json::json!({
486 "selector": selector,
487 "strict": true,
488 "timeout": crate::DEFAULT_TIMEOUT_MS
489 }),
490 )
491 .await?;
492
493 Ok(response.value)
494 }
495
496 pub(crate) async fn locator_is_focused(&self, selector: &str) -> Result<bool> {
502 #[derive(Deserialize)]
503 struct EvaluateResult {
504 value: serde_json::Value,
505 }
506
507 let script = r#"selector => {
510 const elements = document.querySelectorAll(selector);
511 if (elements.length === 0) return false;
512 const element = elements[0];
513 return document.activeElement === element;
514 }"#;
515
516 let params = serde_json::json!({
517 "expression": script,
518 "arg": {
519 "value": {"s": selector},
520 "handles": []
521 }
522 });
523
524 let result: EvaluateResult = self.channel().send("evaluateExpression", params).await?;
525
526 if let serde_json::Value::Object(map) = &result.value {
528 if let Some(b) = map.get("b").and_then(|v| v.as_bool()) {
529 return Ok(b);
530 }
531 }
532
533 Ok(result.value.to_string().to_lowercase().contains("true"))
535 }
536
537 pub(crate) async fn locator_click(
541 &self,
542 selector: &str,
543 options: Option<crate::protocol::ClickOptions>,
544 ) -> Result<()> {
545 let mut params = serde_json::json!({
546 "selector": selector,
547 "strict": true
548 });
549
550 if let Some(opts) = options {
551 let opts_json = opts.to_json();
552 if let Some(obj) = params.as_object_mut() {
553 if let Some(opts_obj) = opts_json.as_object() {
554 obj.extend(opts_obj.clone());
555 }
556 }
557 } else {
558 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
559 }
560
561 self.channel()
562 .send_no_result("click", params)
563 .await
564 .map_err(|e| match e {
565 Error::Timeout(msg) => {
566 Error::Timeout(format!("{} (selector: '{}')", msg, selector))
567 }
568 other => other,
569 })
570 }
571
572 pub(crate) async fn locator_dblclick(
574 &self,
575 selector: &str,
576 options: Option<crate::protocol::ClickOptions>,
577 ) -> Result<()> {
578 let mut params = serde_json::json!({
579 "selector": selector,
580 "strict": true
581 });
582
583 if let Some(opts) = options {
584 let opts_json = opts.to_json();
585 if let Some(obj) = params.as_object_mut() {
586 if let Some(opts_obj) = opts_json.as_object() {
587 obj.extend(opts_obj.clone());
588 }
589 }
590 } else {
591 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
592 }
593
594 self.channel().send_no_result("dblclick", params).await
595 }
596
597 pub(crate) async fn locator_fill(
599 &self,
600 selector: &str,
601 text: &str,
602 options: Option<crate::protocol::FillOptions>,
603 ) -> Result<()> {
604 let mut params = serde_json::json!({
605 "selector": selector,
606 "value": text,
607 "strict": true
608 });
609
610 if let Some(opts) = options {
611 let opts_json = opts.to_json();
612 if let Some(obj) = params.as_object_mut() {
613 if let Some(opts_obj) = opts_json.as_object() {
614 obj.extend(opts_obj.clone());
615 }
616 }
617 } else {
618 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
619 }
620
621 self.channel().send_no_result("fill", params).await
622 }
623
624 pub(crate) async fn locator_clear(
626 &self,
627 selector: &str,
628 options: Option<crate::protocol::FillOptions>,
629 ) -> Result<()> {
630 let mut params = serde_json::json!({
631 "selector": selector,
632 "value": "",
633 "strict": true
634 });
635
636 if let Some(opts) = options {
637 let opts_json = opts.to_json();
638 if let Some(obj) = params.as_object_mut() {
639 if let Some(opts_obj) = opts_json.as_object() {
640 obj.extend(opts_obj.clone());
641 }
642 }
643 } else {
644 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
645 }
646
647 self.channel().send_no_result("fill", params).await
648 }
649
650 pub(crate) async fn locator_press(
652 &self,
653 selector: &str,
654 key: &str,
655 options: Option<crate::protocol::PressOptions>,
656 ) -> Result<()> {
657 let mut params = serde_json::json!({
658 "selector": selector,
659 "key": key,
660 "strict": true
661 });
662
663 if let Some(opts) = options {
664 let opts_json = opts.to_json();
665 if let Some(obj) = params.as_object_mut() {
666 if let Some(opts_obj) = opts_json.as_object() {
667 obj.extend(opts_obj.clone());
668 }
669 }
670 } else {
671 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
672 }
673
674 self.channel().send_no_result("press", params).await
675 }
676
677 pub(crate) async fn locator_check(
678 &self,
679 selector: &str,
680 options: Option<crate::protocol::CheckOptions>,
681 ) -> Result<()> {
682 let mut params = serde_json::json!({
683 "selector": selector,
684 "strict": true
685 });
686
687 if let Some(opts) = options {
688 let opts_json = opts.to_json();
689 if let Some(obj) = params.as_object_mut() {
690 if let Some(opts_obj) = opts_json.as_object() {
691 obj.extend(opts_obj.clone());
692 }
693 }
694 } else {
695 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
696 }
697
698 self.channel().send_no_result("check", params).await
699 }
700
701 pub(crate) async fn locator_uncheck(
702 &self,
703 selector: &str,
704 options: Option<crate::protocol::CheckOptions>,
705 ) -> Result<()> {
706 let mut params = serde_json::json!({
707 "selector": selector,
708 "strict": true
709 });
710
711 if let Some(opts) = options {
712 let opts_json = opts.to_json();
713 if let Some(obj) = params.as_object_mut() {
714 if let Some(opts_obj) = opts_json.as_object() {
715 obj.extend(opts_obj.clone());
716 }
717 }
718 } else {
719 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
720 }
721
722 self.channel().send_no_result("uncheck", params).await
723 }
724
725 pub(crate) async fn locator_hover(
726 &self,
727 selector: &str,
728 options: Option<crate::protocol::HoverOptions>,
729 ) -> Result<()> {
730 let mut params = serde_json::json!({
731 "selector": selector,
732 "strict": true
733 });
734
735 if let Some(opts) = options {
736 let opts_json = opts.to_json();
737 if let Some(obj) = params.as_object_mut() {
738 if let Some(opts_obj) = opts_json.as_object() {
739 obj.extend(opts_obj.clone());
740 }
741 }
742 } else {
743 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
744 }
745
746 self.channel().send_no_result("hover", params).await
747 }
748
749 pub(crate) async fn locator_input_value(&self, selector: &str) -> Result<String> {
750 #[derive(Deserialize)]
751 struct InputValueResponse {
752 value: String,
753 }
754
755 let response: InputValueResponse = self
756 .channel()
757 .send(
758 "inputValue",
759 serde_json::json!({
760 "selector": selector,
761 "strict": true,
762 "timeout": crate::DEFAULT_TIMEOUT_MS }),
764 )
765 .await?;
766
767 Ok(response.value)
768 }
769
770 pub(crate) async fn locator_select_option(
771 &self,
772 selector: &str,
773 value: crate::protocol::SelectOption,
774 options: Option<crate::protocol::SelectOptions>,
775 ) -> Result<Vec<String>> {
776 #[derive(Deserialize)]
777 struct SelectOptionResponse {
778 values: Vec<String>,
779 }
780
781 let mut params = serde_json::json!({
782 "selector": selector,
783 "strict": true,
784 "options": [value.to_json()]
785 });
786
787 if let Some(opts) = options {
788 let opts_json = opts.to_json();
789 if let Some(obj) = params.as_object_mut() {
790 if let Some(opts_obj) = opts_json.as_object() {
791 obj.extend(opts_obj.clone());
792 }
793 }
794 } else {
795 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
797 }
798
799 let response: SelectOptionResponse = self.channel().send("selectOption", params).await?;
800
801 Ok(response.values)
802 }
803
804 pub(crate) async fn locator_select_option_multiple(
805 &self,
806 selector: &str,
807 values: Vec<crate::protocol::SelectOption>,
808 options: Option<crate::protocol::SelectOptions>,
809 ) -> Result<Vec<String>> {
810 #[derive(Deserialize)]
811 struct SelectOptionResponse {
812 values: Vec<String>,
813 }
814
815 let values_array: Vec<_> = values.iter().map(|v| v.to_json()).collect();
816
817 let mut params = serde_json::json!({
818 "selector": selector,
819 "strict": true,
820 "options": values_array
821 });
822
823 if let Some(opts) = options {
824 let opts_json = opts.to_json();
825 if let Some(obj) = params.as_object_mut() {
826 if let Some(opts_obj) = opts_json.as_object() {
827 obj.extend(opts_obj.clone());
828 }
829 }
830 } else {
831 params["timeout"] = serde_json::json!(crate::DEFAULT_TIMEOUT_MS);
833 }
834
835 let response: SelectOptionResponse = self.channel().send("selectOption", params).await?;
836
837 Ok(response.values)
838 }
839
840 pub(crate) async fn locator_set_input_files(
841 &self,
842 selector: &str,
843 file: &std::path::PathBuf,
844 ) -> Result<()> {
845 use base64::{engine::general_purpose, Engine as _};
846 use std::io::Read;
847
848 let mut file_handle = std::fs::File::open(file)?;
850 let mut buffer = Vec::new();
851 file_handle.read_to_end(&mut buffer)?;
852
853 let base64_content = general_purpose::STANDARD.encode(&buffer);
855
856 let file_name = file
858 .file_name()
859 .and_then(|n| n.to_str())
860 .ok_or_else(|| crate::error::Error::InvalidArgument("Invalid file path".to_string()))?;
861
862 self.channel()
863 .send_no_result(
864 "setInputFiles",
865 serde_json::json!({
866 "selector": selector,
867 "strict": true,
868 "timeout": crate::DEFAULT_TIMEOUT_MS, "payloads": [{
870 "name": file_name,
871 "buffer": base64_content
872 }]
873 }),
874 )
875 .await
876 }
877
878 pub(crate) async fn locator_set_input_files_multiple(
879 &self,
880 selector: &str,
881 files: &[&std::path::PathBuf],
882 ) -> Result<()> {
883 use base64::{engine::general_purpose, Engine as _};
884 use std::io::Read;
885
886 if files.is_empty() {
888 return self
889 .channel()
890 .send_no_result(
891 "setInputFiles",
892 serde_json::json!({
893 "selector": selector,
894 "strict": true,
895 "timeout": crate::DEFAULT_TIMEOUT_MS, "payloads": []
897 }),
898 )
899 .await;
900 }
901
902 let mut file_objects = Vec::new();
904 for file_path in files {
905 let mut file_handle = std::fs::File::open(file_path)?;
906 let mut buffer = Vec::new();
907 file_handle.read_to_end(&mut buffer)?;
908
909 let base64_content = general_purpose::STANDARD.encode(&buffer);
910 let file_name = file_path
911 .file_name()
912 .and_then(|n| n.to_str())
913 .ok_or_else(|| {
914 crate::error::Error::InvalidArgument("Invalid file path".to_string())
915 })?;
916
917 file_objects.push(serde_json::json!({
918 "name": file_name,
919 "buffer": base64_content
920 }));
921 }
922
923 self.channel()
924 .send_no_result(
925 "setInputFiles",
926 serde_json::json!({
927 "selector": selector,
928 "strict": true,
929 "timeout": crate::DEFAULT_TIMEOUT_MS, "payloads": file_objects
931 }),
932 )
933 .await
934 }
935
936 pub(crate) async fn locator_set_input_files_payload(
937 &self,
938 selector: &str,
939 file: crate::protocol::FilePayload,
940 ) -> Result<()> {
941 use base64::{engine::general_purpose, Engine as _};
942
943 let base64_content = general_purpose::STANDARD.encode(&file.buffer);
945
946 self.channel()
947 .send_no_result(
948 "setInputFiles",
949 serde_json::json!({
950 "selector": selector,
951 "strict": true,
952 "timeout": crate::DEFAULT_TIMEOUT_MS,
953 "payloads": [{
954 "name": file.name,
955 "mimeType": file.mime_type,
956 "buffer": base64_content
957 }]
958 }),
959 )
960 .await
961 }
962
963 pub(crate) async fn locator_set_input_files_payload_multiple(
964 &self,
965 selector: &str,
966 files: &[crate::protocol::FilePayload],
967 ) -> Result<()> {
968 use base64::{engine::general_purpose, Engine as _};
969
970 if files.is_empty() {
972 return self
973 .channel()
974 .send_no_result(
975 "setInputFiles",
976 serde_json::json!({
977 "selector": selector,
978 "strict": true,
979 "timeout": crate::DEFAULT_TIMEOUT_MS,
980 "payloads": []
981 }),
982 )
983 .await;
984 }
985
986 let file_objects: Vec<_> = files
988 .iter()
989 .map(|file| {
990 let base64_content = general_purpose::STANDARD.encode(&file.buffer);
991 serde_json::json!({
992 "name": file.name,
993 "mimeType": file.mime_type,
994 "buffer": base64_content
995 })
996 })
997 .collect();
998
999 self.channel()
1000 .send_no_result(
1001 "setInputFiles",
1002 serde_json::json!({
1003 "selector": selector,
1004 "strict": true,
1005 "timeout": crate::DEFAULT_TIMEOUT_MS,
1006 "payloads": file_objects
1007 }),
1008 )
1009 .await
1010 }
1011
1012 pub(crate) async fn frame_evaluate_expression(&self, expression: &str) -> Result<()> {
1016 let params = serde_json::json!({
1017 "expression": expression,
1018 "arg": {
1019 "value": {"v": "null"},
1020 "handles": []
1021 }
1022 });
1023
1024 let _: serde_json::Value = self.channel().send("evaluateExpression", params).await?;
1025 Ok(())
1026 }
1027
1028 pub(crate) async fn frame_evaluate_expression_value(&self, expression: &str) -> Result<String> {
1040 let params = serde_json::json!({
1041 "expression": expression,
1042 "arg": {
1043 "value": {"v": "null"},
1044 "handles": []
1045 }
1046 });
1047
1048 #[derive(Deserialize)]
1049 struct EvaluateResult {
1050 value: serde_json::Value,
1051 }
1052
1053 let result: EvaluateResult = self.channel().send("evaluateExpression", params).await?;
1054
1055 match &result.value {
1062 Value::Object(map) => {
1063 if let Some(s) = map.get("s").and_then(|v| v.as_str()) {
1064 Ok(s.to_string())
1066 } else if let Some(n) = map.get("n") {
1067 Ok(n.to_string())
1069 } else if let Some(b) = map.get("b").and_then(|v| v.as_bool()) {
1070 Ok(b.to_string())
1072 } else if let Some(v) = map.get("v").and_then(|v| v.as_str()) {
1073 Ok(v.to_string())
1075 } else {
1076 Ok(result.value.to_string())
1078 }
1079 }
1080 _ => {
1081 Ok(result.value.to_string())
1083 }
1084 }
1085 }
1086}
1087
1088impl ChannelOwner for Frame {
1089 fn guid(&self) -> &str {
1090 self.base.guid()
1091 }
1092
1093 fn type_name(&self) -> &str {
1094 self.base.type_name()
1095 }
1096
1097 fn parent(&self) -> Option<Arc<dyn ChannelOwner>> {
1098 self.base.parent()
1099 }
1100
1101 fn connection(&self) -> Arc<dyn crate::connection::ConnectionLike> {
1102 self.base.connection()
1103 }
1104
1105 fn initializer(&self) -> &Value {
1106 self.base.initializer()
1107 }
1108
1109 fn channel(&self) -> &Channel {
1110 self.base.channel()
1111 }
1112
1113 fn dispose(&self, reason: crate::channel_owner::DisposeReason) {
1114 self.base.dispose(reason)
1115 }
1116
1117 fn adopt(&self, child: Arc<dyn ChannelOwner>) {
1118 self.base.adopt(child)
1119 }
1120
1121 fn add_child(&self, guid: Arc<str>, child: Arc<dyn ChannelOwner>) {
1122 self.base.add_child(guid, child)
1123 }
1124
1125 fn remove_child(&self, guid: &str) {
1126 self.base.remove_child(guid)
1127 }
1128
1129 fn on_event(&self, _method: &str, _params: Value) {
1130 }
1133
1134 fn was_collected(&self) -> bool {
1135 self.base.was_collected()
1136 }
1137
1138 fn as_any(&self) -> &dyn Any {
1139 self
1140 }
1141}
1142
1143impl std::fmt::Debug for Frame {
1144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1145 f.debug_struct("Frame").field("guid", &self.guid()).finish()
1146 }
1147}