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(move |ctx: Ctx<'js>| {
107 // 克隆函数定义以避免生命周期问题
108 let function_definition =
109 function_definition.clone();
110
111 async move {
112 // 调用Rust函数,传入JavaScript参数
113 let response = function_definition
114 .call(Arguments(&[]))
115 .or_throw(&ctx)?;
116
117 // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
118 let k =
119 serde_json::to_value(response)
120 .or_throw(&ctx)?
121 .into();
122
123 return rquickjs::Result::Ok(
124 JsValue(k),
125 );
126 }
127 })),
128 )
129 .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
130 },
131 1 => {
132 md_namespace
133 .set(
134 function_key, // 函数名作为md对象的属性名
135 Func::from(Async(
136 move |ctx: Ctx<'js>, context: JsValue| {
137 // 克隆函数定义以避免生命周期问题
138 let function_definition =
139 function_definition.clone();
140 async move {
141 // 调用Rust函数,传入JavaScript参数
142 let response = function_definition
143 .call(Arguments(&[context.0]))
144 .or_throw(&ctx)?;
145 // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
146 let k = serde_json::to_value(response)
147 .or_throw(&ctx)?
148 .into();
149 return rquickjs::Result::Ok(JsValue(
150 k,
151 ));
152 }
153 },
154 )),
155 )
156 .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
157 },
158 2 => {
159 md_namespace
160 .set(
161 function_key, // 函数名作为md对象的属性名
162 Func::from(Async(
163 move |ctx: Ctx<'js>, context: JsValue,context2: JsValue| {
164 // 克隆函数定义以避免生命周期问题
165 let function_definition =
166 function_definition.clone();
167 async move {
168 // 调用Rust函数,传入JavaScript参数
169 let response = function_definition
170 .call(Arguments(&[context.0,context2.0]))
171 .or_throw(&ctx)?;
172 // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
173 let k = serde_json::to_value(response)
174 .or_throw(&ctx)?
175 .into();
176 return rquickjs::Result::Ok(JsValue(
177 k,
178 ));
179 }
180 },
181 )),
182 )
183 .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
184 },
185 3 => {
186 md_namespace
187 .set(
188 function_key, // 函数名作为md对象的属性名
189 Func::from(Async(
190 move |ctx: Ctx<'js>, context: JsValue,context2: JsValue,context3: JsValue| {
191 // 克隆函数定义以避免生命周期问题
192 let function_definition =
193 function_definition.clone();
194 async move {
195 // 调用Rust函数,传入JavaScript参数
196 let response = function_definition
197 .call(Arguments(&[context.0,context2.0,context3.0]))
198 .or_throw(&ctx)?;
199 // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
200 let k = serde_json::to_value(response)
201 .or_throw(&ctx)?
202 .into();
203 return rquickjs::Result::Ok(JsValue(
204 k,
205 ));
206 }
207 },
208 )),
209 )
210 .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
211 },
212 _ => {
213 md_namespace
214 .set(
215 function_key, // 函数名作为md对象的属性名
216 Func::from(Async(
217 move |ctx: Ctx<'js>, context: Vec<JsValue>| {
218 // 克隆函数定义以避免生命周期问题
219 let function_definition =
220 function_definition.clone();
221 async move {
222 // 调用Rust函数,传入JavaScript参数
223 let response = function_definition
224 .call(Arguments(&context.iter().map(|arg| arg.0.clone()).collect::<Vec<_>>()))
225 .or_throw(&ctx)?;
226 // 将Rust函数的返回值序列化为JSON,再转换为JavaScript值
227 let k = serde_json::to_value(response)
228 .or_throw(&ctx)?
229 .into();
230 return rquickjs::Result::Ok(JsValue(
231 k,
232 ));
233 }
234 },
235 )),
236 )
237 .catch(&ctx)?; // 捕获并处理可能的JavaScript异常
238 },
239 }
240 }
241 }
242
243 Ok(()) // 成功完成函数注册
244 })
245 }
246}
247
248pub struct ModuforgeModule;
249
250impl ModuleDef for ModuforgeModule {
251 fn declare<'js>(decl: &Declarations<'js>) -> rquickjs::Result<()> {
252 // 声明所有可用的函数
253 for function_key in CustomFunctionRegistry::list_functions() {
254 decl.declare(function_key.as_str())?;
255 }
256 decl.declare("default")?;
257 Ok(())
258 }
259
260 fn evaluate<'js>(
261 ctx: &Ctx<'js>,
262 exports: &Exports<'js>,
263 ) -> rquickjs::Result<()> {
264 export_default(ctx, exports, |default| {
265 // 为每个函数创建对应的异步函数
266 for function_key in CustomFunctionRegistry::list_functions() {
267 if let Some(function_definition) =
268 CustomFunctionRegistry::get_definition(&function_key)
269 {
270 let function_definition = function_definition.clone();
271 let parameters = function_definition.required_parameters();
272 match parameters {
273 0 => {
274 default.set(
275 &function_key,
276 Func::from(Async(move |ctx: Ctx<'js>| {
277 let function_definition =
278 function_definition.clone();
279 async move {
280 let response = function_definition
281 .call(Arguments(&[]))
282 .or_throw(&ctx)?;
283
284 let result =
285 serde_json::to_value(response)
286 .or_throw(&ctx)?
287 .into();
288
289 Ok::<JsValue, rquickjs::Error>(JsValue(
290 result,
291 ))
292 }
293 })),
294 )?;
295 },
296 1 => {
297 //只有一个参数
298 default.set(
299 &function_key,
300 Func::from(Async(
301 move |ctx: Ctx<'js>, args: JsValue| {
302 let function_definition =
303 function_definition.clone();
304 async move {
305 let response = function_definition
306 .call(Arguments(&[args.0]))
307 .or_throw(&ctx)?;
308
309 let result =
310 serde_json::to_value(response)
311 .or_throw(&ctx)?
312 .into();
313
314 Ok::<JsValue, rquickjs::Error>(
315 JsValue(result),
316 )
317 }
318 },
319 )),
320 )?;
321 },
322 2 => {
323 //有两个参数
324 default.set(
325 &function_key,
326 Func::from(Async(
327 move |ctx: Ctx<'js>, args: JsValue,args2: JsValue| {
328 let function_definition =
329 function_definition.clone();
330 async move {
331 let response = function_definition
332 .call(Arguments(&[args.0,args2.0]))
333 .or_throw(&ctx)?;
334
335 let result =
336 serde_json::to_value(response)
337 .or_throw(&ctx)?
338 .into();
339
340 Ok::<JsValue, rquickjs::Error>(
341 JsValue(result),
342 )
343 }
344 },
345 )),
346 )?;
347 },
348 3 => {
349 //有三个参数
350 default.set(
351 &function_key,
352 Func::from(Async(
353 move |ctx: Ctx<'js>, args: JsValue,args2: JsValue,args3: JsValue| {
354 let function_definition =
355 function_definition.clone();
356 async move {
357 let response = function_definition
358 .call(Arguments(&[args.0,args2.0,args3.0]))
359 .or_throw(&ctx)?;
360
361 let result =
362 serde_json::to_value(response)
363 .or_throw(&ctx)?
364 .into();
365
366 Ok::<JsValue, rquickjs::Error>(
367 JsValue(result),
368 )
369 }
370 },
371 )),
372 )?;
373 },
374 _ => {
375 //4个以上参数 的参数必须以数组的形式传入
376 default.set(
377 &function_key,
378 Func::from(Async(
379 move |ctx: Ctx<'js>, args: Vec<JsValue>| {
380 let function_definition =
381 function_definition.clone();
382 async move {
383 let args_vec = args
384 .iter()
385 .map(|arg| arg.0.clone())
386 .collect::<Vec<_>>();
387 let response = function_definition
388 .call(Arguments(&args_vec))
389 .or_throw(&ctx)?;
390
391 let result =
392 serde_json::to_value(response)
393 .or_throw(&ctx)?
394 .into();
395
396 Ok::<JsValue, rquickjs::Error>(
397 JsValue(result),
398 )
399 }
400 },
401 )),
402 )?;
403 },
404 }
405 }
406 }
407
408 Ok(())
409 })
410 }
411}