use futures::future::LocalBoxFuture;
use serde_json::Value;
use crate::Result;
use crate::bindings::oino::extension::provider_host as wph;
pub struct ProviderStream {
pub(crate) reader: wit_bindgen::StreamReader<String>,
}
pub struct EventSink(wit_bindgen::StreamWriter<String>);
impl EventSink {
pub async fn send(&mut self, event: &impl serde::Serialize) -> bool {
let Ok(text) = serde_json::to_string(event) else {
return false;
};
self.0.write_one(text).await.is_none()
}
}
impl ProviderStream {
pub fn spawn<F, Fut>(producer: F) -> Self
where
F: FnOnce(EventSink) -> Fut + 'static,
Fut: Future<Output = ()> + 'static,
{
let (tx, rx) = crate::bindings::wit_stream::new::<String>();
wit_bindgen::spawn_local(producer(EventSink(tx)));
Self { reader: rx }
}
}
pub trait Provider: 'static {
fn stream(&'static self, request: Value) -> LocalBoxFuture<'static, Result<ProviderStream>>;
fn list_models(
&'static self,
provider_id: String,
credential: Option<Value>,
) -> LocalBoxFuture<'static, Result<Value>>;
fn oauth_login(&'static self, _provider_id: String) -> LocalBoxFuture<'static, Result<Value>> {
Box::pin(async { Err(crate::Error::msg("oauth not supported")) })
}
fn oauth_refresh(
&'static self,
_provider_id: String,
_credential: Value,
) -> LocalBoxFuture<'static, Result<Value>> {
Box::pin(async { Err(crate::Error::msg("oauth not supported")) })
}
}
pub async fn before_request(
request_id: &str,
payload: &Value,
headers: Vec<(String, String)>,
) -> (Value, Vec<(String, String)>) {
let (p, h) = wph::before_request(request_id.to_owned(), payload.to_string(), headers).await;
(
serde_json::from_str(&p).unwrap_or_else(|_| payload.clone()),
h,
)
}
pub fn after_response(request_id: &str, status: u16, headers: &[(String, String)]) {
wph::after_response(request_id, status, headers);
}
pub fn stream_event(request_id: &str, data: &Value) {
wph::stream_event(request_id, &data.to_string());
}