2026-06-24 f4bd1f3c89d906131495a0aca5aaf82966378510
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package cn.iocoder.yudao.module.iot.service.rule.scene.matcher;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum;
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotSceneRuleConditionMatcher;
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.trigger.IotSceneRuleTriggerMatcher;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
 
import java.util.*;
import java.util.function.Function;
 
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 
/**
 * IoT 场景规则匹配器统一管理器:负责管理所有匹配器(触发器匹配器和条件匹配器),并提供统一的匹配入口
 *
 * @author HUIHUI
 */
@Component
@Slf4j
public class IotSceneRuleMatcherManager {
 
    /**
     * 触发器匹配器映射表
     */
    private final Map<IotSceneRuleTriggerTypeEnum, IotSceneRuleTriggerMatcher> triggerMatchers;
 
    /**
     * 条件匹配器映射表
     */
    private final Map<IotSceneRuleConditionTypeEnum, IotSceneRuleConditionMatcher> conditionMatchers;
 
    public IotSceneRuleMatcherManager(List<IotSceneRuleMatcher> matchers) {
        if (CollUtil.isEmpty(matchers)) {
            log.warn("[IotSceneRuleMatcherManager][没有找到任何匹配器]");
            this.triggerMatchers = new HashMap<>();
            this.conditionMatchers = new HashMap<>();
            return;
        }
 
        // 1.1 按优先级排序并过滤启用的匹配器
        List<IotSceneRuleMatcher> allMatchers = matchers.stream()
                .filter(IotSceneRuleMatcher::isEnabled)
                .sorted(Comparator.comparing(IotSceneRuleMatcher::getPriority))
                .toList();
        // 1.2 分离触发器匹配器和条件匹配器
        List<IotSceneRuleTriggerMatcher> triggerMatchers = allMatchers.stream()
                .filter(matcher -> matcher instanceof IotSceneRuleTriggerMatcher)
                .map(matcher -> (IotSceneRuleTriggerMatcher) matcher)
                .toList();
        List<IotSceneRuleConditionMatcher> conditionMatchers = allMatchers.stream()
                .filter(matcher -> matcher instanceof IotSceneRuleConditionMatcher)
                .map(matcher -> (IotSceneRuleConditionMatcher) matcher)
                .toList();
 
        // 2.1 构建触发器匹配器映射表
        this.triggerMatchers = convertMap(triggerMatchers, IotSceneRuleTriggerMatcher::getSupportedTriggerType,
                Function.identity(),
                (existing, replacement) -> {
                    log.warn("[IotSceneRuleMatcherManager][触发器类型({})存在多个匹配器,使用优先级更高的: {}]",
                            existing.getSupportedTriggerType(),
                            existing.getPriority() <= replacement.getPriority() ?
                                    existing.getSupportedTriggerType() : replacement.getSupportedTriggerType());
                    return existing.getPriority() <= replacement.getPriority() ? existing : replacement;
                }, LinkedHashMap::new);
        // 2.2 构建条件匹配器映射表
        this.conditionMatchers = convertMap(conditionMatchers, IotSceneRuleConditionMatcher::getSupportedConditionType,
                Function.identity(),
                (existing, replacement) -> {
                    log.warn("[IotSceneRuleMatcherManager][条件类型({})存在多个匹配器,使用优先级更高的: {}]",
                            existing.getSupportedConditionType(),
                            existing.getPriority() <= replacement.getPriority() ?
                                    existing.getSupportedConditionType() : replacement.getSupportedConditionType());
                    return existing.getPriority() <= replacement.getPriority() ? existing : replacement;
                },
                LinkedHashMap::new);
 
        // 3. 日志输出初始化信息
        log.info("[IotSceneRuleMatcherManager][初始化完成,共加载({})个匹配器,其中触发器匹配器({})个,条件匹配器({})个]",
                allMatchers.size(), this.triggerMatchers.size(), this.conditionMatchers.size());
        this.triggerMatchers.forEach((type, matcher) ->
                log.info("[IotSceneRuleMatcherManager][触发器匹配器类型: ({}), 优先级: ({})] ", type, matcher.getPriority()));
        this.conditionMatchers.forEach((type, matcher) ->
                log.info("[IotSceneRuleMatcherManager][条件匹配器类型: ({}), 优先级: ({})]", type, matcher.getPriority()));
    }
 
    /**
     * 检查触发器是否匹配消息(主条件匹配)
     *
     * @param message 设备消息
     * @param trigger 触发器配置
     * @return 是否匹配
     */
    public boolean isMatched(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
        if (message == null || trigger == null || trigger.getType() == null) {
            log.debug("[isMatched][message({}) trigger({}) 参数无效]", message, trigger);
            return false;
        }
        IotSceneRuleTriggerTypeEnum triggerType = IotSceneRuleTriggerTypeEnum.typeOf(trigger.getType());
        if (triggerType == null) {
            log.warn("[isMatched][triggerType({}) 未知的触发器类型]", trigger.getType());
            return false;
        }
        IotSceneRuleTriggerMatcher matcher = triggerMatchers.get(triggerType);
        if (matcher == null) {
            log.warn("[isMatched][triggerType({}) 没有对应的匹配器]", triggerType);
            return false;
        }
 
        try {
            return matcher.matches(message, trigger);
        } catch (Exception e) {
            log.error("[isMatched][触发器匹配异常] message: {}, trigger: {}", message, trigger, e);
            return false;
        }
    }
 
    /**
     * 检查子条件是否匹配消息
     *
     * @param message   设备消息
     * @param condition 触发条件
     * @return 是否匹配
     */
    public boolean isConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) {
        if (message == null || condition == null || condition.getType() == null) {
            log.debug("[isConditionMatched][message({}) condition({}) 参数无效]", message, condition);
            return false;
        }
 
        // 1. 根据条件类型查找对应的匹配器
        IotSceneRuleConditionTypeEnum conditionType = IotSceneRuleConditionTypeEnum.typeOf(condition.getType());
        if (conditionType == null) {
            log.warn("[isConditionMatched][conditionType({}) 未知的条件类型]", condition.getType());
            return false;
        }
        IotSceneRuleConditionMatcher matcher = conditionMatchers.get(conditionType);
        if (matcher == null) {
            log.warn("[isConditionMatched][conditionType({}) 没有对应的匹配器]", conditionType);
            return false;
        }
 
        // 2. 执行匹配逻辑
        try {
            return matcher.matches(message, condition);
        } catch (Exception e) {
            log.error("[isConditionMatched][message({}) condition({}) 条件匹配异常]", message, condition, e);
            return false;
        }
    }
 
}