use crate::agentic::{AgentStream, Config, ConfigSchema};
use crate::{FromSchema, FromWire, IntoSchema, IntoWire, WireSchema};
#[derive(Clone, IntoSchema, FromSchema, IntoWire, FromWire, WireSchema)]
pub struct Header {
pub name: String,
pub value: Vec<u8>,
}
#[derive(IntoSchema, FromSchema, IntoWire, FromWire, WireSchema)]
pub struct HttpRequest {
pub method: String,
pub scheme: String,
pub authority: String,
pub path: String,
pub query: Option<String>,
pub headers: Vec<Header>,
pub body: AgentStream<Vec<u8>>,
}
#[derive(IntoSchema, FromSchema, IntoWire, FromWire, WireSchema)]
pub struct HttpResponse {
pub status: u16,
pub headers: Vec<Header>,
pub body: AgentStream<Vec<u8>>,
}
#[derive(Clone)]
pub struct OriginalHttpRequest {
pub method: String,
pub scheme: String,
pub authority: String,
pub path: String,
pub query: Option<String>,
pub headers: Vec<Header>,
}
impl HttpRequest {
pub fn into_http(self) -> Result<http::Request<AgentStream<Vec<u8>>>, http::Error> {
let original = OriginalHttpRequest {
method: self.method.clone(),
scheme: self.scheme.clone(),
authority: self.authority.clone(),
path: self.path.clone(),
query: self.query.clone(),
headers: self.headers.clone(),
};
let query = self
.query
.as_ref()
.map(|query| format!("?{query}"))
.unwrap_or_default();
let mut request = http::Request::builder()
.method(self.method.as_str())
.uri(format!(
"{}://{}{}{query}",
self.scheme, self.authority, self.path
))
.header(http::header::HOST, self.authority);
for header in self.headers {
request = request.header(header.name, header.value);
}
let mut request = request.body(self.body)?;
request.extensions_mut().insert(original);
Ok(request)
}
}
impl From<http::Response<AgentStream<Vec<u8>>>> for HttpResponse {
fn from(response: http::Response<AgentStream<Vec<u8>>>) -> Self {
let (parts, body) = response.into_parts();
Self {
status: parts.status.as_u16(),
headers: parts
.headers
.iter()
.map(|(name, value)| Header {
name: name.as_str().to_string(),
value: value.as_bytes().to_vec(),
})
.collect(),
body,
}
}
}
#[allow(async_fn_in_trait)]
pub trait HttpRouter: Sized + 'static {
type Config: ConfigSchema;
fn new(config: Config<Self::Config>) -> Self;
async fn handle(&self, _request: HttpRequest) -> HttpResponse {
panic!("HttpRouter::handle is not implemented or registered")
}
async fn openapi(&self) -> String {
panic!("HttpRouter::openapi is not implemented or registered")
}
}