browser_control/session/cdp_session.rs
1//! Transient flat-session helper for CDP page operations.
2//!
3//! Every CDP page op in `browser-control` follows the same shape: attach a
4//! flat session to the target, enable `Inspector` so renderer crashes are
5//! observable, run the op under the crash-detecting timeout, and detach
6//! regardless of outcome. This helper factors that shape so new native
7//! operations (accessibility tree, input dispatch) do not copy the block
8//! from `TabBackend::evaluate` a fourth time.
9
10use std::future::Future;
11use std::time::Duration;
12
13use anyhow::Result;
14use serde_json::json;
15
16use crate::cdp::CdpClient;
17use crate::session::crash::evaluate_with_crash_detection;
18
19/// Attach to `target_id`, run `f(session_id)` bounded by `timeout` with
20/// crash detection, then detach. Detach is best-effort: the target may
21/// already be gone, and the caller's result is what matters.
22pub async fn with_page_session<T, F, Fut>(
23 client: &CdpClient,
24 target_id: &str,
25 timeout: Duration,
26 f: F,
27) -> Result<T>
28where
29 F: FnOnce(String) -> Fut,
30 Fut: Future<Output = Result<T>>,
31{
32 let session_id = client.attach_to_target(target_id).await?;
33 // Best-effort, same rationale as `TabBackend::evaluate`: a failed
34 // enable would only mute crash detection.
35 let _ = client
36 .send_with_session("Inspector.enable", json!({}), Some(&session_id))
37 .await;
38 let fut = f(session_id.clone());
39 let result =
40 evaluate_with_crash_detection(client, target_id, Some(&session_id), fut, Some(timeout))
41 .await;
42 let _ = client
43 .send(
44 "Target.detachFromTarget",
45 json!({ "sessionId": session_id }),
46 )
47 .await;
48 result
49}