aily 0.0.2

A ai api proxy library.
Documentation
use crate::providers::{deepseek, openai, Provider};
use reqwest::header::HeaderMap;
use reqwest::{Body, Method, Response, Url};

pub struct Client {
    inner: reqwest::Client,
    providers: Vec<Box<dyn Provider>>,
}

impl Client {
    pub fn new() -> Self {
        Self {
            inner: reqwest::Client::new(),
            providers: vec![Box::new(openai::OpenAI), Box::new(deepseek::DeepSeek)],
        }
    }

    pub fn add_provider(mut self, provider: Box<dyn Provider>) -> Self {
        self.providers.push(provider);
        self
    }

    pub async fn request<T: Into<Body>>(
        &self,
        path: &str,
        method: Method,
        mut headers: HeaderMap,
        body: T,
    ) -> Result<Response, Box<dyn std::error::Error>> {
        let body = body.into();
        let Some(provider) = self.providers.iter().find(|p| p.is_self(body.as_bytes())) else {
            return Err("No provider found".into());
        };

        let base_url = provider.host();
        let target_url = format!("{}{}", base_url, path);
        if let Ok(url) = Url::parse(&base_url) {
            if let Some(Ok(value)) = url.host_str().map(|host| host.parse()) {
                headers.insert(reqwest::header::HOST, value);
            }
        }
        log::debug!(
            "Method: {}, Target URL: {}, Headers: {:?}",
            method,
            target_url,
            headers
        );

        let request = self
            .inner
            .request(method, target_url)
            .headers(headers)
            .body(body);
        log::debug!("Request: {:?}", request);

        let response = request.send().await.map(|mut resp| {
            if let Ok(value) = "Aily".parse() {
                resp.headers_mut().insert("X-Forwarded-By", value);
            }
            resp
        })?;
        Ok(response)
    }
}