#![allow(dead_code)]
use std::ops::{Deref, DerefMut};
use bytes::Bytes;
use futures_core::Stream;
use reqwest::RequestBuilder;
use serde::{de::DeserializeOwned, Serialize};
#[cfg(not(target_arch = "wasm32"))]
type InnerByteStream = std::pin::Pin<Box<dyn Stream<Item = reqwest::Result<Bytes>> + Send + Sync>>;
#[cfg(target_arch = "wasm32")]
type InnerByteStream = std::pin::Pin<Box<dyn Stream<Item = reqwest::Result<Bytes>>>>;
pub struct ByteStream(InnerByteStream);
impl ByteStream {
pub fn new(inner: InnerByteStream) -> Self {
Self(inner)
}
pub fn into_inner(self) -> InnerByteStream {
self.0
}
}
impl Deref for ByteStream {
type Target = InnerByteStream;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ByteStream {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub struct ResponseValue<T> {
inner: T,
status: reqwest::StatusCode,
headers: reqwest::header::HeaderMap,
}
impl<T: DeserializeOwned> ResponseValue<T> {
#[doc(hidden)]
pub async fn from_response<E>(response: reqwest::Response) -> Result<Self, Error<E>> {
let status = response.status();
let headers = response.headers().clone();
let full = response.bytes().await.map_err(Error::ResponseBodyError)?;
let inner =
serde_json::from_slice(&full).map_err(|e| Error::InvalidResponsePayload(full, e))?;
Ok(Self {
inner,
status,
headers,
})
}
}
#[cfg(not(target_arch = "wasm32"))]
impl ResponseValue<reqwest::Upgraded> {
#[doc(hidden)]
pub async fn upgrade<E: std::fmt::Debug>(
response: reqwest::Response,
) -> Result<Self, Error<E>> {
let status = response.status();
let headers = response.headers().clone();
if status == reqwest::StatusCode::SWITCHING_PROTOCOLS {
let inner = response.upgrade().await.map_err(Error::InvalidUpgrade)?;
Ok(Self {
inner,
status,
headers,
})
} else {
Err(Error::UnexpectedResponse(response))
}
}
}
impl ResponseValue<ByteStream> {
#[doc(hidden)]
pub fn stream(response: reqwest::Response) -> Self {
let status = response.status();
let headers = response.headers().clone();
Self {
inner: ByteStream(Box::pin(response.bytes_stream())),
status,
headers,
}
}
}
impl ResponseValue<()> {
#[doc(hidden)]
pub fn empty(response: reqwest::Response) -> Self {
let status = response.status();
let headers = response.headers().clone();
Self {
inner: (),
status,
headers,
}
}
}
impl<T> ResponseValue<T> {
pub fn new(inner: T, status: reqwest::StatusCode, headers: reqwest::header::HeaderMap) -> Self {
Self {
inner,
status,
headers,
}
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn status(&self) -> reqwest::StatusCode {
self.status
}
pub fn headers(&self) -> &reqwest::header::HeaderMap {
&self.headers
}
pub fn content_length(&self) -> Option<u64> {
self.headers
.get(reqwest::header::CONTENT_LENGTH)?
.to_str()
.ok()?
.parse::<u64>()
.ok()
}
#[doc(hidden)]
pub fn map<U: std::fmt::Debug, F, E>(self, f: F) -> Result<ResponseValue<U>, E>
where
F: FnOnce(T) -> U,
{
let Self {
inner,
status,
headers,
} = self;
Ok(ResponseValue {
inner: f(inner),
status,
headers,
})
}
}
impl ResponseValue<ByteStream> {
pub fn into_inner_stream(self) -> InnerByteStream {
self.into_inner().into_inner()
}
}
impl<T> Deref for ResponseValue<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for ResponseValue<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T> AsRef<T> for ResponseValue<T> {
fn as_ref(&self) -> &T {
&self.inner
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for ResponseValue<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
}
}
pub enum Error<E = ()> {
InvalidRequest(String),
CommunicationError(reqwest::Error),
InvalidUpgrade(reqwest::Error),
ErrorResponse(ResponseValue<E>),
ResponseBodyError(reqwest::Error),
InvalidResponsePayload(Bytes, serde_json::Error),
UnexpectedResponse(reqwest::Response),
PreHookError(String),
PostHookError(String),
}
impl<E> Error<E> {
pub fn status(&self) -> Option<reqwest::StatusCode> {
match self {
Error::InvalidRequest(_) => None,
Error::PreHookError(_) => None,
Error::PostHookError(_) => None,
Error::CommunicationError(e) => e.status(),
Error::ErrorResponse(rv) => Some(rv.status()),
Error::InvalidUpgrade(e) => e.status(),
Error::ResponseBodyError(e) => e.status(),
Error::InvalidResponsePayload(_, _) => None,
Error::UnexpectedResponse(r) => Some(r.status()),
}
}
pub fn into_untyped(self) -> Error {
match self {
Error::InvalidRequest(s) => Error::InvalidRequest(s),
Error::PreHookError(s) => Error::PreHookError(s),
Error::PostHookError(s) => Error::PostHookError(s),
Error::CommunicationError(e) => Error::CommunicationError(e),
Error::ErrorResponse(ResponseValue {
inner: _,
status,
headers,
}) => Error::ErrorResponse(ResponseValue {
inner: (),
status,
headers,
}),
Error::InvalidUpgrade(e) => Error::InvalidUpgrade(e),
Error::ResponseBodyError(e) => Error::ResponseBodyError(e),
Error::InvalidResponsePayload(b, e) => Error::InvalidResponsePayload(b, e),
Error::UnexpectedResponse(r) => Error::UnexpectedResponse(r),
}
}
}
impl<E> From<reqwest::Error> for Error<E> {
fn from(e: reqwest::Error) -> Self {
Self::CommunicationError(e)
}
}
impl<E> From<reqwest::header::InvalidHeaderValue> for Error<E> {
fn from(e: reqwest::header::InvalidHeaderValue) -> Self {
Self::InvalidRequest(e.to_string())
}
}
impl<E> std::fmt::Display for Error<E>
where
ResponseValue<E>: ErrorFormat,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::InvalidRequest(s) => {
write!(f, "Invalid Request: {}", s)?;
}
Error::CommunicationError(e) => {
write!(f, "Communication Error: {}", e)?;
}
Error::ErrorResponse(rve) => {
write!(f, "Error Response: ")?;
rve.fmt_info(f)?;
}
Error::InvalidUpgrade(e) => {
write!(f, "Invalid Response Upgrade: {}", e)?;
}
Error::ResponseBodyError(e) => {
write!(f, "Invalid Response Body Bytes: {}", e)?;
}
Error::InvalidResponsePayload(b, e) => {
write!(f, "Invalid Response Payload ({:?}): {}", b, e)?;
}
Error::UnexpectedResponse(r) => {
write!(f, "Unexpected Response: {:?}", r)?;
}
Error::PreHookError(s) => {
write!(f, "Pre-hook Error: {}", s)?;
}
Error::PostHookError(s) => {
write!(f, "Post-hook Error: {}", s)?;
}
}
if f.alternate() {
use std::error::Error as _;
let mut src = self.source().and_then(|e| e.source());
while let Some(s) = src {
write!(f, ": {s}")?;
src = s.source();
}
}
Ok(())
}
}
trait ErrorFormat {
fn fmt_info(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
}
impl<E> ErrorFormat for ResponseValue<E>
where
E: std::fmt::Debug,
{
fn fmt_info(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"status: {}; headers: {:?}; value: {:?}",
self.status, self.headers, self.inner,
)
}
}
impl ErrorFormat for ResponseValue<ByteStream> {
fn fmt_info(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"status: {}; headers: {:?}; value: <stream>",
self.status, self.headers,
)
}
}
impl<E> std::fmt::Debug for Error<E>
where
ResponseValue<E>: ErrorFormat,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
impl<E> std::error::Error for Error<E>
where
ResponseValue<E>: ErrorFormat,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::CommunicationError(e) => Some(e),
Error::InvalidUpgrade(e) => Some(e),
Error::ResponseBodyError(e) => Some(e),
Error::InvalidResponsePayload(_b, e) => Some(e),
_ => None,
}
}
}
const PATH_SET: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
.add(b' ')
.add(b'"')
.add(b'#')
.add(b'<')
.add(b'>')
.add(b'?')
.add(b'`')
.add(b'{')
.add(b'}')
.add(b'/')
.add(b'%');
#[doc(hidden)]
pub fn encode_path(pc: &str) -> String {
percent_encoding::utf8_percent_encode(pc, PATH_SET).to_string()
}
#[doc(hidden)]
pub trait RequestBuilderExt<E> {
fn form_urlencoded<T: Serialize + ?Sized>(self, body: &T) -> Result<RequestBuilder, Error<E>>;
}
impl<E> RequestBuilderExt<E> for RequestBuilder {
fn form_urlencoded<T: Serialize + ?Sized>(self, body: &T) -> Result<Self, Error<E>> {
Ok(self
.header(
reqwest::header::CONTENT_TYPE,
reqwest::header::HeaderValue::from_static("application/x-www-form-urlencoded"),
)
.body(
serde_urlencoded::to_string(body)
.map_err(|_| Error::InvalidRequest("failed to serialize body".to_string()))?,
))
}
}
#[doc(hidden)]
pub struct QueryParam<'a, T> {
name: &'a str,
value: &'a T,
}
impl<'a, T> QueryParam<'a, T> {
#[doc(hidden)]
pub fn new(name: &'a str, value: &'a T) -> Self {
Self { name, value }
}
}
impl<T> Serialize for QueryParam<'_, T>
where
T: Serialize,
{
fn serialize<S>(&self, inner: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let serializer = QuerySerializer {
inner,
name: self.name,
};
self.value.serialize(serializer)
}
}
pub(crate) struct QuerySerializer<'a, S> {
inner: S,
name: &'a str,
}
macro_rules! serialize_scalar {
($f:ident, $t:ty) => {
fn $f(self, v: $t) -> Result<Self::Ok, Self::Error> {
[(self.name, v)].serialize(self.inner)
}
};
}
impl<'a, S> serde::Serializer for QuerySerializer<'a, S>
where
S: serde::Serializer,
{
type Ok = S::Ok;
type Error = S::Error;
type SerializeSeq = QuerySeq<'a, S::SerializeSeq>;
type SerializeTuple = S::SerializeTuple;
type SerializeTupleStruct = S::SerializeTupleStruct;
type SerializeTupleVariant = S::SerializeTupleVariant;
type SerializeMap = S::SerializeMap;
type SerializeStruct = S::SerializeStruct;
type SerializeStructVariant = S::SerializeStructVariant;
serialize_scalar!(serialize_bool, bool);
serialize_scalar!(serialize_i8, i8);
serialize_scalar!(serialize_i16, i16);
serialize_scalar!(serialize_i32, i32);
serialize_scalar!(serialize_i64, i64);
serialize_scalar!(serialize_u8, u8);
serialize_scalar!(serialize_u16, u16);
serialize_scalar!(serialize_u32, u32);
serialize_scalar!(serialize_u64, u64);
serialize_scalar!(serialize_f32, f32);
serialize_scalar!(serialize_f64, f64);
serialize_scalar!(serialize_char, char);
serialize_scalar!(serialize_str, &str);
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Self::Error> {
self.inner.serialize_bytes(v)
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
self.inner.serialize_none()
}
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
self.inner.serialize_unit()
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
self.inner.serialize_unit_struct(name)
}
fn serialize_unit_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
self.inner
.serialize_unit_variant(name, variant_index, variant)
}
fn serialize_newtype_struct<T>(
self,
name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
self.inner.serialize_newtype_struct(name, value)
}
fn serialize_newtype_variant<T>(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ?Sized + Serialize,
{
self.inner
.serialize_newtype_variant(name, variant_index, variant, value)
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
let Self { inner, name, .. } = self;
Ok(QuerySeq {
inner: inner.serialize_seq(len)?,
name,
})
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
self.inner.serialize_tuple(len)
}
fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
self.inner.serialize_tuple_struct(name, len)
}
fn serialize_tuple_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
self.inner
.serialize_tuple_variant(name, variant_index, variant, len)
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
self.inner.serialize_map(len)
}
fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
self.inner.serialize_struct(name, len)
}
fn serialize_struct_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
self.inner
.serialize_struct_variant(name, variant_index, variant, len)
}
}
#[doc(hidden)]
pub struct QuerySeq<'a, S> {
inner: S,
name: &'a str,
}
impl<S> serde::ser::SerializeSeq for QuerySeq<'_, S>
where
S: serde::ser::SerializeSeq,
{
type Ok = S::Ok;
type Error = S::Error;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ?Sized + Serialize,
{
let v = (self.name, value);
self.inner.serialize_element(&v)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
self.inner.end()
}
}