moduforge_rules_engine/handler/function/module/
custom.rs

1//! # 自定义函数监听器模块
2//!
3//! 本模块实现了CustomListener,用于在JavaScript运行时环境中注册和管理自定义函数。
4//!
5//! ## 主要功能
6//!
7//! - **函数注册**: 在运行时启动时自动将Rust自定义函数注册到JavaScript的md命名空间
8//! - **命名空间管理**: 创建和管理md作用域,避免全局命名冲突
9//! - **类型转换**: 处理Rust和JavaScript之间的数据类型转换
10//! - **异步支持**: 提供异步函数调用支持,确保不阻塞JavaScript执行
11//! - **错误处理**: 完善的错误捕获和处理机制
12//!
13//! ## 使用场景
14//!
15//! 该监听器主要用于规则引擎中,允许在规则表达式中通过`md.functionName()`的形式
16//! 调用预定义的Rust函数,从而扩展JavaScript运行时的功能。
17//!
18//! ## 架构说明
19//!
20//! ```text
21//! CustomFunctionRegistry → CustomListener → JavaScript Runtime (md namespace)
22//!        ↓                      ↓                    ↓
23//!    函数定义存储           函数注册处理          md.functionName() 调用执行
24//! ```
25
26use std::future::Future;
27use std::pin::Pin;
28use crate::handler::function::error::{FunctionResult, ResultExt};
29use crate::handler::function::listener::{RuntimeEvent, RuntimeListener};
30use crate::handler::function::module::export_default;
31use crate::handler::function::serde::JsValue;
32use moduforge_rules_expression::{
33    CustomFunctionRegistry, functions::arguments::Arguments,
34};
35use rquickjs::module::{Declarations, Exports, ModuleDef};
36use rquickjs::prelude::{Async, Func};
37use rquickjs::{CatchResultExt, Ctx};
38
39/// 自定义函数监听器
40///
41/// 该监听器负责在JavaScript运行时启动时,将所有注册的自定义函数
42/// 绑定到JavaScript的md命名空间中,使得这些函数可以在规则表达式中通过
43/// `md.functionName()`的形式被调用
44///
45/// # 工作流程
46/// 1. 监听运行时启动事件
47/// 2. 创建或获取md命名空间对象
48/// 3. 从CustomFunctionRegistry获取所有已注册的函数
49/// 4. 将每个函数包装为异步JavaScript函数
50/// 5. 注册到JavaScript的md命名空间中
51pub struct ModuforgeListener {
52    // 目前为空结构体,后续可以添加配置或状态字段
53}
54
55impl RuntimeListener for ModuforgeListener {
56    /// 处理运行时事件的核心方法
57    ///
58    /// # 参数
59    /// - `ctx`: QuickJS上下文,用于操作JavaScript环境
60    /// - `event`: 运行时事件类型
61    ///
62    /// # 返回值
63    /// 返回一个异步Future,包含操作结果
64    fn on_event<'js>(
65        &self,
66        ctx: Ctx<'js>,
67        event: RuntimeEvent,
68    ) -> Pin<Box<dyn Future<Output = FunctionResult> + 'js>> {
69        Box::pin(async move {
70            // 只在运行时启动事件时执行函数注册
71            if event != RuntimeEvent::Startup {
72                return Ok(());
73            };
74
75            // 设置全局函数及变量
76            // 创建或获取 md 命名空间对象
77            let md_namespace = if ctx.globals().contains_key("md")? {
78                // 如果 md 已存在,获取它
79                ctx.globals().get("md")?
80            } else {
81                // 如果 md 不存在,创建一个新的空对象
82                let md_obj = rquickjs::Object::new(ctx.clone())?;
83                ctx.globals().set("md", md_obj.clone())?;
84                md_obj
85            };
86
87            // 从自定义函数注册表中获取所有函数名称
88            let functions_keys = CustomFunctionRegistry::list_functions();
89
90            // 遍历每个注册的函数
91            for function_key in functions_keys {
92                // 根据函数名获取函数定义
93                let function_definition =
94                    CustomFunctionRegistry::get_definition(&function_key);
95
96                if let Some(function_definition) = function_definition {
97                    // 将Rust函数包装为JavaScript异步函数并注册到md命名空间下
98
99                    let function_definition = function_definition.clone();
100                    let parameters = function_definition.required_parameters();
101                    match parameters {
102                        0 => {
103                            md_namespace
104                            .set(
105                                function_key, // 函数名作为md对象的属性名
106                                Func::from(Async(
107                                    move |ctx: Ctx<'js>| {
108                                        // 克隆函数定义以避免生命周期问题
109                                        let function_definition =
110                                            function_definition.clone();
111    
112                                        async move {
113                                            // 调用Rust函数,传入JavaScript参数
114                                            let response = function_definition
115                                                .call(Arguments(&[]))
116                                                .or_throw(&ctx)?;
117    
118                                            // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
119                                            let k = serde_json::to_value(response)
120                                                .or_throw(&ctx)?
121                                                .into();
122    
123                                            return rquickjs::Result::Ok(JsValue(
124                                                k,
125                                            ));
126                                        }
127                                    },
128                                )),
129                            )
130                            .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
131                        }
132                        1 => {
133                            md_namespace
134                            .set(
135                                function_key, // 函数名作为md对象的属性名
136                                Func::from(Async(
137                                    move |ctx: Ctx<'js>, context: JsValue| {
138                                        // 克隆函数定义以避免生命周期问题
139                                        let function_definition =
140                                            function_definition.clone();
141    
142                                        async move {
143                                            // 调用Rust函数,传入JavaScript参数
144                                            let response = function_definition
145                                                .call(Arguments(&[context.0]))
146                                                .or_throw(&ctx)?;
147    
148                                            // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
149                                            let k = serde_json::to_value(response)
150                                                .or_throw(&ctx)?
151                                                .into();
152    
153                                            return rquickjs::Result::Ok(JsValue(
154                                                k,
155                                            ));
156                                        }
157                                    },
158                                )),
159                            )
160                            .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
161                        }
162                        2 => {
163                            md_namespace
164                            .set(
165                                function_key, // 函数名作为md对象的属性名
166                                Func::from(Async(
167                                    move |ctx: Ctx<'js>, context: JsValue,context2: JsValue| {
168                                        // 克隆函数定义以避免生命周期问题
169                                        let function_definition =
170                                            function_definition.clone();
171    
172                                        async move {
173                                            // 调用Rust函数,传入JavaScript参数
174                                            let response = function_definition
175                                                .call(Arguments(&[context.0,context2.0]))
176                                                .or_throw(&ctx)?;
177    
178                                            // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
179                                            let k = serde_json::to_value(response)
180                                                .or_throw(&ctx)?
181                                                .into();
182    
183                                            return rquickjs::Result::Ok(JsValue(
184                                                k,
185                                            ));
186                                        }
187                                    },
188                                )),
189                            )
190                            .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
191                        }
192                        3 => {
193                            md_namespace
194                            .set(
195                                function_key, // 函数名作为md对象的属性名
196                                Func::from(Async(
197                                    move |ctx: Ctx<'js>, context: JsValue,context2: JsValue,context3: JsValue| {
198                                        // 克隆函数定义以避免生命周期问题
199                                        let function_definition =
200                                            function_definition.clone();
201    
202                                        async move {
203                                            // 调用Rust函数,传入JavaScript参数
204                                            let response = function_definition
205                                                .call(Arguments(&[context.0,context2.0,context3.0]))
206                                                .or_throw(&ctx)?;
207    
208                                            // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
209                                            let k = serde_json::to_value(response)
210                                                .or_throw(&ctx)?
211                                                .into();
212    
213                                            return rquickjs::Result::Ok(JsValue(
214                                                k,
215                                            ));
216                                        }
217                                    },
218                                )),
219                            )
220                            .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
221                        }
222                        _ => {
223                            md_namespace
224                            .set(
225                                function_key, // 函数名作为md对象的属性名
226                                Func::from(Async(
227                                    move |ctx: Ctx<'js>, context: Vec<JsValue>| {
228                                        // 克隆函数定义以避免生命周期问题
229                                        let function_definition =
230                                            function_definition.clone();
231    
232                                        async move {
233                                            // 调用Rust函数,传入JavaScript参数
234                                            let response = function_definition
235                                                .call(Arguments(&context.iter().map(|arg| arg.0.clone()).collect::<Vec<_>>()))
236                                                .or_throw(&ctx)?;
237    
238                                            // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
239                                            let k = serde_json::to_value(response)
240                                                .or_throw(&ctx)?
241                                                .into();
242    
243                                            return rquickjs::Result::Ok(JsValue(
244                                                k,
245                                            ));
246                                        }
247                                    },
248                                )),
249                            )
250                            .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
251                        }
252                    }
253                  
254                }
255            }
256
257            Ok(()) // 成功完成函数注册
258        })
259    }
260}
261
262pub struct ModuforgeModule;
263
264impl ModuleDef for ModuforgeModule {
265    fn declare<'js>(decl: &Declarations<'js>) -> rquickjs::Result<()> {
266        // 声明所有可用的函数
267        for function_key in CustomFunctionRegistry::list_functions() {
268            decl.declare(function_key.as_str())?;
269        }
270        decl.declare("default")?;
271        Ok(())
272    }
273
274    fn evaluate<'js>(
275        ctx: &Ctx<'js>,
276        exports: &Exports<'js>,
277    ) -> rquickjs::Result<()> {
278        export_default(ctx, exports, |default| {
279            // 为每个函数创建对应的异步函数
280            for function_key in CustomFunctionRegistry::list_functions() {
281                if let Some(function_definition) =
282                    CustomFunctionRegistry::get_definition(&function_key)
283                {
284                    let function_definition = function_definition.clone();
285                    let parameters = function_definition.required_parameters();
286                    match parameters {
287                        0 => {
288                            default.set(
289                                &function_key,
290                                Func::from(Async(
291                                    move |ctx: Ctx<'js>| {
292                                        let function_definition =
293                                            function_definition.clone();
294                                        async move {
295                                            let response = function_definition
296                                                .call(Arguments(&[]))
297                                                .or_throw(&ctx)?;
298
299                                            let result =
300                                                serde_json::to_value(response)
301                                                    .or_throw(&ctx)?
302                                                    .into();
303
304                                            Ok::<JsValue, rquickjs::Error>(
305                                                JsValue(result),
306                                            )
307                                        }
308                                    },
309                                )),
310                            )?;
311                        }
312                        1 => {
313                            //只有一个参数
314                            default.set(
315                                &function_key,
316                                Func::from(Async(
317                                    move |ctx: Ctx<'js>, args: JsValue| {
318                                        let function_definition =
319                                            function_definition.clone();
320                                        async move {
321                                            let response = function_definition
322                                                .call(Arguments(&[args.0]))
323                                                .or_throw(&ctx)?;
324
325                                            let result =
326                                                serde_json::to_value(response)
327                                                    .or_throw(&ctx)?
328                                                    .into();
329
330                                            Ok::<JsValue, rquickjs::Error>(
331                                                JsValue(result),
332                                            )
333                                        }
334                                    },
335                                )),
336                            )?;
337                        },
338                        2 => {
339                            //有两个参数
340                            default.set(
341                                &function_key,
342                                Func::from(Async(
343                                    move |ctx: Ctx<'js>, args: JsValue,args2: JsValue| {
344                                        let function_definition =
345                                            function_definition.clone();
346                                        async move {
347                                            let response = function_definition
348                                                .call(Arguments(&[args.0,args2.0]))
349                                                .or_throw(&ctx)?;
350
351                                            let result =
352                                                serde_json::to_value(response)
353                                                    .or_throw(&ctx)?
354                                                    .into();
355
356                                            Ok::<JsValue, rquickjs::Error>(
357                                                JsValue(result),
358                                            )
359                                        }
360                                    },
361                                )),
362                            )?;
363                        },
364                        3 => {
365                            //有三个参数
366                            default.set(
367                                &function_key,
368                                Func::from(Async(
369                                    move |ctx: Ctx<'js>, args: JsValue,args2: JsValue,args3: JsValue| {
370                                        let function_definition =
371                                            function_definition.clone();
372                                        async move {
373                                            let response = function_definition
374                                                .call(Arguments(&[args.0,args2.0,args3.0]))
375                                                .or_throw(&ctx)?;
376
377                                            let result =
378                                                serde_json::to_value(response)
379                                                    .or_throw(&ctx)?
380                                                    .into();
381
382                                            Ok::<JsValue, rquickjs::Error>(
383                                                JsValue(result),
384                                            )
385                                        }
386                                    },
387                                )),
388                            )?;
389                        },
390                        _ => {
391                            //4个以上参数 的参数必须以数组的形式传入
392                            default.set(
393                                &function_key,
394                                Func::from(Async(
395                                    move |ctx: Ctx<'js>, args: Vec<JsValue>| {
396                                        let function_definition =
397                                            function_definition.clone();
398                                        async move {
399                                            let args_vec = args
400                                                .iter()
401                                                .map(|arg| arg.0.clone())
402                                                .collect::<Vec<_>>();
403                                            let response = function_definition
404                                                .call(Arguments(&args_vec))
405                                                .or_throw(&ctx)?;
406
407                                            let result =
408                                                serde_json::to_value(response)
409                                                    .or_throw(&ctx)?
410                                                    .into();
411
412                                            Ok::<JsValue, rquickjs::Error>(
413                                                JsValue(result),
414                                            )
415                                        }
416                                    },
417                                )),
418                            )?;
419                        },
420                    }
421                }
422            }
423
424            Ok(())
425        })
426    }
427}