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}