diff --git a/chromiumoxide_types/Cargo.toml b/chromiumoxide_types/Cargo.toml index 395983d2..469ec043 100644 --- a/chromiumoxide_types/Cargo.toml +++ b/chromiumoxide_types/Cargo.toml @@ -12,4 +12,4 @@ include = ["src/**/*", "LICENSE-*"] [dependencies] serde = { version = "1.0.130", features = ["derive"] } -serde_json = "1.0.72" +serde_json = { version = "1.0.72", features = ["raw_value"] } diff --git a/chromiumoxide_types/src/lib.rs b/chromiumoxide_types/src/lib.rs index ce6f022e..21639424 100644 --- a/chromiumoxide_types/src/lib.rs +++ b/chromiumoxide_types/src/lib.rs @@ -48,9 +48,12 @@ pub trait Command: serde::ser::Serialize + Method { /// The type of the response this request triggers on the chromium server type Response: serde::de::DeserializeOwned + fmt::Debug; - /// deserialize the response from json - fn response_from_value(response: serde_json::Value) -> serde_json::Result { - serde_json::from_value(response) + /// A helper method to make the response type inferenced without fullly qualifying response type that returns the identical value. + /// + /// For example: `let response = serde_json::from_str(res).map(CaptureSnapshotParams::infer_response)?;` + /// instead of `let response = serde_json::from_str::<::Response>(res)?;` + fn infer_response(res: Self::Response) -> Self::Response { + res } } @@ -186,12 +189,12 @@ impl Request { } /// A response to a [`MethodCall`] from the chromium instance -#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] +#[derive(Deserialize, Debug, Clone)] pub struct Response { /// Numeric identifier for the exact request pub id: CallId, /// The response payload - pub result: Option, + pub result: Option>, /// The Reason why the [`MethodCall`] failed. pub error: Option, } diff --git a/src/cmd.rs b/src/cmd.rs index 5b96335e..7289b4b4 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -19,12 +19,14 @@ pub(crate) fn to_command_response( method: MethodId, ) -> Result> { if let Some(res) = resp.result { - let result = serde_json::from_value(res)?; - Ok(CommandResponse { - id: resp.id, - result, - method, - }) + match serde_json::from_str(res.get()) { + Ok(result) => Ok(CommandResponse { + id: resp.id, + result, + method, + }), + Err(error) => Err(CdpError::InvalidResponse { result: res, error }), + } } else if let Some(err) = resp.error { Err(err.into()) } else { diff --git a/src/error.rs b/src/error.rs index ce75bab4..6a72a573 100644 --- a/src/error.rs +++ b/src/error.rs @@ -61,6 +61,12 @@ pub enum CdpError { JavascriptException(Box), #[error("{0}")] Url(#[from] url::ParseError), + #[error("got invalid response with error: {error}")] + InvalidResponse { + // not Value to avoid deserialization and additional allocations + result: Box, + error: serde_json::Error, + }, } impl CdpError { pub fn msg(msg: impl Into) -> Self { diff --git a/src/handler/target.rs b/src/handler/target.rs index cfba904f..aa17c2c0 100644 --- a/src/handler/target.rs +++ b/src/handler/target.rs @@ -210,10 +210,11 @@ impl Target { #[allow(clippy::single_match)] // allow for now match method { GetFrameTreeParams::IDENTIFIER => { - if let Some(resp) = resp - .result - .and_then(|val| GetFrameTreeParams::response_from_value(val).ok()) - { + if let Some(resp) = resp.result.and_then(|val| { + serde_json::from_str(val.get()) + .map(GetFrameTreeParams::infer_response) + .ok() + }) { self.frame_manager.on_frame_tree(resp.frame_tree); } }