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