From 80acb66445a612798ddf74bd6df60b51fd674fa0 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 23 May 2020 16:16:25 -0400 Subject: better error messages when parsing a server message --- src/api.rs | 26 ++++++++++++-------------- src/error.rs | 5 +++++ src/json.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 4 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 src/json.rs (limited to 'src') diff --git a/src/api.rs b/src/api.rs index 09c90b1..c0125d6 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,5 +1,9 @@ use crate::prelude::*; +use crate::json::{ + DeserializeJsonWithPath as _, DeserializeJsonWithPathAsync as _, +}; + #[derive(serde::Serialize, Debug)] struct PreloginReq { email: String, @@ -385,8 +389,7 @@ impl Client { .send() .await .context(crate::error::Reqwest)?; - let prelogin_res: PreloginRes = - res.json().await.context(crate::error::Reqwest)?; + let prelogin_res: PreloginRes = res.json_with_path().await?; Ok(prelogin_res.kdf_iterations) } @@ -417,7 +420,7 @@ impl Client { .context(crate::error::Reqwest)?; if let reqwest::StatusCode::OK = res.status() { let connect_res: ConnectPasswordRes = - res.json().await.context(crate::error::Reqwest)?; + res.json_with_path().await?; Ok(( connect_res.access_token, connect_res.refresh_token, @@ -425,8 +428,7 @@ impl Client { )) } else { let code = res.status().as_u16(); - let error_res: ConnectErrorRes = - res.json().await.context(crate::error::Reqwest)?; + let error_res: ConnectErrorRes = res.json_with_path().await?; if error_res.error_model.message == "Username or password is incorrect. Try again" { @@ -455,8 +457,7 @@ impl Client { .context(crate::error::Reqwest)?; match res.status() { reqwest::StatusCode::OK => { - let sync_res: SyncRes = - res.json().await.context(crate::error::Reqwest)?; + let sync_res: SyncRes = res.json_with_path().await?; let folders = sync_res.folders.clone(); let ciphers = sync_res .ciphers @@ -760,8 +761,7 @@ impl Client { .context(crate::error::Reqwest)?; match res.status() { reqwest::StatusCode::OK => { - let folders_res: FoldersRes = - res.json().context(crate::error::Reqwest)?; + let folders_res: FoldersRes = res.json_with_path()?; Ok(folders_res .data .iter() @@ -794,8 +794,7 @@ impl Client { .context(crate::error::Reqwest)?; match res.status() { reqwest::StatusCode::OK => { - let folders_res: FoldersResData = - res.json().context(crate::error::Reqwest)?; + let folders_res: FoldersResData = res.json_with_path()?; Ok(folders_res.id) } reqwest::StatusCode::UNAUTHORIZED => { @@ -822,8 +821,7 @@ impl Client { .form(&connect_req) .send() .context(crate::error::Reqwest)?; - let connect_res: ConnectRefreshTokenRes = - res.json().context(crate::error::Reqwest)?; + let connect_res: ConnectRefreshTokenRes = res.json_with_path()?; Ok(connect_res.access_token) } @@ -844,7 +842,7 @@ impl Client { .await .context(crate::error::Reqwest)?; let connect_res: ConnectRefreshTokenRes = - res.json().await.context(crate::error::Reqwest)?; + res.json_with_path().await?; Ok(connect_res.access_token) } diff --git a/src/error.rs b/src/error.rs index a6e6a84..6e8a51e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -43,6 +43,11 @@ pub enum Error { #[snafu(display("invalid mac"))] InvalidMac, + #[snafu(display("{}", source))] + JSON { + source: serde_path_to_error::Error, + }, + #[snafu(display("failed to load config: {}", source))] LoadConfig { source: std::io::Error }, diff --git a/src/json.rs b/src/json.rs new file mode 100644 index 0000000..2816a1f --- /dev/null +++ b/src/json.rs @@ -0,0 +1,38 @@ +use crate::prelude::*; + +pub trait DeserializeJsonWithPath { + fn json_with_path(self) -> Result; +} + +impl DeserializeJsonWithPath for String { + fn json_with_path(self) -> Result { + let jd = &mut serde_json::Deserializer::from_str(&self); + serde_path_to_error::deserialize(jd).context(crate::error::JSON) + } +} + +impl DeserializeJsonWithPath for reqwest::blocking::Response { + fn json_with_path(self) -> Result { + let bytes = self.bytes().context(crate::error::Reqwest)?; + let jd = &mut serde_json::Deserializer::from_slice(&bytes); + serde_path_to_error::deserialize(jd).context(crate::error::JSON) + } +} + +#[async_trait::async_trait] +pub trait DeserializeJsonWithPathAsync { + async fn json_with_path( + self, + ) -> Result; +} + +#[async_trait::async_trait] +impl DeserializeJsonWithPathAsync for reqwest::Response { + async fn json_with_path( + self, + ) -> Result { + let bytes = self.bytes().await.context(crate::error::Reqwest)?; + let jd = &mut serde_json::Deserializer::from_slice(&bytes); + serde_path_to_error::deserialize(jd).context(crate::error::JSON) + } +} diff --git a/src/lib.rs b/src/lib.rs index f010bf0..6605c22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub mod dirs; pub mod edit; pub mod error; pub mod identity; +pub mod json; pub mod locked; pub mod pinentry; mod prelude; -- cgit v1.2.3-54-g00ecf