Skip to main content

acts_next/env/
mod.rs

1mod moudle;
2#[cfg(test)]
3mod tests;
4mod value;
5
6use crate::{ActError, Result, ShareLock, Vars};
7use core::fmt;
8use rquickjs::{Context as JsContext, Ctx as JsCtx, FromJs, Runtime as JsRuntime};
9use serde::de::DeserializeOwned;
10use std::sync::{Arc, RwLock};
11
12use self::value::ActValue;
13
14pub trait ActModule: Send + Sync {
15    fn init(&self, ctx: &JsCtx<'_>) -> Result<()>;
16}
17
18/// User var trait
19/// It can create user releated context data
20///
21/// # Example
22/// ```rust
23///   use acts::{ActUserVar, Vars, Result};
24///   #[derive(Clone)]
25///   pub struct TestModule;
26///   impl ActUserVar for TestModule {
27///     fn name(&self) -> String {
28///         "my_var".to_string()
29///     }
30///     
31///     fn default_data(&self) -> Option<Vars> {
32///         None
33///     }
34///   }
35/// ```
36pub trait ActUserVar: Send + Sync {
37    /// global easier access name in js expression
38    /// such as secrets.TOKEN, the secrets will be the name
39    /// it will get the data by the name from task context
40    fn name(&self) -> String;
41
42    /// initialzie default data
43    /// the data will be overridden by context vars
44    fn default_data(&self) -> Option<Vars> {
45        None
46    }
47}
48
49#[derive(Clone)]
50pub struct Enviroment {
51    modules: ShareLock<Vec<Box<dyn ActModule>>>,
52    pub(crate) user_vars: ShareLock<Vec<Box<dyn ActUserVar>>>,
53}
54
55impl fmt::Debug for Enviroment {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        f.debug_struct("Enviroment").finish()
58    }
59}
60
61unsafe impl Send for Enviroment {}
62unsafe impl Sync for Enviroment {}
63
64impl Default for Enviroment {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl Enviroment {
71    pub fn new() -> Self {
72        let mut env = Enviroment {
73            modules: Arc::new(RwLock::new(Vec::new())),
74            user_vars: Arc::new(RwLock::new(Vec::new())),
75        };
76        env.init();
77        env
78    }
79
80    #[cfg(test)]
81    pub fn user_env_count(&self) -> usize {
82        self.user_vars.read().unwrap().len()
83    }
84
85    pub fn register_var<T: ActUserVar + Clone + 'static>(&self, module: &T) {
86        let mut user_envs = self.user_vars.write().unwrap();
87        user_envs.push(Box::new(module.clone()));
88    }
89
90    pub fn eval<T>(&self, expr: &str) -> Result<T>
91    where
92        T: DeserializeOwned,
93    {
94        let runtime = JsRuntime::new().unwrap();
95        let ctx = JsContext::full(&runtime).unwrap();
96        ctx.with(|ctx| {
97            let modules = self.modules.read().unwrap();
98            for m in modules.iter() {
99                m.init(&ctx)?;
100            }
101
102            let result = ctx.eval::<ActValue, &str>(expr);
103            if let Err(rquickjs::Error::Exception) = result {
104                let exception = rquickjs::Exception::from_js(&ctx, ctx.catch()).unwrap();
105                eprintln!("error: {exception:?}");
106                return Err(ActError::Exception {
107                    ecode: "".to_string(),
108                    message: exception.message().unwrap_or_default(),
109                });
110            }
111
112            let value = result.map_err(ActError::from)?;
113            let ret = serde_json::from_value::<T>(value.into()).map_err(ActError::from)?;
114            Ok(ret)
115        })
116    }
117}