From 1b89225c78a426ecd41ba7cee4781b058135d0ea Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Tue, 24 May 2022 12:31:50 +0200 Subject: [PATCH] Move things around, improved error handling --- src/k2v-client/Cargo.toml | 4 ++ src/k2v-client/{src => }/bin/k2v-cli.rs | 0 src/k2v-client/{src => }/error.rs | 7 ++++ src/k2v-client/{src => }/lib.rs | 50 +++++++++++++++++++------ 4 files changed, 50 insertions(+), 11 deletions(-) rename src/k2v-client/{src => }/bin/k2v-cli.rs (100%) rename src/k2v-client/{src => }/error.rs (82%) rename src/k2v-client/{src => }/lib.rs (93%) diff --git a/src/k2v-client/Cargo.toml b/src/k2v-client/Cargo.toml index 6106f4db..224414ab 100644 --- a/src/k2v-client/Cargo.toml +++ b/src/k2v-client/Cargo.toml @@ -23,6 +23,10 @@ garage_util = { path = "../util", optional = true } [features] cli = ["clap", "tokio/fs", "tokio/io-std", "garage_util"] +[lib] +path = "lib.rs" + [[bin]] name = "k2v-cli" +path = "bin/k2v-cli.rs" required-features = ["cli"] diff --git a/src/k2v-client/src/bin/k2v-cli.rs b/src/k2v-client/bin/k2v-cli.rs similarity index 100% rename from src/k2v-client/src/bin/k2v-cli.rs rename to src/k2v-client/bin/k2v-cli.rs diff --git a/src/k2v-client/src/error.rs b/src/k2v-client/error.rs similarity index 82% rename from src/k2v-client/src/error.rs rename to src/k2v-client/error.rs index 62357934..98379697 100644 --- a/src/k2v-client/src/error.rs +++ b/src/k2v-client/error.rs @@ -5,6 +5,13 @@ use thiserror::Error; /// Errors returned by this crate #[derive(Error, Debug)] pub enum Error { + #[error("{0} {1}: {2} (at {3})")] + Remote( + http::StatusCode, + Cow<'static, str>, + Cow<'static, str>, + Cow<'static, str>, + ), #[error("received invalid response: {0}")] InvalidResponse(Cow<'static, str>), #[error("not found")] diff --git a/src/k2v-client/src/lib.rs b/src/k2v-client/lib.rs similarity index 93% rename from src/k2v-client/src/lib.rs rename to src/k2v-client/lib.rs index a5a7a0bb..16d51819 100644 --- a/src/k2v-client/src/lib.rs +++ b/src/k2v-client/lib.rs @@ -311,20 +311,39 @@ impl K2vClient { StatusCode::NO_CONTENT => Vec::new(), StatusCode::NOT_FOUND => return Err(Error::NotFound), StatusCode::NOT_MODIFIED => Vec::new(), - _ => { + s => { let err_body = read_body(&mut res.headers, res.body) .await .unwrap_or_default(); - error!( - "Error response {}: {}", - res.status, - std::str::from_utf8(&err_body) - .map(String::from) - .unwrap_or_else(|_| base64::encode(&err_body)) - ); - return Err(Error::InvalidResponse( - format!("invalid error code: {}", res.status).into(), - )); + let err_body_str = std::str::from_utf8(&err_body) + .map(String::from) + .unwrap_or_else(|_| base64::encode(&err_body)); + + if s.is_client_error() || s.is_server_error() { + error!("Error response {}: {}", res.status, err_body_str); + let err = match serde_json::from_slice::(&err_body) { + Ok(err) => Error::Remote( + res.status, + err.code.into(), + err.message.into(), + err.path.into(), + ), + Err(_) => Error::Remote( + res.status, + "unknown".into(), + err_body_str.into(), + "".into(), + ), + }; + return Err(err); + } else { + let msg = format!( + "Unexpected response code {}. Response body: {}", + res.status, err_body_str + ); + error!("{}", msg); + return Err(Error::InvalidResponse(msg.into())); + } } }; debug!( @@ -575,6 +594,15 @@ struct BatchDeleteResponse<'a> { deleted_items: u64, } +#[derive(Deserialize)] +struct ErrorResponse { + code: String, + message: String, + #[allow(dead_code)] + region: String, + path: String, +} + struct Response { body: Vec, status: StatusCode,