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}