use bytes::Bytes;
#[derive(Debug, Clone, Copy, Default)]
pub struct TransportOptions {
pub total_timeout: Option<std::time::Duration>,
pub max_redirects: Option<usize>,
pub http_version: Option<http::Version>,
pub omit_body: bool,
}
pub trait ByteStreamDecoder: Send {
fn push(&mut self, chunk: &[u8]) -> Result<Vec<u8>, ClientError>;
fn finish(&mut self) -> Result<Vec<u8>, ClientError>;
}
#[derive(Debug, thiserror::Error)]
pub enum ClientError {
#[error("upstream transport error: {0}")]
Transport(String),
#[error("upstream client config error: {0}")]
Config(String),
#[error("upstream stream decode failed: {0}")]
Decode(String),
}
#[cfg(not(target_arch = "wasm32"))]
pub type RespStream =
std::pin::Pin<Box<dyn futures_core::Stream<Item = Result<Bytes, ClientError>> + Send>>;
#[cfg(target_arch = "wasm32")]
pub type RespStream =
std::pin::Pin<Box<dyn futures_core::Stream<Item = Result<Bytes, ClientError>>>>;
#[cfg(not(target_arch = "wasm32"))]
#[derive(Debug)]
pub enum ConduitFrame {
Text(String),
Binary(Bytes),
Close,
}
#[cfg(not(target_arch = "wasm32"))]
#[async_trait::async_trait]
pub trait ConduitSocket: Send {
async fn send_text(&mut self, text: String) -> Result<(), ClientError>;
async fn send_binary(&mut self, _bytes: Bytes) -> Result<(), ClientError> {
Err(ClientError::Config(
"binary upstream websocket frames not supported by this client".into(),
))
}
async fn recv_text(&mut self) -> Option<Result<String, ClientError>>;
async fn recv_frame(&mut self) -> Option<Result<ConduitFrame, ClientError>> {
self.recv_text()
.await
.map(|result| result.map(ConduitFrame::Text))
}
async fn close(&mut self) -> Result<(), ClientError> {
Ok(())
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
pub trait UpstreamClient: Send + Sync {
async fn send(&self, req: http::Request<Bytes>) -> Result<http::Response<Bytes>, ClientError>;
async fn send_websocket(
&self,
_req: http::Request<Bytes>,
) -> Result<http::Response<Bytes>, ClientError> {
Err(ClientError::Config(
"upstream websocket not supported by this client".into(),
))
}
async fn send_streaming(
&self,
req: http::Request<Bytes>,
) -> Result<(http::StatusCode, http::HeaderMap, RespStream), ClientError> {
let resp = self.send(req).await?;
let (parts, body) = resp.into_parts();
let once = futures_util::stream::once(async move { Ok::<Bytes, ClientError>(body) });
Ok((parts.status, parts.headers, Box::pin(once)))
}
#[cfg(not(target_arch = "wasm32"))]
async fn open_websocket(
&self,
_req: http::Request<Bytes>,
) -> Result<Box<dyn ConduitSocket>, ClientError> {
Err(ClientError::Config(
"upstream websocket not supported by this client".into(),
))
}
}