Skip to main content

mofa_extra/rhai/
rules.rs

1//! Rhai 规则引擎
2//!
3//! 提供灵活的业务规则定义和执行能力:
4//! - 条件规则评估
5//! - 规则链和规则组
6//! - 动作触发
7//! - 规则优先级管理
8//! - 规则热更新
9
10use super::engine::{RhaiScriptEngine, ScriptContext, ScriptEngineConfig};
11use anyhow::{Result, anyhow};
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::sync::Arc;
15use tokio::sync::RwLock;
16use tracing::{info, warn};
17
18// ============================================================================
19// 规则定义
20// ============================================================================
21
22/// 规则优先级
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Default)]
24pub enum RulePriority {
25    Lowest = 0,
26    Low = 25,
27    #[default]
28    Normal = 50,
29    High = 75,
30    Highest = 100,
31    Critical = 200,
32}
33
34/// 规则匹配模式
35#[derive(Debug, Clone, Serialize, Deserialize, Default)]
36pub enum RuleMatchMode {
37    /// 第一个匹配的规则执行后停止
38    #[default]
39    FirstMatch,
40    /// 执行所有匹配的规则
41    AllMatch,
42    /// 按优先级执行所有匹配的规则
43    AllMatchOrdered,
44    /// 执行到第一个成功的规则为止
45    FirstSuccess,
46}
47
48/// 规则动作类型
49#[derive(Debug, Clone, Serialize, Deserialize)]
50#[serde(tag = "type")]
51pub enum RuleAction {
52    /// 返回固定值
53    ReturnValue { value: serde_json::Value },
54    /// 执行脚本并返回结果
55    ExecuteScript { script: String },
56    /// 调用函数
57    CallFunction {
58        function: String,
59        args: Vec<serde_json::Value>,
60    },
61    /// 修改上下文变量
62    SetVariable {
63        name: String,
64        value: serde_json::Value,
65    },
66    /// 触发事件
67    TriggerEvent {
68        event_type: String,
69        data: serde_json::Value,
70    },
71    /// 跳转到另一个规则
72    GotoRule { rule_id: String },
73    /// 停止规则执行
74    Stop,
75    /// 组合多个动作
76    Composite { actions: Vec<RuleAction> },
77}
78
79/// 规则定义
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct RuleDefinition {
82    /// 规则 ID
83    pub id: String,
84    /// 规则名称
85    pub name: String,
86    /// 规则描述
87    #[serde(default)]
88    pub description: String,
89    /// 规则优先级
90    #[serde(default)]
91    pub priority: RulePriority,
92    /// 是否启用
93    #[serde(default = "default_true")]
94    pub enabled: bool,
95    /// 条件脚本(返回 bool)
96    pub condition: String,
97    /// 规则动作
98    pub action: RuleAction,
99    /// 规则标签
100    #[serde(default)]
101    pub tags: Vec<String>,
102    /// 元数据
103    #[serde(default)]
104    pub metadata: HashMap<String, String>,
105}
106
107fn default_true() -> bool {
108    true
109}
110
111impl RuleDefinition {
112    pub fn new(id: &str, name: &str, condition: &str, action: RuleAction) -> Self {
113        Self {
114            id: id.to_string(),
115            name: name.to_string(),
116            description: String::new(),
117            priority: RulePriority::Normal,
118            enabled: true,
119            condition: condition.to_string(),
120            action,
121            tags: Vec::new(),
122            metadata: HashMap::new(),
123        }
124    }
125
126    pub fn with_priority(mut self, priority: RulePriority) -> Self {
127        self.priority = priority;
128        self
129    }
130
131    pub fn with_description(mut self, desc: &str) -> Self {
132        self.description = desc.to_string();
133        self
134    }
135
136    pub fn with_tag(mut self, tag: &str) -> Self {
137        self.tags.push(tag.to_string());
138        self
139    }
140
141    pub fn disabled(mut self) -> Self {
142        self.enabled = false;
143        self
144    }
145}
146
147// ============================================================================
148// 规则组
149// ============================================================================
150
151/// 规则组定义
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct RuleGroupDefinition {
154    /// 组 ID
155    pub id: String,
156    /// 组名称
157    pub name: String,
158    /// 组描述
159    #[serde(default)]
160    pub description: String,
161    /// 匹配模式
162    #[serde(default)]
163    pub match_mode: RuleMatchMode,
164    /// 组内规则 ID 列表
165    pub rule_ids: Vec<String>,
166    /// 是否启用
167    #[serde(default = "default_true")]
168    pub enabled: bool,
169    /// 默认动作(没有规则匹配时执行)
170    pub default_action: Option<RuleAction>,
171}
172
173impl RuleGroupDefinition {
174    pub fn new(id: &str, name: &str) -> Self {
175        Self {
176            id: id.to_string(),
177            name: name.to_string(),
178            description: String::new(),
179            match_mode: RuleMatchMode::FirstMatch,
180            rule_ids: Vec::new(),
181            enabled: true,
182            default_action: None,
183        }
184    }
185
186    pub fn with_match_mode(mut self, mode: RuleMatchMode) -> Self {
187        self.match_mode = mode;
188        self
189    }
190
191    pub fn with_rules(mut self, rule_ids: Vec<&str>) -> Self {
192        self.rule_ids = rule_ids.into_iter().map(|s| s.to_string()).collect();
193        self
194    }
195
196    pub fn with_default_action(mut self, action: RuleAction) -> Self {
197        self.default_action = Some(action);
198        self
199    }
200}
201
202// ============================================================================
203// 规则执行结果
204// ============================================================================
205
206/// 规则匹配结果
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct RuleMatchResult {
209    /// 规则 ID
210    pub rule_id: String,
211    /// 是否匹配
212    pub matched: bool,
213    /// 条件评估时间(毫秒)
214    pub evaluation_time_ms: u64,
215}
216
217/// 规则执行结果
218#[derive(Debug, Clone, Serialize, Deserialize)]
219pub struct RuleExecutionResult {
220    /// 执行的规则 ID
221    pub rule_id: String,
222    /// 是否成功
223    pub success: bool,
224    /// 动作结果
225    pub result: serde_json::Value,
226    /// 错误信息
227    pub error: Option<String>,
228    /// 执行时间(毫秒)
229    pub execution_time_ms: u64,
230    /// 变量更新
231    pub variable_updates: HashMap<String, serde_json::Value>,
232    /// 触发的事件
233    pub triggered_events: Vec<(String, serde_json::Value)>,
234}
235
236/// 规则组执行结果
237#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct RuleGroupExecutionResult {
239    /// 组 ID
240    pub group_id: String,
241    /// 匹配结果列表
242    pub match_results: Vec<RuleMatchResult>,
243    /// 执行结果列表
244    pub execution_results: Vec<RuleExecutionResult>,
245    /// 最终结果(如果有)
246    pub final_result: Option<serde_json::Value>,
247    /// 是否有规则匹配
248    pub any_matched: bool,
249    /// 是否执行了默认动作
250    pub used_default: bool,
251    /// 总执行时间(毫秒)
252    pub total_time_ms: u64,
253}
254
255// ============================================================================
256// 规则引擎
257// ============================================================================
258
259/// 规则引擎
260pub struct RuleEngine {
261    /// 脚本引擎
262    engine: Arc<RhaiScriptEngine>,
263    /// 规则存储
264    rules: Arc<RwLock<HashMap<String, RuleDefinition>>>,
265    /// 规则组存储
266    groups: Arc<RwLock<HashMap<String, RuleGroupDefinition>>>,
267    /// 事件处理器
268    event_handlers:
269        Arc<RwLock<HashMap<String, Vec<Box<dyn Fn(&str, &serde_json::Value) + Send + Sync>>>>>,
270}
271
272impl RuleEngine {
273    /// 创建规则引擎
274    pub fn new(engine_config: ScriptEngineConfig) -> Result<Self> {
275        let engine = Arc::new(RhaiScriptEngine::new(engine_config)?);
276        Ok(Self {
277            engine,
278            rules: Arc::new(RwLock::new(HashMap::new())),
279            groups: Arc::new(RwLock::new(HashMap::new())),
280            event_handlers: Arc::new(RwLock::new(HashMap::new())),
281        })
282    }
283
284    /// 使用已有引擎创建
285    pub fn with_engine(engine: Arc<RhaiScriptEngine>) -> Self {
286        Self {
287            engine,
288            rules: Arc::new(RwLock::new(HashMap::new())),
289            groups: Arc::new(RwLock::new(HashMap::new())),
290            event_handlers: Arc::new(RwLock::new(HashMap::new())),
291        }
292    }
293
294    /// 注册规则
295    pub async fn register_rule(&self, rule: RuleDefinition) -> Result<()> {
296        let mut rules = self.rules.write().await;
297        info!("Registered rule: {} ({})", rule.name, rule.id);
298        rules.insert(rule.id.clone(), rule);
299        Ok(())
300    }
301
302    /// 批量注册规则
303    pub async fn register_rules(&self, rules: Vec<RuleDefinition>) -> Result<()> {
304        for rule in rules {
305            self.register_rule(rule).await?;
306        }
307        Ok(())
308    }
309
310    /// 注册规则组
311    pub async fn register_group(&self, group: RuleGroupDefinition) -> Result<()> {
312        let mut groups = self.groups.write().await;
313        info!("Registered rule group: {} ({})", group.name, group.id);
314        groups.insert(group.id.clone(), group);
315        Ok(())
316    }
317
318    /// 从 YAML 加载规则
319    pub async fn load_rules_from_yaml(&self, path: &str) -> Result<Vec<String>> {
320        let content = tokio::fs::read_to_string(path).await?;
321        let rules: Vec<RuleDefinition> = serde_yaml::from_str(&content)?;
322        let ids: Vec<String> = rules.iter().map(|r| r.id.clone()).collect();
323        self.register_rules(rules).await?;
324        Ok(ids)
325    }
326
327    /// 从 JSON 加载规则
328    pub async fn load_rules_from_json(&self, path: &str) -> Result<Vec<String>> {
329        let content = tokio::fs::read_to_string(path).await?;
330        let rules: Vec<RuleDefinition> = serde_json::from_str(&content)?;
331        let ids: Vec<String> = rules.iter().map(|r| r.id.clone()).collect();
332        self.register_rules(rules).await?;
333        Ok(ids)
334    }
335
336    /// 评估规则条件
337    pub async fn evaluate_condition(
338        &self,
339        rule: &RuleDefinition,
340        context: &ScriptContext,
341    ) -> Result<bool> {
342        if !rule.enabled {
343            return Ok(false);
344        }
345
346        let result = self.engine.execute(&rule.condition, context).await?;
347
348        if !result.success {
349            warn!(
350                "Rule {} condition evaluation failed: {:?}",
351                rule.id, result.error
352            );
353            return Ok(false);
354        }
355
356        // 转换结果为布尔值
357        Ok(match &result.value {
358            serde_json::Value::Bool(b) => *b,
359            serde_json::Value::Number(n) => n.as_i64().unwrap_or(0) != 0,
360            serde_json::Value::String(s) => !s.is_empty() && s != "false" && s != "0",
361            serde_json::Value::Array(arr) => !arr.is_empty(),
362            serde_json::Value::Object(obj) => !obj.is_empty(),
363            serde_json::Value::Null => false,
364        })
365    }
366
367    /// 执行规则动作
368    pub fn execute_action<'a>(
369        &'a self,
370        action: &'a RuleAction,
371        context: &'a mut ScriptContext,
372    ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<RuleExecutionResult>> + Send + 'a>>
373    {
374        Box::pin(async move {
375            let start_time = std::time::Instant::now();
376            let mut variable_updates = HashMap::new();
377            let mut triggered_events = Vec::new();
378
379            let result = match action {
380                RuleAction::ReturnValue { value } => value.clone(),
381
382                RuleAction::ExecuteScript { script } => {
383                    let result = self.engine.execute(script, context).await?;
384                    if !result.success {
385                        return Ok(RuleExecutionResult {
386                            rule_id: String::new(),
387                            success: false,
388                            result: serde_json::Value::Null,
389                            error: result.error,
390                            execution_time_ms: start_time.elapsed().as_millis() as u64,
391                            variable_updates,
392                            triggered_events,
393                        });
394                    }
395                    result.value
396                }
397
398                RuleAction::CallFunction { function, args } => {
399                    // 简化处理:将函数调用转换为脚本
400                    let args_str = args
401                        .iter()
402                        .map(|a| a.to_string())
403                        .collect::<Vec<_>>()
404                        .join(", ");
405                    let script = format!("{}({})", function, args_str);
406                    let result = self.engine.execute(&script, context).await?;
407                    if !result.success {
408                        return Ok(RuleExecutionResult {
409                            rule_id: String::new(),
410                            success: false,
411                            result: serde_json::Value::Null,
412                            error: result.error,
413                            execution_time_ms: start_time.elapsed().as_millis() as u64,
414                            variable_updates,
415                            triggered_events,
416                        });
417                    }
418                    result.value
419                }
420
421                RuleAction::SetVariable { name, value } => {
422                    context.set_variable(name, value.clone())?;
423                    variable_updates.insert(name.clone(), value.clone());
424                    serde_json::json!({ "set": name, "value": value })
425                }
426
427                RuleAction::TriggerEvent { event_type, data } => {
428                    triggered_events.push((event_type.clone(), data.clone()));
429                    // 调用事件处理器
430                    let handlers = self.event_handlers.read().await;
431                    if let Some(handlers) = handlers.get(event_type) {
432                        for handler in handlers {
433                            handler(event_type, data);
434                        }
435                    }
436                    serde_json::json!({ "event": event_type, "data": data })
437                }
438
439                RuleAction::GotoRule { rule_id } => {
440                    // 返回特殊值表示跳转
441                    serde_json::json!({ "goto": rule_id })
442                }
443
444                RuleAction::Stop => {
445                    serde_json::json!({ "stop": true })
446                }
447
448                RuleAction::Composite { actions } => {
449                    // 对于复合动作,顺序执行所有子动作
450                    let mut results = Vec::new();
451                    for sub_action in actions {
452                        // 使用非递归方式处理
453                        let sub_result = self.execute_single_action(sub_action, context).await?;
454                        if !sub_result.success {
455                            return Ok(sub_result);
456                        }
457                        results.push(sub_result.result);
458                        variable_updates.extend(sub_result.variable_updates);
459                        triggered_events.extend(sub_result.triggered_events);
460                    }
461                    serde_json::json!(results)
462                }
463            };
464
465            Ok(RuleExecutionResult {
466                rule_id: String::new(),
467                success: true,
468                result,
469                error: None,
470                execution_time_ms: start_time.elapsed().as_millis() as u64,
471                variable_updates,
472                triggered_events,
473            })
474        })
475    }
476
477    /// 执行单个非复合动作(避免递归)
478    async fn execute_single_action(
479        &self,
480        action: &RuleAction,
481        context: &mut ScriptContext,
482    ) -> Result<RuleExecutionResult> {
483        let start_time = std::time::Instant::now();
484        let mut variable_updates = HashMap::new();
485        let mut triggered_events = Vec::new();
486
487        let result = match action {
488            RuleAction::ReturnValue { value } => value.clone(),
489
490            RuleAction::ExecuteScript { script } => {
491                let result = self.engine.execute(script, context).await?;
492                if !result.success {
493                    return Ok(RuleExecutionResult {
494                        rule_id: String::new(),
495                        success: false,
496                        result: serde_json::Value::Null,
497                        error: result.error,
498                        execution_time_ms: start_time.elapsed().as_millis() as u64,
499                        variable_updates,
500                        triggered_events,
501                    });
502                }
503                result.value
504            }
505
506            RuleAction::CallFunction { function, args } => {
507                let args_str = args
508                    .iter()
509                    .map(|a| a.to_string())
510                    .collect::<Vec<_>>()
511                    .join(", ");
512                let script = format!("{}({})", function, args_str);
513                let result = self.engine.execute(&script, context).await?;
514                if !result.success {
515                    return Ok(RuleExecutionResult {
516                        rule_id: String::new(),
517                        success: false,
518                        result: serde_json::Value::Null,
519                        error: result.error,
520                        execution_time_ms: start_time.elapsed().as_millis() as u64,
521                        variable_updates,
522                        triggered_events,
523                    });
524                }
525                result.value
526            }
527
528            RuleAction::SetVariable { name, value } => {
529                context.set_variable(name, value.clone())?;
530                variable_updates.insert(name.clone(), value.clone());
531                serde_json::json!({ "set": name, "value": value })
532            }
533
534            RuleAction::TriggerEvent { event_type, data } => {
535                triggered_events.push((event_type.clone(), data.clone()));
536                let handlers = self.event_handlers.read().await;
537                if let Some(handlers) = handlers.get(event_type) {
538                    for handler in handlers {
539                        handler(event_type, data);
540                    }
541                }
542                serde_json::json!({ "event": event_type, "data": data })
543            }
544
545            RuleAction::GotoRule { rule_id } => {
546                serde_json::json!({ "goto": rule_id })
547            }
548
549            RuleAction::Stop => {
550                serde_json::json!({ "stop": true })
551            }
552
553            RuleAction::Composite { .. } => {
554                // 复合动作在这里不递归处理,返回错误
555                return Err(anyhow!("Nested composite actions are not supported"));
556            }
557        };
558
559        Ok(RuleExecutionResult {
560            rule_id: String::new(),
561            success: true,
562            result,
563            error: None,
564            execution_time_ms: start_time.elapsed().as_millis() as u64,
565            variable_updates,
566            triggered_events,
567        })
568    }
569
570    /// 执行单个规则
571    pub async fn execute_rule(
572        &self,
573        rule_id: &str,
574        context: &mut ScriptContext,
575    ) -> Result<Option<RuleExecutionResult>> {
576        let rules = self.rules.read().await;
577        let rule = rules
578            .get(rule_id)
579            .ok_or_else(|| anyhow!("Rule not found: {}", rule_id))?
580            .clone();
581        drop(rules);
582
583        // 评估条件
584        if !self.evaluate_condition(&rule, context).await? {
585            return Ok(None);
586        }
587
588        // 执行动作
589        let mut result = self.execute_action(&rule.action, context).await?;
590        result.rule_id = rule_id.to_string();
591        Ok(Some(result))
592    }
593
594    /// 执行规则组
595    pub async fn execute_group(
596        &self,
597        group_id: &str,
598        context: &mut ScriptContext,
599    ) -> Result<RuleGroupExecutionResult> {
600        let start_time = std::time::Instant::now();
601
602        let groups = self.groups.read().await;
603        let group = groups
604            .get(group_id)
605            .ok_or_else(|| anyhow!("Rule group not found: {}", group_id))?
606            .clone();
607        drop(groups);
608
609        if !group.enabled {
610            return Ok(RuleGroupExecutionResult {
611                group_id: group_id.to_string(),
612                match_results: Vec::new(),
613                execution_results: Vec::new(),
614                final_result: None,
615                any_matched: false,
616                used_default: false,
617                total_time_ms: start_time.elapsed().as_millis() as u64,
618            });
619        }
620
621        // 获取规则并按优先级排序
622        let rules = self.rules.read().await;
623        let mut group_rules: Vec<_> = group
624            .rule_ids
625            .iter()
626            .filter_map(|id| rules.get(id).cloned())
627            .collect();
628        drop(rules);
629
630        // 按优先级排序(高优先级在前)
631        group_rules.sort_by(|a, b| b.priority.cmp(&a.priority));
632
633        let mut match_results = Vec::new();
634        let mut execution_results = Vec::new();
635        let mut any_matched = false;
636        let mut final_result = None;
637
638        for rule in group_rules {
639            let eval_start = std::time::Instant::now();
640            let matched = self.evaluate_condition(&rule, context).await?;
641
642            match_results.push(RuleMatchResult {
643                rule_id: rule.id.clone(),
644                matched,
645                evaluation_time_ms: eval_start.elapsed().as_millis() as u64,
646            });
647
648            if !matched {
649                continue;
650            }
651
652            any_matched = true;
653
654            // 执行动作
655            let mut result = self.execute_action(&rule.action, context).await?;
656            result.rule_id = rule.id.clone();
657
658            // 检查是否需要停止
659            let should_stop = if let Some(obj) = result.result.as_object() {
660                obj.contains_key("stop")
661            } else {
662                false
663            };
664
665            // 检查是否跳转
666            let goto_rule = if let Some(obj) = result.result.as_object() {
667                obj.get("goto")
668                    .and_then(|v| v.as_str())
669                    .map(|s| s.to_string())
670            } else {
671                None
672            };
673
674            final_result = Some(result.result.clone());
675            execution_results.push(result);
676
677            if should_stop {
678                break;
679            }
680
681            if let Some(target_rule_id) = goto_rule {
682                // 执行目标规则
683                if let Some(goto_result) = self.execute_rule(&target_rule_id, context).await? {
684                    final_result = Some(goto_result.result.clone());
685                    execution_results.push(goto_result);
686                }
687                break;
688            }
689
690            // 根据匹配模式决定是否继续
691            match group.match_mode {
692                RuleMatchMode::FirstMatch | RuleMatchMode::FirstSuccess => break,
693                RuleMatchMode::AllMatch | RuleMatchMode::AllMatchOrdered => continue,
694            }
695        }
696
697        // 如果没有匹配且有默认动作
698        let used_default = !any_matched && group.default_action.is_some();
699        if let Some(ref default_action) = group.default_action
700            && !any_matched
701        {
702            let mut result = self.execute_action(default_action, context).await?;
703            result.rule_id = format!("{}_default", group_id);
704            final_result = Some(result.result.clone());
705            execution_results.push(result);
706        }
707
708        Ok(RuleGroupExecutionResult {
709            group_id: group_id.to_string(),
710            match_results,
711            execution_results,
712            final_result,
713            any_matched,
714            used_default,
715            total_time_ms: start_time.elapsed().as_millis() as u64,
716        })
717    }
718
719    /// 执行所有匹配的规则
720    pub async fn execute_all(
721        &self,
722        context: &mut ScriptContext,
723    ) -> Result<Vec<RuleExecutionResult>> {
724        let rules = self.rules.read().await;
725        let mut all_rules: Vec<_> = rules.values().cloned().collect();
726        drop(rules);
727
728        // 按优先级排序
729        all_rules.sort_by(|a, b| b.priority.cmp(&a.priority));
730
731        let mut results = Vec::new();
732
733        for rule in all_rules {
734            if !rule.enabled {
735                continue;
736            }
737
738            if self.evaluate_condition(&rule, context).await? {
739                let mut result = self.execute_action(&rule.action, context).await?;
740                result.rule_id = rule.id.clone();
741                results.push(result);
742            }
743        }
744
745        Ok(results)
746    }
747
748    /// 获取规则
749    pub async fn get_rule(&self, rule_id: &str) -> Option<RuleDefinition> {
750        let rules = self.rules.read().await;
751        rules.get(rule_id).cloned()
752    }
753
754    /// 列出所有规则
755    pub async fn list_rules(&self) -> Vec<RuleDefinition> {
756        let rules = self.rules.read().await;
757        rules.values().cloned().collect()
758    }
759
760    /// 按标签过滤规则
761    pub async fn list_rules_by_tag(&self, tag: &str) -> Vec<RuleDefinition> {
762        let rules = self.rules.read().await;
763        rules
764            .values()
765            .filter(|r| r.tags.contains(&tag.to_string()))
766            .cloned()
767            .collect()
768    }
769
770    /// 移除规则
771    pub async fn unregister_rule(&self, rule_id: &str) -> bool {
772        let mut rules = self.rules.write().await;
773        rules.remove(rule_id).is_some()
774    }
775
776    /// 启用规则
777    pub async fn enable_rule(&self, rule_id: &str) -> Result<()> {
778        let mut rules = self.rules.write().await;
779        if let Some(rule) = rules.get_mut(rule_id) {
780            rule.enabled = true;
781            Ok(())
782        } else {
783            Err(anyhow!("Rule not found: {}", rule_id))
784        }
785    }
786
787    /// 禁用规则
788    pub async fn disable_rule(&self, rule_id: &str) -> Result<()> {
789        let mut rules = self.rules.write().await;
790        if let Some(rule) = rules.get_mut(rule_id) {
791            rule.enabled = false;
792            Ok(())
793        } else {
794            Err(anyhow!("Rule not found: {}", rule_id))
795        }
796    }
797
798    /// 规则数量
799    pub async fn rule_count(&self) -> usize {
800        let rules = self.rules.read().await;
801        rules.len()
802    }
803
804    /// 清空所有规则
805    pub async fn clear(&self) {
806        let mut rules = self.rules.write().await;
807        let mut groups = self.groups.write().await;
808        rules.clear();
809        groups.clear();
810    }
811}
812
813// ============================================================================
814// 便捷构建器
815// ============================================================================
816
817/// 规则构建器
818pub struct RuleBuilder {
819    rule: RuleDefinition,
820}
821
822impl RuleBuilder {
823    pub fn new(id: &str, name: &str) -> Self {
824        Self {
825            rule: RuleDefinition {
826                id: id.to_string(),
827                name: name.to_string(),
828                description: String::new(),
829                priority: RulePriority::Normal,
830                enabled: true,
831                condition: "true".to_string(),
832                action: RuleAction::Stop,
833                tags: Vec::new(),
834                metadata: HashMap::new(),
835            },
836        }
837    }
838
839    pub fn description(mut self, desc: &str) -> Self {
840        self.rule.description = desc.to_string();
841        self
842    }
843
844    pub fn priority(mut self, priority: RulePriority) -> Self {
845        self.rule.priority = priority;
846        self
847    }
848
849    pub fn condition(mut self, condition: &str) -> Self {
850        self.rule.condition = condition.to_string();
851        self
852    }
853
854    pub fn when_true(mut self, condition: &str) -> Self {
855        self.rule.condition = condition.to_string();
856        self
857    }
858
859    pub fn then_return(mut self, value: serde_json::Value) -> Self {
860        self.rule.action = RuleAction::ReturnValue { value };
861        self
862    }
863
864    pub fn then_execute(mut self, script: &str) -> Self {
865        self.rule.action = RuleAction::ExecuteScript {
866            script: script.to_string(),
867        };
868        self
869    }
870
871    pub fn then_set(mut self, name: &str, value: serde_json::Value) -> Self {
872        self.rule.action = RuleAction::SetVariable {
873            name: name.to_string(),
874            value,
875        };
876        self
877    }
878
879    pub fn then_trigger(mut self, event_type: &str, data: serde_json::Value) -> Self {
880        self.rule.action = RuleAction::TriggerEvent {
881            event_type: event_type.to_string(),
882            data,
883        };
884        self
885    }
886
887    pub fn then_goto(mut self, rule_id: &str) -> Self {
888        self.rule.action = RuleAction::GotoRule {
889            rule_id: rule_id.to_string(),
890        };
891        self
892    }
893
894    pub fn then_stop(mut self) -> Self {
895        self.rule.action = RuleAction::Stop;
896        self
897    }
898
899    pub fn action(mut self, action: RuleAction) -> Self {
900        self.rule.action = action;
901        self
902    }
903
904    pub fn tag(mut self, tag: &str) -> Self {
905        self.rule.tags.push(tag.to_string());
906        self
907    }
908
909    pub fn disabled(mut self) -> Self {
910        self.rule.enabled = false;
911        self
912    }
913
914    pub fn build(self) -> RuleDefinition {
915        self.rule
916    }
917}
918
919// ============================================================================
920// 测试
921// ============================================================================
922
923#[cfg(test)]
924mod tests {
925    use super::*;
926
927    #[tokio::test]
928    async fn test_rule_registration() {
929        let engine = RuleEngine::new(ScriptEngineConfig::default()).unwrap();
930
931        let rule = RuleBuilder::new("test_rule", "Test Rule")
932            .condition("value > 10")
933            .then_return(serde_json::json!("high"))
934            .build();
935
936        engine.register_rule(rule).await.unwrap();
937
938        assert_eq!(engine.rule_count().await, 1);
939    }
940
941    #[tokio::test]
942    async fn test_rule_execution() {
943        let engine = RuleEngine::new(ScriptEngineConfig::default()).unwrap();
944
945        let rule = RuleBuilder::new("check_value", "Check Value")
946            .condition("value > 100")
947            .then_execute(r#"value * 2"#)
948            .build();
949
950        engine.register_rule(rule).await.unwrap();
951
952        let mut context = ScriptContext::new().with_variable("value", 150).unwrap();
953
954        let result = engine
955            .execute_rule("check_value", &mut context)
956            .await
957            .unwrap();
958
959        assert!(result.is_some());
960        let result = result.unwrap();
961        assert!(result.success);
962        assert_eq!(result.result, serde_json::json!(300));
963    }
964
965    #[tokio::test]
966    async fn test_rule_condition_not_met() {
967        let engine = RuleEngine::new(ScriptEngineConfig::default()).unwrap();
968
969        let rule = RuleBuilder::new("check_value", "Check Value")
970            .condition("value > 100")
971            .then_return(serde_json::json!("high"))
972            .build();
973
974        engine.register_rule(rule).await.unwrap();
975
976        let mut context = ScriptContext::new().with_variable("value", 50).unwrap();
977
978        let result = engine
979            .execute_rule("check_value", &mut context)
980            .await
981            .unwrap();
982
983        assert!(result.is_none());
984    }
985
986    #[tokio::test]
987    async fn test_rule_group_first_match() {
988        let engine = RuleEngine::new(ScriptEngineConfig::default()).unwrap();
989
990        // 注册多个规则
991        let rules = vec![
992            RuleBuilder::new("rule_high", "High Value")
993                .priority(RulePriority::High)
994                .condition("value > 100")
995                .then_return(serde_json::json!("high"))
996                .build(),
997            RuleBuilder::new("rule_medium", "Medium Value")
998                .priority(RulePriority::Normal)
999                .condition("value > 50")
1000                .then_return(serde_json::json!("medium"))
1001                .build(),
1002            RuleBuilder::new("rule_low", "Low Value")
1003                .priority(RulePriority::Low)
1004                .condition("value > 0")
1005                .then_return(serde_json::json!("low"))
1006                .build(),
1007        ];
1008
1009        engine.register_rules(rules).await.unwrap();
1010
1011        // 创建规则组
1012        let group = RuleGroupDefinition::new("value_checker", "Value Checker")
1013            .with_match_mode(RuleMatchMode::FirstMatch)
1014            .with_rules(vec!["rule_high", "rule_medium", "rule_low"]);
1015
1016        engine.register_group(group).await.unwrap();
1017
1018        // 测试高值
1019        let mut context = ScriptContext::new().with_variable("value", 150).unwrap();
1020        let result = engine
1021            .execute_group("value_checker", &mut context)
1022            .await
1023            .unwrap();
1024
1025        assert!(result.any_matched);
1026        assert_eq!(result.execution_results.len(), 1);
1027        assert_eq!(result.final_result, Some(serde_json::json!("high")));
1028
1029        // 测试中值
1030        let mut context = ScriptContext::new().with_variable("value", 75).unwrap();
1031        let result = engine
1032            .execute_group("value_checker", &mut context)
1033            .await
1034            .unwrap();
1035
1036        assert!(result.any_matched);
1037        assert_eq!(result.final_result, Some(serde_json::json!("medium")));
1038    }
1039
1040    #[tokio::test]
1041    async fn test_rule_with_default_action() {
1042        let engine = RuleEngine::new(ScriptEngineConfig::default()).unwrap();
1043
1044        let rule = RuleBuilder::new("positive_rule", "Positive Only")
1045            .condition("value > 0")
1046            .then_return(serde_json::json!("positive"))
1047            .build();
1048
1049        engine.register_rule(rule).await.unwrap();
1050
1051        let group = RuleGroupDefinition::new("number_group", "Number Group")
1052            .with_rules(vec!["positive_rule"])
1053            .with_default_action(RuleAction::ReturnValue {
1054                value: serde_json::json!("non_positive"),
1055            });
1056
1057        engine.register_group(group).await.unwrap();
1058
1059        // 测试负值,应该使用默认动作
1060        let mut context = ScriptContext::new().with_variable("value", -10).unwrap();
1061        let result = engine
1062            .execute_group("number_group", &mut context)
1063            .await
1064            .unwrap();
1065
1066        assert!(!result.any_matched);
1067        assert!(result.used_default);
1068        assert_eq!(result.final_result, Some(serde_json::json!("non_positive")));
1069    }
1070
1071    #[tokio::test]
1072    async fn test_set_variable_action() {
1073        let engine = RuleEngine::new(ScriptEngineConfig::default()).unwrap();
1074
1075        let rule = RuleBuilder::new("set_status", "Set Status")
1076            .condition("true")
1077            .then_set("status", serde_json::json!("processed"))
1078            .build();
1079
1080        engine.register_rule(rule).await.unwrap();
1081
1082        let mut context = ScriptContext::new();
1083        let result = engine
1084            .execute_rule("set_status", &mut context)
1085            .await
1086            .unwrap()
1087            .unwrap();
1088
1089        assert!(result.success);
1090        assert!(result.variable_updates.contains_key("status"));
1091        assert_eq!(
1092            context.get_variable::<String>("status"),
1093            Some("processed".to_string())
1094        );
1095    }
1096
1097    #[test]
1098    fn test_rule_builder() {
1099        let rule = RuleBuilder::new("my_rule", "My Rule")
1100            .description("A test rule")
1101            .priority(RulePriority::High)
1102            .condition("x > 10")
1103            .then_return(serde_json::json!({"result": "success"}))
1104            .tag("test")
1105            .build();
1106
1107        assert_eq!(rule.id, "my_rule");
1108        assert_eq!(rule.priority, RulePriority::High);
1109        assert_eq!(rule.condition, "x > 10");
1110        assert!(rule.tags.contains(&"test".to_string()));
1111    }
1112}