cdp.rs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. //! Chrome DevTools Protocol(CDP)通用 helper —— 仅 Windows
  2. //!
  3. //! 通过 webview2_com 的 CallDevToolsProtocolMethod 调任意 CDP 命令,
  4. //! 异步回调用 oneshot 桥成 async/await。当前供:
  5. //! - capture.rs:截图前的预热脚本 + Page.captureScreenshot
  6. //! - landing.rs:中间页轮询 div.c-tags 与 Site 链接
  7. #![cfg(target_os = "windows")]
  8. use anyhow::{anyhow, Result};
  9. use serde_json::Value;
  10. use std::sync::{Arc, Mutex};
  11. use tauri::Webview;
  12. use tokio::sync::oneshot;
  13. use webview2_com::CallDevToolsProtocolMethodCompletedHandler;
  14. use windows::core::HSTRING;
  15. /// 调一个 CDP 方法,返回响应 JSON(已 parse 为 serde_json::Value)。
  16. ///
  17. /// 失败原因可能来自三处:
  18. /// 1) with_webview 同步阶段(如 controller 为空)
  19. /// 2) CDP HRESULT 错误(远端方法不支持或 webview 已卸载)
  20. /// 3) CDP 响应不是合法 JSON(理论上不会发生)
  21. pub async fn call_cdp(webview: &Webview, method: &str, params: Value) -> Result<Value> {
  22. let (tx, rx) = oneshot::channel::<Result<String, String>>();
  23. let tx = Arc::new(Mutex::new(Some(tx)));
  24. let method_owned = method.to_string();
  25. let params_str = serde_json::to_string(&params)?;
  26. let tx_for_native = tx.clone();
  27. let method_for_native = method_owned.clone();
  28. webview
  29. .with_webview(move |platform| {
  30. let result: Result<()> = (|| {
  31. let controller = platform.controller();
  32. let core = unsafe { controller.CoreWebView2()? };
  33. let method_h: HSTRING = method_for_native.clone().into();
  34. let params_h: HSTRING = params_str.clone().into();
  35. let tx_handler = tx_for_native.clone();
  36. let handler = CallDevToolsProtocolMethodCompletedHandler::create(Box::new(
  37. move |hr, json_pcwstr| {
  38. let json_str = json_pcwstr.to_string();
  39. let res = if hr.is_ok() {
  40. Ok(json_str)
  41. } else {
  42. Err(format!("CDP HRESULT 错误: {}", hr.err().unwrap()))
  43. };
  44. if let Ok(mut guard) = tx_handler.lock() {
  45. if let Some(sender) = guard.take() {
  46. let _ = sender.send(res);
  47. }
  48. }
  49. Ok(())
  50. },
  51. ));
  52. unsafe {
  53. core.CallDevToolsProtocolMethod(&method_h, &params_h, &handler)?;
  54. }
  55. Ok(())
  56. })();
  57. if let Err(e) = result {
  58. if let Ok(mut guard) = tx_for_native.lock() {
  59. if let Some(sender) = guard.take() {
  60. let _ = sender.send(Err(format!("CDP 同步阶段失败: {e}")));
  61. }
  62. }
  63. }
  64. })
  65. .map_err(|e| anyhow!("with_webview 调用失败: {e}"))?;
  66. let raw = rx.await?.map_err(|_| anyhow!("CDP oneshot 通道关闭"))?;
  67. serde_json::from_str(&raw).map_err(|e| anyhow!("CDP 响应不是合法 JSON: {e}; raw={raw}"))
  68. }