use std::{collections::VecDeque, sync::Arc};
use async_trait::async_trait;
use serde_json::Value;
use starweaver_core::CancellationToken;
use crate::ModelError;
use super::{HttpRequest, HttpResponse};
#[async_trait]
pub trait ModelHttpClient: Send + Sync {
async fn send(&self, request: HttpRequest) -> Result<HttpResponse, ModelError>;
async fn send_event_stream(&self, request: HttpRequest) -> Result<Vec<Value>, ModelError> {
let mut stream = self.send_event_stream_incremental(request).await?;
let mut events = Vec::new();
while let Some(event) = stream.recv().await {
events.push(event?);
}
Ok(events)
}
async fn send_event_stream_incremental(
&self,
request: HttpRequest,
) -> Result<ModelEventStream, ModelError> {
Err(ModelError::Transport(format!(
"server-sent event streaming is not implemented for {}",
request.url
)))
}
async fn send_websocket_event_stream_incremental(
&self,
request: HttpRequest,
) -> Result<ModelEventStream, ModelError> {
Err(ModelError::Transport(format!(
"websocket event streaming is not implemented for {}",
request.url
)))
}
fn websocket_event_session(&self) -> Box<dyn ModelWebSocketEventSession + '_> {
Box::new(PerRequestWebSocketEventSession { client: self })
}
}
#[async_trait]
pub trait ModelWebSocketEventSession: Send {
async fn send_websocket_event_stream_incremental(
&mut self,
request: HttpRequest,
) -> Result<ModelEventStream, ModelError>;
async fn reset(&mut self) {}
}
struct PerRequestWebSocketEventSession<'a, C: ModelHttpClient + ?Sized> {
client: &'a C,
}
#[async_trait]
impl<C> ModelWebSocketEventSession for PerRequestWebSocketEventSession<'_, C>
where
C: ModelHttpClient + ?Sized,
{
async fn send_websocket_event_stream_incremental(
&mut self,
request: HttpRequest,
) -> Result<ModelEventStream, ModelError> {
self.client
.send_websocket_event_stream_incremental(request)
.await
}
}
pub struct ModelEventStream {
receiver: tokio::sync::mpsc::Receiver<Result<Value, ModelError>>,
prefetched: VecDeque<Result<Value, ModelError>>,
cancellation_token: CancellationToken,
drop_abort_token: Option<CancellationToken>,
}
impl ModelEventStream {
#[must_use]
pub fn new(receiver: tokio::sync::mpsc::Receiver<Result<Value, ModelError>>) -> Self {
Self::new_with_cancellation(receiver, CancellationToken::default())
}
#[must_use]
pub const fn new_with_cancellation(
receiver: tokio::sync::mpsc::Receiver<Result<Value, ModelError>>,
cancellation_token: CancellationToken,
) -> Self {
Self::new_with_cancellation_and_drop_abort(receiver, cancellation_token, None)
}
#[must_use]
pub const fn new_with_cancellation_and_drop_abort(
receiver: tokio::sync::mpsc::Receiver<Result<Value, ModelError>>,
cancellation_token: CancellationToken,
drop_abort_token: Option<CancellationToken>,
) -> Self {
Self {
receiver,
prefetched: VecDeque::new(),
cancellation_token,
drop_abort_token,
}
}
pub(crate) fn prepend_events(
mut self,
events: impl IntoIterator<Item = Result<Value, ModelError>>,
) -> Self {
let mut prefetched = events.into_iter().collect::<VecDeque<_>>();
prefetched.append(&mut self.prefetched);
self.prefetched = prefetched;
self
}
#[must_use]
pub fn drop_abort_token(&self) -> Option<CancellationToken> {
self.drop_abort_token.clone()
}
pub async fn recv(&mut self) -> Option<Result<Value, ModelError>> {
if self.cancellation_token.is_cancelled() {
return Some(Err(ModelError::Cancelled {
reason: "model event stream cancellation requested".to_string(),
}));
}
if let Some(event) = self.prefetched.pop_front() {
return Some(event);
}
tokio::select! {
biased;
() = self.cancellation_token.cancelled() => Some(Err(ModelError::Cancelled {
reason: "model event stream cancellation requested".to_string(),
})),
event = self.receiver.recv() => event,
}
}
}
impl Drop for ModelEventStream {
fn drop(&mut self) {
if let Some(token) = &self.drop_abort_token {
token.cancel();
}
}
}
pub type DynHttpClient = Arc<dyn ModelHttpClient>;