use crate::Result;
use crate::dir_context::DirContext;
use crate::exec::ExecutorSender;
use crate::run::{Literals, new_genai_client};
use crate::runtime::runtime_inner::RuntimeInner;
use crate::script::LuaEngine;
use genai::Client;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct Runtime {
inner: Arc<RuntimeInner>,
}
impl Runtime {
pub fn new(dir_context: DirContext, exec_sender: ExecutorSender) -> Result<Self> {
let client = new_genai_client()?;
let inner = RuntimeInner::new(dir_context, client, exec_sender);
let runtime = Self { inner: Arc::new(inner) };
Ok(runtime)
}
}
impl Runtime {
pub fn new_lua_engine_with_ctx(&self, ctx: &Literals) -> Result<LuaEngine> {
LuaEngine::new_with_ctx(self.clone(), ctx)
}
#[cfg(test)]
pub fn new_lua_engine_without_ctx_test_only(&self) -> Result<LuaEngine> {
LuaEngine::new(self.clone())
}
}
impl Runtime {
pub fn genai_client(&self) -> &Client {
self.inner.genai_client()
}
pub fn dir_context(&self) -> &DirContext {
self.inner.dir_context()
}
pub fn executor_sender(&self) -> ExecutorSender {
self.inner.executor_sender()
}
}
#[cfg(test)]
mod tests_support {
use super::*;
use crate::_test_support::{SANDBOX_01_BASE_AIPACK_DIR, SANDBOX_01_WKS_DIR, gen_test_dir_path};
use crate::dir_context::{AipackBaseDir, AipackPaths};
use crate::exec::Executor;
use crate::hub::{HubEvent, get_hub};
use simple_fs::{SPath, ensure_dir};
impl Runtime {
pub fn new_test_runtime_sandbox_01() -> Result<Self> {
let current_dir = SPath::new(SANDBOX_01_WKS_DIR).canonicalize()?;
let current_dir = SPath::new(current_dir);
let wks_dir = current_dir.clone();
let aipack_base_dir = SPath::new(SANDBOX_01_BASE_AIPACK_DIR).canonicalize()?;
let aipack_base_dir = AipackBaseDir::new_for_test(aipack_base_dir)?;
let aipack_paths = AipackPaths::from_aipack_base_and_wks_dirs(aipack_base_dir, wks_dir)?;
let dir_context = DirContext::from_current_and_aipack_paths(current_dir, aipack_paths)?;
Self::new_test_runtime(dir_context)
}
pub fn new_test_runtime_for_temp_dir() -> Result<Self> {
let test_dir = gen_test_dir_path();
if test_dir.path().is_absolute() {
return Err(format!("temp dir cannot be absolute. Was '{test_dir}' ").into());
}
ensure_dir(&test_dir)?;
let current_dir = test_dir.canonicalize()?;
let wks_dir = current_dir.clone();
ensure_dir(wks_dir.path())?;
let base_aipack_dir = AipackBaseDir::new_for_test(current_dir.join(".aipack-base"))?;
ensure_dir(&*base_aipack_dir)?;
let aipack_paths = AipackPaths::from_aipack_base_and_wks_dirs(base_aipack_dir, wks_dir)?;
let dir_context = DirContext::from_current_and_aipack_paths(current_dir, aipack_paths)?;
Self::new_test_runtime(dir_context)
}
fn new_test_runtime(dir_context: DirContext) -> Result<Self> {
let executor = Executor::new();
let exec_sender = executor.sender();
tokio::spawn(async move {
if let Err(err) = executor.start().await {
let hub = get_hub();
hub.publish(HubEvent::Error { error: err.into() }).await;
hub.publish(HubEvent::Quit).await;
}
});
Self::new(dir_context, exec_sender)
}
}
}