use std::error::Error;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::sync::Arc;
use aion::engine::builder::WorkflowPackageSource;
use aion::signal::ConcreteSignalRouter;
use aion::{Engine, EngineBuilder};
use aion_awl_package::compile_and_assemble_awl;
use aion_client::Client;
use aion_store_libsql::LibSqlStore;
use super::store_dir;
pub struct EmbeddedAion {
pub runtime: tokio::runtime::Runtime,
pub engine: Arc<Engine>,
pub dir: PathBuf,
}
impl EmbeddedAion {
pub fn start(label: &str, awl_sources: &[&str]) -> Result<Self, Box<dyn Error>> {
Self::start_at(store_dir(label)?, awl_sources, |builder| builder)
}
pub fn start_at(
dir: PathBuf,
awl_sources: &[&str],
customize: impl FnOnce(EngineBuilder) -> EngineBuilder,
) -> Result<Self, Box<dyn Error>> {
let mut archives = Vec::new();
for (index, source) in awl_sources.iter().enumerate() {
let prepared = compile_and_assemble_awl(source, &dir)
.map_err(|error| format!("AWL compile refused source {index}: {error}"))?;
let path = dir.join(format!("workflow-{index}.aion"));
std::fs::write(&path, &prepared.archive)?;
archives.push(path);
}
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()?;
let engine = runtime.block_on(async {
let store = LibSqlStore::open(dir.join("aion.db")).await?;
let mut builder = EngineBuilder::new()
.store(store)
.in_memory_visibility()
.event_streaming(NonZeroUsize::new(256).expect("nonzero"))
.signal_router_factory(|runtime, handoff| {
Arc::new(ConcreteSignalRouter::new(runtime, handoff))
});
for archive in &archives {
builder = builder.load_workflows(WorkflowPackageSource::Path(archive.clone()));
}
customize(builder)
.build()
.await
.map_err(|error| Box::<dyn Error>::from(error.to_string()))
})?;
Ok(Self {
runtime,
engine: Arc::new(engine),
dir,
})
}
pub fn client(&self) -> Client {
Client::embedded(Arc::clone(&self.engine))
}
}