use std::sync::Arc;
use serde_json::{Value, json};
use crate::cdp::core::CdpCore;
use crate::cdp::element::ChromiumElement;
use crate::cdp::tab::doc_query_expr;
use crate::{Error, Result};
pub struct ChromiumFrame {
core: Arc<CdpCore>,
context_id: i64,
}
impl ChromiumFrame {
pub(crate) async fn from_iframe(core: Arc<CdpCore>, iframe_object_id: &str) -> Result<Self> {
let d = core
.send("DOM.describeNode", json!({ "objectId": iframe_object_id }))
.await?;
let frame_id = d["node"]["frameId"]
.as_str()
.ok_or_else(|| Error::msg("CDP: 该元素不是 iframe 或无 frameId"))?
.to_string();
Self::from_frame_id(core, &frame_id).await
}
pub(crate) async fn from_frame_id(core: Arc<CdpCore>, frame_id: &str) -> Result<Self> {
let w = core
.send(
"Page.createIsolatedWorld",
json!({ "frameId": frame_id, "worldName": "drission_frame" }),
)
.await?;
let context_id = w["executionContextId"]
.as_i64()
.ok_or_else(|| Error::msg("CDP: createIsolatedWorld 无 executionContextId"))?;
Ok(Self { core, context_id })
}
async fn eval_handle(&self, expr: &str) -> Result<Option<String>> {
let r = self
.core
.send(
"Runtime.evaluate",
json!({ "expression": expr, "contextId": self.context_id, "returnByValue": false, "awaitPromise": true }),
)
.await?;
Ok(r["result"]["objectId"].as_str().map(str::to_string))
}
async fn eval_value(&self, expr: &str) -> Result<Value> {
let r = self
.core
.send(
"Runtime.evaluate",
json!({ "expression": expr, "contextId": self.context_id, "returnByValue": true, "awaitPromise": true }),
)
.await?;
Ok(r["result"]["value"].clone())
}
pub async fn ele(&self, selector: &str) -> Result<ChromiumElement> {
match self.eval_handle(&doc_query_expr(selector, true)).await? {
Some(oid) => Ok(ChromiumElement::new(self.core.clone(), oid)),
None => Err(Error::ElementNotFound(selector.to_string())),
}
}
pub async fn eles(&self, selector: &str) -> Result<Vec<ChromiumElement>> {
let Some(arr) = self.eval_handle(&doc_query_expr(selector, false)).await? else {
return Ok(Vec::new());
};
let oids = self.core.array_object_ids(&arr).await?;
Ok(oids
.into_iter()
.map(|oid| ChromiumElement::new(self.core.clone(), oid))
.collect())
}
pub async fn run_js(&self, expression: &str) -> Result<Value> {
self.eval_value(expression).await
}
pub async fn html(&self) -> Result<String> {
Ok(self
.eval_value("document.documentElement.outerHTML")
.await?
.as_str()
.unwrap_or_default()
.to_string())
}
pub async fn s_ele(&self, selector: &str) -> Result<crate::static_element::StaticElement> {
crate::static_element::StaticElement::parse(&self.html().await?)?.ele(selector)
}
pub async fn s_eles(
&self,
selector: &str,
) -> Result<Vec<crate::static_element::StaticElement>> {
crate::static_element::StaticElement::parse(&self.html().await?)?.eles(selector)
}
}