use async_trait::async_trait;
use std::time::Duration;
use tokio::time::timeout;
use crate::interceptors::{Interceptor, RequestContext};
use crate::types::{AiLibError, ChatCompletionRequest, ChatCompletionResponse};
pub struct TimeoutInterceptor {
timeout_duration: Duration,
}
impl TimeoutInterceptor {
pub fn new(timeout_duration: Duration) -> Self {
Self { timeout_duration }
}
}
impl Default for TimeoutInterceptor {
fn default() -> Self {
Self::new(Duration::from_secs(30))
}
}
#[async_trait]
impl Interceptor for TimeoutInterceptor {
async fn on_request(&self, ctx: &RequestContext, _req: &ChatCompletionRequest) {
let _ = (self.timeout_duration, ctx);
}
}
pub struct TimeoutWrapper {
interceptor: TimeoutInterceptor,
}
impl TimeoutWrapper {
pub fn new(interceptor: TimeoutInterceptor) -> Self {
Self { interceptor }
}
}
impl Default for TimeoutWrapper {
fn default() -> Self {
Self::new(TimeoutInterceptor::default())
}
}
impl TimeoutWrapper {
pub async fn execute<F, Fut>(
&self,
ctx: &RequestContext,
_req: &ChatCompletionRequest,
f: F,
) -> Result<ChatCompletionResponse, AiLibError>
where
F: Fn() -> Fut,
Fut: std::future::Future<Output = Result<ChatCompletionResponse, AiLibError>>,
{
match timeout(self.interceptor.timeout_duration, f()).await {
Ok(result) => result,
Err(_) => Err(AiLibError::TimeoutError(format!(
"Request timeout after {:?} for {}:{}",
self.interceptor.timeout_duration, ctx.provider, ctx.model
))),
}
}
}