1pub mod core;
2pub mod event;
3pub mod transform;
4
5#[cfg(test)]
6mod tests;
7
8use crate::{
9 Engine, Result, Vars, data,
10 scheduler::{Context, Runtime},
11};
12use serde::{Deserialize, Serialize, de::DeserializeOwned};
13use std::{
14 collections::HashMap,
15 sync::{Arc, Mutex},
16};
17use tracing::debug;
18
19#[cfg(test)]
20pub use core::RunningMode;
21
22#[derive(Debug, Clone)]
23pub struct Package {
24 packages: Arc<Mutex<HashMap<String, ActPackageRegister>>>,
25}
26
27pub trait ActPackage {
28 fn meta() -> ActPackageMeta;
29}
30
31#[async_trait::async_trait]
32pub trait ActPackageFn: Send + Sync {
33 fn execute(&self, _ctx: &Context) -> Result<Option<Vars>> {
35 Ok(None)
36 }
37
38 async fn start(&self, _rt: &Arc<Runtime>, _options: &Vars) -> Result<Option<Vars>> {
40 Ok(None)
41 }
42}
43
44#[derive(
45 Serialize,
46 Deserialize,
47 Debug,
48 Clone,
49 Copy,
50 Default,
51 PartialEq,
52 strum::AsRefStr,
53 strum::EnumString,
54)]
55#[serde(rename_all = "snake_case")]
56#[strum(serialize_all = "snake_case")]
57pub enum ActRunAs {
58 Func,
60 #[default]
62 Irq,
63 Msg,
65}
66
67#[derive(
68 Serialize,
69 Deserialize,
70 Debug,
71 Clone,
72 Copy,
73 Default,
74 PartialEq,
75 strum::AsRefStr,
76 strum::EnumString,
77)]
78#[serde(rename_all = "snake_case")]
79#[strum(serialize_all = "snake_case")]
80pub enum ActPackageCatalog {
81 Core,
83
84 Event,
86
87 Transform,
89
90 Form,
92
93 Ai,
95
96 #[default]
99 App,
100}
101
102#[derive(Debug, Clone, Deserialize, Serialize)]
103pub struct ActPackageMeta {
104 pub name: &'static str,
106
107 pub desc: &'static str,
109
110 pub icon: &'static str,
112
113 pub doc: &'static str,
115
116 pub version: &'static str,
118
119 pub schema: serde_json::Value,
121
122 pub run_as: ActRunAs,
125
126 pub resources: Vec<ActResource>,
129
130 pub catalog: ActPackageCatalog,
132}
133
134#[derive(Debug, Clone, Deserialize, Serialize)]
135pub struct ActResource {
136 pub name: String,
137 pub desc: String,
138 pub operations: Vec<ActOperation>,
139}
140
141#[derive(Debug, Clone, Deserialize, Serialize)]
142pub struct ActOperation {
143 pub name: String,
144 pub desc: String,
145 pub value: String,
146}
147
148#[derive(Debug, Clone)]
149pub struct ActPackageRegister {
150 pub meta: fn() -> ActPackageMeta,
151 pub(crate) create: fn(serde_json::Value) -> Result<Box<dyn ActPackageFn>>,
152}
153
154impl ActPackageRegister {
155 pub(crate) const fn new<T>() -> Self
156 where
157 T: ActPackageFn + ActPackage + DeserializeOwned + 'static,
158 {
159 Self {
160 meta: T::meta,
161 create: (|params: serde_json::Value| {
162 let meta = T::meta();
163
164 jsonschema::validate(&meta.schema, ¶ms)?;
165 let ret = serde_json::from_value::<T>(params)?;
166 Ok(Box::new(ret) as Box<dyn ActPackageFn>)
167 }),
168 }
169 }
170}
171
172impl Default for Package {
173 fn default() -> Self {
174 Self::new()
175 }
176}
177
178impl Package {
179 pub fn new() -> Self {
180 Self {
181 packages: Arc::new(Mutex::new(HashMap::new())),
182 }
183 }
184
185 pub fn register(&self, name: &str, register: &ActPackageRegister) {
186 let mut packages = self.packages.lock().unwrap();
187 packages.insert(name.to_string(), register.clone());
188 }
189
190 pub fn get(&self, name: &str) -> Option<ActPackageRegister> {
191 let registrar = self.packages.lock().unwrap();
192 registrar.get(name).cloned()
193 }
194}
195
196impl ActPackageMeta {
197 pub fn into_data(&self) -> Result<data::Package> {
198 let pack = self.clone();
199 Ok(data::Package {
200 id: pack.name.to_string(),
201 desc: pack.desc.to_string(),
202 icon: pack.icon.to_string(),
203 doc: pack.doc.to_string(),
204 version: pack.version.to_string(),
205 schema: pack.schema.to_string(),
206 run_as: pack.run_as,
207 resources: serde_json::to_string(&pack.resources)
208 .expect("cannot convert ActPackageMeta.group to json"),
209 catalog: pack.catalog,
210 create_time: 0,
211 update_time: 0,
212 timestamp: 0,
213 built_in: false,
214 })
215 }
216}
217
218inventory::collect!(ActPackageRegister);
219
220pub fn init(engine: &Engine) {
221 for register in inventory::iter::<ActPackageRegister> {
222 let meta = (register.meta)();
223 debug!("package: {}", meta.name);
224
225 let mut pack = meta
226 .into_data()
227 .unwrap_or_else(|_| panic!("cannot convert ActPackageMeta to data::Package"));
228 pack.built_in = true;
229
230 engine
231 .executor()
232 .pack()
233 .publish(&pack)
234 .unwrap_or_else(|_| panic!("cannot publish package '{}'", pack.id));
235 engine.runtime().package().register(meta.name, register);
236 }
237}