mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
144 lines
3.8 KiB
Rust
144 lines
3.8 KiB
Rust
use http::Error as HttpError;
|
|
use reqwest::IntoUrl;
|
|
use reqwest::Method;
|
|
use reqwest::Response;
|
|
use reqwest::header::HeaderMap;
|
|
use reqwest::header::HeaderName;
|
|
use reqwest::header::HeaderValue;
|
|
use serde::Serialize;
|
|
use std::collections::HashMap;
|
|
use std::fmt::Display;
|
|
use std::time::Duration;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct CodexHttpClient {
|
|
inner: reqwest::Client,
|
|
}
|
|
|
|
impl CodexHttpClient {
|
|
pub fn new(inner: reqwest::Client) -> Self {
|
|
Self { inner }
|
|
}
|
|
|
|
pub fn get<U>(&self, url: U) -> CodexRequestBuilder
|
|
where
|
|
U: IntoUrl,
|
|
{
|
|
self.request(Method::GET, url)
|
|
}
|
|
|
|
pub fn post<U>(&self, url: U) -> CodexRequestBuilder
|
|
where
|
|
U: IntoUrl,
|
|
{
|
|
self.request(Method::POST, url)
|
|
}
|
|
|
|
pub fn request<U>(&self, method: Method, url: U) -> CodexRequestBuilder
|
|
where
|
|
U: IntoUrl,
|
|
{
|
|
let url_str = url.as_str().to_string();
|
|
CodexRequestBuilder::new(self.inner.request(method.clone(), url), method, url_str)
|
|
}
|
|
}
|
|
|
|
#[must_use = "requests are not sent unless `send` is awaited"]
|
|
#[derive(Debug)]
|
|
pub struct CodexRequestBuilder {
|
|
builder: reqwest::RequestBuilder,
|
|
method: Method,
|
|
url: String,
|
|
}
|
|
|
|
impl CodexRequestBuilder {
|
|
fn new(builder: reqwest::RequestBuilder, method: Method, url: String) -> Self {
|
|
Self {
|
|
builder,
|
|
method,
|
|
url,
|
|
}
|
|
}
|
|
|
|
fn map(self, f: impl FnOnce(reqwest::RequestBuilder) -> reqwest::RequestBuilder) -> Self {
|
|
Self {
|
|
builder: f(self.builder),
|
|
method: self.method,
|
|
url: self.url,
|
|
}
|
|
}
|
|
|
|
pub fn headers(self, headers: HeaderMap) -> Self {
|
|
self.map(|builder| builder.headers(headers))
|
|
}
|
|
|
|
pub fn header<K, V>(self, key: K, value: V) -> Self
|
|
where
|
|
HeaderName: TryFrom<K>,
|
|
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
|
HeaderValue: TryFrom<V>,
|
|
<HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
|
|
{
|
|
self.map(|builder| builder.header(key, value))
|
|
}
|
|
|
|
pub fn bearer_auth<T>(self, token: T) -> Self
|
|
where
|
|
T: Display,
|
|
{
|
|
self.map(|builder| builder.bearer_auth(token))
|
|
}
|
|
|
|
pub fn timeout(self, timeout: Duration) -> Self {
|
|
self.map(|builder| builder.timeout(timeout))
|
|
}
|
|
|
|
pub fn json<T>(self, value: &T) -> Self
|
|
where
|
|
T: ?Sized + Serialize,
|
|
{
|
|
self.map(|builder| builder.json(value))
|
|
}
|
|
|
|
pub async fn send(self) -> Result<Response, reqwest::Error> {
|
|
match self.builder.send().await {
|
|
Ok(response) => {
|
|
let request_ids = Self::extract_request_ids(&response);
|
|
tracing::debug!(
|
|
method = %self.method,
|
|
url = %self.url,
|
|
status = %response.status(),
|
|
request_ids = ?request_ids,
|
|
version = ?response.version(),
|
|
"Request completed"
|
|
);
|
|
|
|
Ok(response)
|
|
}
|
|
Err(error) => {
|
|
let status = error.status();
|
|
tracing::debug!(
|
|
method = %self.method,
|
|
url = %self.url,
|
|
status = status.map(|s| s.as_u16()),
|
|
error = %error,
|
|
"Request failed"
|
|
);
|
|
Err(error)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn extract_request_ids(response: &Response) -> HashMap<String, String> {
|
|
["cf-ray", "x-request-id", "x-oai-request-id"]
|
|
.iter()
|
|
.filter_map(|&name| {
|
|
let header_name = HeaderName::from_static(name);
|
|
let value = response.headers().get(header_name)?;
|
|
let value = value.to_str().ok()?.to_owned();
|
|
Some((name.to_owned(), value))
|
|
})
|
|
.collect()
|
|
}
|
|
}
|