acts 0.18.0

a fast, lightweight, extensiable workflow engine
Documentation
use super::super::ActModule;
use crate::{ActError, Context, Result, Vars, env::value::ActJsValue};
use rquickjs::{CatchResultExt, Module as JsModule};

pub struct ActJsModule;
impl ActJsModule {
    pub fn new() -> Self {
        Self
    }

    pub fn vars(&self) -> Option<Vars> {
        if let Ok(ctx) = Context::current() {
            return Some(ctx.task().vars());
        }
        None
    }
}

#[allow(clippy::module_inception)]
#[rquickjs::module(rename_vars = "camelCase")]
mod act {
    use crate::{
        Context, TimeoutLimit, Vars,
        env::value::ActJsValue,
        utils::{self, consts},
    };

    #[rquickjs::function]
    pub fn get_act_value(name: String) -> Option<ActJsValue> {
        Context::with(|ctx| {
            if let Some(v) = ctx.task().find(&name) {
                let v = ActJsValue::new(v);
                return Some(v);
            }
            None
        })
    }

    #[rquickjs::function]
    pub fn set_act_value(name: String, value: ActJsValue) {
        Context::with(|ctx| {
            let vars = Vars::new().with(&name, value.inner());
            ctx.task().update_data(&vars);
        })
    }

    #[rquickjs::function]
    pub fn set_process_var(name: String, value: ActJsValue) {
        Context::with(|ctx| {
            let vars = Vars::new().with(&name, value.inner());
            ctx.proc.set_data(&vars);
        })
    }

    #[rquickjs::function]
    pub fn get_act_inputs() -> ActJsValue {
        Context::with(|ctx| ctx.task().inputs().into())
    }

    #[rquickjs::function]
    pub fn get_act_data() -> ActJsValue {
        Context::with(|ctx| ctx.task().data().into())
    }

    #[rquickjs::function]
    pub fn err_code() -> Option<String> {
        Context::with(|ctx| ctx.task().data().get::<String>(consts::ACT_ERR_CODE))
    }

    #[rquickjs::function]
    pub fn cost() -> i64 {
        Context::with(|ctx| {
            // the data.cost is user custom cost value
            if let Some(cost) = ctx.task().data().get::<i64>(consts::TASK_COST) {
                return cost;
            }
            ctx.task().cost()
        })
    }

    #[rquickjs::function]
    pub fn cost_in(value: String) -> bool {
        Context::with(|ctx| {
            let mut cost = utils::time::time_millis() - ctx.task().start_time();
            if let Some(v) = ctx.task().data().get::<i64>(consts::TASK_COST) {
                cost = v;
            }

            let on = TimeoutLimit::parse(&value).unwrap_or_default();
            cost >= on.as_secs() * 1000
        })
    }
}

impl ActModule for ActJsModule {
    fn init(&self, ctx: &rquickjs::Ctx<'_>) -> Result<()> {
        JsModule::declare_def::<js_act, _>(ctx.clone(), "@acts/act").unwrap();

        if let Some(vars) = self.vars() {
            for (key, value) in &vars {
                ctx.globals().set(&key, ActJsValue::new(value))?;
            }
        }

        let source = r#"
        import { get_act_value, set_act_value, set_process_var, get_act_inputs, get_act_data, err_code, cost, cost_in } from '@acts/act';

        globalThis.$get = get_act_value;
        globalThis.$set = set_act_value;
        globalThis.$inputs = get_act_inputs;
        globalThis.$data = get_act_data;
        globalThis.$set_process_var = set_process_var;
        globalThis.$ecode = err_code;
        globalThis.$cost = cost
        globalThis.$cost_in = cost_in
        "#;
        let _ = JsModule::evaluate(ctx.clone(), "@acts/act", source)
            .catch(ctx)
            .map_err(|err| ActError::Script(err.to_string()))?;

        Ok(())
    }
}