Skip to main content

rust_okx/transport/
mod.rs

1//! The HTTP transport abstraction.
2//!
3//! [`Transport`] is intentionally minimal: it knows nothing about OKX
4//! authentication, endpoints, or response envelopes. It only sends a fully
5//! built [`http::Request`] and returns the raw [`http::Response`]. This keeps
6//! custom and mock implementations trivial, and lets cross-cutting concerns
7//! (retries, logging, rate limiting) be added as wrapper types instead of new
8//! trait methods.
9//!
10//! The trait uses return-position `impl Future` (no `async_trait`), so calling
11//! it incurs no boxing or dynamic dispatch — the [`OkxClient`](crate::OkxClient)
12//! is generic over `T: Transport`.
13
14use std::future::Future;
15
16use bytes::Bytes;
17
18#[cfg(feature = "reqwest")]
19mod reqwest_impl;
20#[cfg(feature = "reqwest")]
21pub use reqwest_impl::ReqwestTransport;
22
23/// The default transport type used as the `OkxClient<T>` type parameter.
24///
25/// When the `reqwest` feature is enabled this is [`ReqwestTransport`]. Otherwise
26/// it is a placeholder that does not implement [`Transport`]; you must then
27/// supply your own transport via [`OkxClient::with_transport`](crate::OkxClient::with_transport).
28#[cfg(feature = "reqwest")]
29pub type DefaultTransport = ReqwestTransport;
30
31/// See [`DefaultTransport`].
32#[cfg(not(feature = "reqwest"))]
33pub type DefaultTransport = UnconfiguredTransport;
34
35/// Placeholder used as the default `OkxClient` transport when no built-in
36/// transport feature is enabled. It does not implement [`Transport`].
37#[cfg(not(feature = "reqwest"))]
38#[derive(Debug, Clone, Copy, Default)]
39pub struct UnconfiguredTransport;
40
41/// An opaque transport-layer error.
42///
43/// The concrete source error (e.g. `reqwest::Error`) is boxed so it does not
44/// leak into this crate's public API.
45#[derive(Debug, thiserror::Error)]
46#[error("{0}")]
47pub struct TransportError(Box<dyn std::error::Error + Send + Sync>);
48
49impl TransportError {
50    /// Wrap any boxable error as a [`TransportError`].
51    pub fn new(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
52        Self(error.into())
53    }
54
55    /// Create a [`TransportError`] from a message string.
56    pub fn message(message: impl Into<String>) -> Self {
57        Self(message.into().into())
58    }
59}
60
61/// Sends HTTP requests on behalf of the client.
62///
63/// Implementors receive a complete request (URL, method, headers, and body
64/// already set, including authentication headers) and return the raw response.
65///
66/// # Example
67///
68/// ```
69/// use bytes::Bytes;
70/// use rust_okx::{Transport, TransportError};
71///
72/// #[derive(Clone)]
73/// struct AlwaysOk;
74///
75/// impl Transport for AlwaysOk {
76///     fn send(
77///         &self,
78///         _request: http::Request<Bytes>,
79///     ) -> impl std::future::Future<Output = Result<http::Response<Bytes>, TransportError>> + Send
80///     {
81///         async move {
82///             Ok(http::Response::builder()
83///                 .status(200)
84///                 .body(Bytes::from_static(b"{\"code\":\"0\",\"msg\":\"\",\"data\":[]}"))
85///                 .unwrap())
86///         }
87///     }
88/// }
89/// ```
90pub trait Transport: Send + Sync {
91    /// Send a request and return the response.
92    fn send(
93        &self,
94        request: http::Request<Bytes>,
95    ) -> impl Future<Output = Result<http::Response<Bytes>, TransportError>> + Send;
96}