use std::time::Duration;
use anyhow::{Context as _, Result};
pub const USER_AGENT: &str = concat!("anodizer/", env!("CARGO_PKG_VERSION"));
pub fn blocking_client(timeout: Duration) -> Result<reqwest::blocking::Client> {
reqwest::blocking::Client::builder()
.user_agent(USER_AGENT)
.timeout(timeout)
.build()
.context("build blocking HTTP client")
}
pub fn async_client(timeout: Duration) -> Result<reqwest::Client> {
reqwest::Client::builder()
.user_agent(USER_AGENT)
.timeout(timeout)
.build()
.context("build async HTTP client")
}
pub fn body_read_error_message<E: std::fmt::Display>(err: E) -> String {
format!("could not read response body: {err}")
}
pub async fn body_of(resp: reqwest::Response) -> String {
match resp.text().await {
Ok(s) => s,
Err(err) => body_read_error_message(err),
}
}
pub fn body_of_blocking(resp: reqwest::blocking::Response) -> String {
match resp.text() {
Ok(s) => s,
Err(err) => body_read_error_message(err),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_body_read_error_message_uses_descriptive_prefix() {
let formatted = body_read_error_message("connection reset by peer");
assert_eq!(
formatted,
"could not read response body: connection reset by peer"
);
}
#[test]
fn test_body_read_error_message_with_io_error() {
let io_err = std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "stream ended early");
let formatted = body_read_error_message(io_err);
assert!(
formatted.starts_with("could not read response body: "),
"format must keep the descriptive prefix: {formatted}"
);
assert!(
formatted.contains("stream ended early"),
"format must include the underlying error: {formatted}"
);
}
}