Files
zen/bindings/nodejs/src/loader.rs
T

99 lines
2.6 KiB
Rust

use std::fmt::{Debug, Formatter};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use napi::anyhow::anyhow;
use napi::bindgen_prelude::{Buffer, Promise};
use napi::threadsafe_function::ThreadsafeFunction;
use napi::{Either, Status};
use zen_engine::loader::{
DecisionLoader as DecisionLoaderTrait, LoaderError, LoaderResponse, LoaderResult,
};
use zen_engine::model::DecisionContent;
use crate::content::ZenDecisionContent;
pub(crate) type LoaderTsfn = Arc<
ThreadsafeFunction<
String,
Promise<Option<Either<Buffer, &'static ZenDecisionContent>>>,
String,
Status,
false,
true,
>,
>;
#[derive(Default)]
pub(crate) struct DecisionLoader {
function: Option<LoaderTsfn>,
}
impl Debug for DecisionLoader {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "DecisionLoader")
}
}
impl DecisionLoader {
pub fn new(tsf: LoaderTsfn) -> Self {
Self {
function: Some(tsf),
}
}
pub async fn get_key(&self, key: &str) -> LoaderResult<Arc<DecisionContent>> {
let Some(function) = &self.function else {
return Err(LoaderError::Internal {
key: key.to_string(),
source: anyhow!("Loader is undefined"),
}
.into());
};
let promise: Promise<Option<Either<Buffer, &ZenDecisionContent>>> = function
.clone()
.call_async(key.to_string())
.await
.map_err(|e| LoaderError::Internal {
key: key.to_string(),
source: anyhow!(e.reason.clone()),
})?;
let result = promise.await.map_err(|e| LoaderError::Internal {
key: key.to_string(),
source: anyhow!(e.reason.clone()),
})?;
let Some(buffer) = result else {
return Err(LoaderError::NotFound(key.to_string()).into());
};
let decision_content = match buffer {
Either::A(buf) => Arc::new(serde_json::from_slice(buf.as_ref()).map_err(|e| {
LoaderError::Internal {
key: key.to_string(),
source: e.into(),
}
})?),
Either::B(dc) => dc.inner.clone(),
};
Ok(decision_content)
}
}
impl DecisionLoaderTrait for DecisionLoader {
fn load<'a>(
&'a self,
key: &'a str,
) -> Pin<Box<dyn Future<Output = LoaderResponse> + 'a + Send>> {
Box::pin(async move {
let decision_content = self.get_key(key).await?;
Ok(decision_content)
})
}
}