Skip to main content

agent_first_http/sdk/cdp/
session.rs

1//! Helpers around target attach / detach for one-shot CDP sessions.
2
3use std::time::Duration;
4
5use serde_json::Value;
6
7use crate::sdk::cdp::ws_client::Connection;
8use crate::shared::error::{Error, ErrorCode};
9
10/// Attach to a fresh target and return its `targetId` + `sessionId`.
11pub async fn open_blank_target(conn: &Connection) -> Result<(String, String), Error> {
12    let target = conn
13        .send(
14            "Target.createTarget",
15            &serde_json::json!({"url": "about:blank"}),
16            None,
17        )
18        .await?;
19    let target_id = target["targetId"]
20        .as_str()
21        .ok_or_else(|| {
22            Error::new(
23                ErrorCode::CdpError,
24                "Target.createTarget: no targetId returned",
25            )
26        })?
27        .to_string();
28    let session_id = attach_to_target(conn, &target_id).await?;
29    Ok((target_id, session_id))
30}
31
32pub async fn attach_to_target(conn: &Connection, target_id: &str) -> Result<String, Error> {
33    let attach = conn
34        .send(
35            "Target.attachToTarget",
36            &serde_json::json!({"targetId": target_id, "flatten": true}),
37            None,
38        )
39        .await?;
40    attach["sessionId"]
41        .as_str()
42        .map(str::to_string)
43        .ok_or_else(|| {
44            Error::new(
45                ErrorCode::CdpError,
46                "Target.attachToTarget: no sessionId returned",
47            )
48        })
49}
50
51pub async fn close_target(conn: &Connection, target_id: &str) -> Result<(), Error> {
52    let _ = conn
53        .send(
54            "Target.closeTarget",
55            &serde_json::json!({"targetId": target_id}),
56            None,
57        )
58        .await?;
59    Ok(())
60}
61
62pub async fn detach_from_target(conn: &Connection, session_id: &str) -> Result<(), Error> {
63    let _ = conn
64        .send(
65            "Target.detachFromTarget",
66            &serde_json::json!({"sessionId": session_id}),
67            None,
68        )
69        .await?;
70    Ok(())
71}
72
73/// Convenience: send a CDP command with no params, returning the JSON
74/// result.
75pub async fn call(conn: &Connection, method: &str, session_id: &str) -> Result<Value, Error> {
76    conn.send(method, &serde_json::json!({}), Some(session_id))
77        .await
78}
79
80/// Convenience: send a CDP command and wait up to `timeout` for it. Used
81/// by callers that need an explicit ceiling rather than the connection's
82/// default.
83pub async fn call_with_timeout<P: serde::Serialize>(
84    conn: &Connection,
85    method: &str,
86    params: &P,
87    session_id: Option<&str>,
88    timeout: Duration,
89) -> Result<Value, Error> {
90    tokio::time::timeout(timeout, conn.send(method, params, session_id))
91        .await
92        .map_err(|_| Error::new(ErrorCode::CdpTimeout, format!("CDP {method}: timeout")))?
93}