#![allow(clippy::needless_pass_by_value)]
mod context;
mod error;
mod json;
mod log;
mod network;
mod outcome;
mod request;
mod string_list;
mod tests;
mod version;
pub use context::IocaineContext;
pub use error::Error;
pub use outcome::Outcome;
pub use request::Request;
pub use string_list::MutableStringList;
use axum::http::HeaderMap;
use roto::{FileTree, Runtime, TypedFunc, Val, Verdict};
use std::path::Path;
use std::sync::Arc;
pub type DecideFunc =
TypedFunc<IocaineContext, fn(Val<Request>) -> Verdict<Val<Outcome>, Val<Outcome>>>;
#[derive(Debug)]
pub struct MeansOfProduction {
pub decider: DecideFunc,
pub context: IocaineContext,
}
impl MeansOfProduction {
pub fn new_runtime() -> Result<Runtime, Error> {
let mut runtime = Runtime::new();
string_list::register_string_list(&mut runtime)?;
request::register_request_type(&mut runtime)?;
context::register_context(&mut runtime)?;
outcome::register_outcome(&mut runtime)?;
version::register_version(&mut runtime)?;
log::register_log(&mut runtime)?;
json::register_json(&mut runtime)?;
network::register_network_type(&mut runtime)?;
Ok(runtime)
}
pub fn run_init(path: &str) -> Result<IocaineContext, Error> {
let runtime = Self::new_runtime()?;
let mut compiled = FileTree::directory(Path::new(&path)).compile(runtime)?;
let init = compiled.get_function::<IocaineContext, fn() -> Verdict<(), Arc<str>>>("init");
let mut context = IocaineContext::default();
if let Ok(init) = init {
init.call(&mut context)
.into_result()
.map_err(|e| Error::String(format!("init script failed: {e}")))?;
}
Ok(context)
}
pub fn new(path: &str) -> Result<Self, Error> {
let context = Self::run_init(path)?;
let runtime = Self::new_runtime()?;
let mut compiled = FileTree::directory(Path::new(path)).compile(runtime)?;
let decider = compiled
.get_function::<IocaineContext, fn(Val<Request>) -> Verdict<Val<Outcome>, Val<Outcome>>>(
"decide",
)
.map_err(|e| e.to_string())?;
Ok(Self { decider, context })
}
pub fn decide(
&self,
headers: HeaderMap,
path: Option<String>,
method: &str,
) -> Result<Outcome, Outcome> {
let request = Request {
method: method.to_owned(),
path: path.unwrap_or_default(),
headers,
};
self.decider
.call(&mut self.context.clone(), Val(request))
.into_result()
.map(|a| a.0)
.map_err(|r| r.0)
}
}