//! Chrome DevTools Protocol(CDP)通用 helper —— 仅 Windows //! //! 通过 webview2_com 的 CallDevToolsProtocolMethod 调任意 CDP 命令, //! 异步回调用 oneshot 桥成 async/await。当前供: //! - capture.rs:截图前的预热脚本 + Page.captureScreenshot //! - landing.rs:中间页轮询 div.c-tags 与 Site 链接 #![cfg(target_os = "windows")] use anyhow::{anyhow, Result}; use serde_json::Value; use std::sync::{Arc, Mutex}; use tauri::Webview; use tokio::sync::oneshot; use webview2_com::CallDevToolsProtocolMethodCompletedHandler; use windows::core::HSTRING; /// 调一个 CDP 方法,返回响应 JSON(已 parse 为 serde_json::Value)。 /// /// 失败原因可能来自三处: /// 1) with_webview 同步阶段(如 controller 为空) /// 2) CDP HRESULT 错误(远端方法不支持或 webview 已卸载) /// 3) CDP 响应不是合法 JSON(理论上不会发生) pub async fn call_cdp(webview: &Webview, method: &str, params: Value) -> Result { let (tx, rx) = oneshot::channel::>(); let tx = Arc::new(Mutex::new(Some(tx))); let method_owned = method.to_string(); let params_str = serde_json::to_string(¶ms)?; let tx_for_native = tx.clone(); let method_for_native = method_owned.clone(); webview .with_webview(move |platform| { let result: Result<()> = (|| { let controller = platform.controller(); let core = unsafe { controller.CoreWebView2()? }; let method_h: HSTRING = method_for_native.clone().into(); let params_h: HSTRING = params_str.clone().into(); let tx_handler = tx_for_native.clone(); let handler = CallDevToolsProtocolMethodCompletedHandler::create(Box::new( move |hr, json_pcwstr| { let json_str = json_pcwstr.to_string(); let res = if hr.is_ok() { Ok(json_str) } else { Err(format!("CDP HRESULT 错误: {}", hr.err().unwrap())) }; if let Ok(mut guard) = tx_handler.lock() { if let Some(sender) = guard.take() { let _ = sender.send(res); } } Ok(()) }, )); unsafe { core.CallDevToolsProtocolMethod(&method_h, ¶ms_h, &handler)?; } Ok(()) })(); if let Err(e) = result { if let Ok(mut guard) = tx_for_native.lock() { if let Some(sender) = guard.take() { let _ = sender.send(Err(format!("CDP 同步阶段失败: {e}"))); } } } }) .map_err(|e| anyhow!("with_webview 调用失败: {e}"))?; let raw = rx.await?.map_err(|_| anyhow!("CDP oneshot 通道关闭"))?; serde_json::from_str(&raw).map_err(|e| anyhow!("CDP 响应不是合法 JSON: {e}; raw={raw}")) }