mirror of
https://github.com/YunaiV/ruoyi-vue-pro.git
synced 2026-03-30 01:52:14 +00:00
review(iot):【场景联动】增加相关的 review 说明
This commit is contained in:
@@ -97,6 +97,7 @@ public class IotWebSocketDataRuleAction extends
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @puhui999:为什么这里要加锁呀?
|
||||
/**
|
||||
* 使用锁进行重连,保证同一服务器地址的重连操作线程安全
|
||||
*
|
||||
|
||||
@@ -67,7 +67,6 @@ public class IotWebSocketClient {
|
||||
// 使用 CountDownLatch 等待连接完成
|
||||
CountDownLatch connectLatch = new CountDownLatch(1);
|
||||
AtomicBoolean connectSuccess = new AtomicBoolean(false);
|
||||
|
||||
// 创建 WebSocket 连接
|
||||
webSocket = okHttpClient.newWebSocket(request, new IotWebSocketListener(connectLatch, connectSuccess));
|
||||
|
||||
@@ -77,7 +76,6 @@ public class IotWebSocketClient {
|
||||
close();
|
||||
throw new Exception("WebSocket 连接超时或失败,服务器地址: " + serverUrl);
|
||||
}
|
||||
|
||||
log.info("[connect][WebSocket 客户端连接成功,服务器地址: {}]", serverUrl);
|
||||
} catch (Exception e) {
|
||||
close();
|
||||
@@ -126,6 +124,7 @@ public class IotWebSocketClient {
|
||||
try {
|
||||
if (webSocket != null) {
|
||||
// 发送正常关闭帧,状态码 1000 表示正常关闭
|
||||
// TODO @puhui999:有没 1000 的枚举哈?在 okhttp 里
|
||||
webSocket.close(1000, "客户端主动关闭");
|
||||
webSocket = null;
|
||||
}
|
||||
@@ -163,6 +162,7 @@ public class IotWebSocketClient {
|
||||
/**
|
||||
* OkHttp WebSocket 监听器
|
||||
*/
|
||||
@SuppressWarnings("NullableProblems")
|
||||
private class IotWebSocketListener extends WebSocketListener {
|
||||
|
||||
private final CountDownLatch connectLatch;
|
||||
|
||||
@@ -4,6 +4,8 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.text.CharPool;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
|
||||
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher;
|
||||
import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -15,8 +17,7 @@ import java.util.List;
|
||||
/**
|
||||
* IoT 场景规则时间匹配工具类
|
||||
* <p>
|
||||
* 提供时间条件匹配的通用方法,供 {@link cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher}
|
||||
* 和 {@link cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator} 共同使用。
|
||||
* 提供时间条件匹配的通用方法,供 {@link IotCurrentTimeConditionMatcher} 和 {@link IotTimerConditionEvaluator} 共同使用。
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@@ -33,6 +34,7 @@ public class IotSceneRuleTimeHelper {
|
||||
*/
|
||||
private static final DateTimeFormatter TIME_FORMATTER_SHORT = DateTimeFormatter.ofPattern("HH:mm");
|
||||
|
||||
// TODO @puhui999:可以使用 lombok 简化
|
||||
private IotSceneRuleTimeHelper() {
|
||||
// 工具类,禁止实例化
|
||||
}
|
||||
@@ -94,6 +96,7 @@ public class IotSceneRuleTimeHelper {
|
||||
* @param param 参数值
|
||||
* @return 是否匹配
|
||||
*/
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
public static boolean matchDateTime(long currentTimestamp, IotSceneRuleConditionOperatorEnum operatorEnum,
|
||||
String param) {
|
||||
try {
|
||||
@@ -133,6 +136,7 @@ public class IotSceneRuleTimeHelper {
|
||||
}
|
||||
long startTimestamp = Long.parseLong(timestampRange.get(0).trim());
|
||||
long endTimestamp = Long.parseLong(timestampRange.get(1).trim());
|
||||
// TODO @puhui999:hutool 里,看看有没 between 方法
|
||||
return currentTimestamp >= startTimestamp && currentTimestamp <= endTimestamp;
|
||||
}
|
||||
|
||||
@@ -144,6 +148,7 @@ public class IotSceneRuleTimeHelper {
|
||||
* @param param 参数值
|
||||
* @return 是否匹配
|
||||
*/
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
public static boolean matchTime(LocalTime currentTime, IotSceneRuleConditionOperatorEnum operatorEnum,
|
||||
String param) {
|
||||
try {
|
||||
@@ -183,6 +188,7 @@ public class IotSceneRuleTimeHelper {
|
||||
}
|
||||
LocalTime startTime = parseTime(timeRange.get(0).trim());
|
||||
LocalTime endTime = parseTime(timeRange.get(1).trim());
|
||||
// TODO @puhui999:hutool 里,看看有没 between 方法
|
||||
return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,11 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger
|
||||
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "触发器基础参数无效");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.2 检查消息方法是否匹配
|
||||
if (!IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod().equals(message.getMethod())) {
|
||||
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "消息方法不匹配,期望: " + IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod() + ", 实际: " + message.getMethod());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1.3 检查标识符是否匹配
|
||||
String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message);
|
||||
if (!IotSceneRuleMatcherHelper.isIdentifierMatched(trigger.getIdentifier(), messageIdentifier)) {
|
||||
@@ -73,21 +71,21 @@ public class IotDeviceServiceInvokeTriggerMatcher implements IotSceneRuleTrigger
|
||||
* @return 是否匹配
|
||||
*/
|
||||
private boolean matchParameterCondition(IotDeviceMessage message, IotSceneRuleDO.Trigger trigger) {
|
||||
// 从消息中提取服务调用的输入参数
|
||||
// 1.1 从消息中提取服务调用的输入参数
|
||||
Map<String, Object> inputParams = IotDeviceMessageUtils.extractServiceInputParams(message);
|
||||
// TODO @puhui999:要考虑 empty 的情况么?
|
||||
if (inputParams == null) {
|
||||
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "消息中缺少服务输入参数");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取要匹配的参数值(使用 identifier 作为参数名)
|
||||
// 1.2 获取要匹配的参数值(使用 identifier 作为参数名)
|
||||
Object paramValue = inputParams.get(trigger.getIdentifier());
|
||||
if (paramValue == null) {
|
||||
IotSceneRuleMatcherHelper.logTriggerMatchFailure(message, trigger, "服务输入参数中缺少指定参数: " + trigger.getIdentifier());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 使用条件评估器进行匹配
|
||||
// 2. 使用条件评估器进行匹配
|
||||
boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(paramValue, trigger.getOperator(), trigger.getValue());
|
||||
if (matched) {
|
||||
IotSceneRuleMatcherHelper.logTriggerMatchSuccess(message, trigger);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.iot.service.rule.scene.timer;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
|
||||
@@ -40,14 +41,14 @@ public class IotTimerConditionEvaluator {
|
||||
* @param condition 条件配置
|
||||
* @return 是否满足条件
|
||||
*/
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
public boolean evaluate(IotSceneRuleDO.TriggerCondition condition) {
|
||||
// 1. 基础参数校验
|
||||
// 1.1 基础参数校验
|
||||
if (condition == null || condition.getType() == null) {
|
||||
log.warn("[evaluate][条件为空或类型为空]");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 根据条件类型分发到具体的评估方法
|
||||
// 1.2 根据条件类型分发到具体的评估方法
|
||||
IotSceneRuleConditionTypeEnum conditionType =
|
||||
IotSceneRuleConditionTypeEnum.typeOf(condition.getType());
|
||||
if (conditionType == null) {
|
||||
@@ -55,6 +56,7 @@ public class IotTimerConditionEvaluator {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 分发评估
|
||||
switch (conditionType) {
|
||||
case DEVICE_PROPERTY:
|
||||
return evaluateDevicePropertyCondition(condition);
|
||||
@@ -89,15 +91,14 @@ public class IotTimerConditionEvaluator {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 获取设备最新属性值
|
||||
// 2.1 获取设备最新属性值
|
||||
Map<String, IotDevicePropertyDO> properties =
|
||||
devicePropertyService.getLatestDeviceProperties(condition.getDeviceId());
|
||||
if (properties == null || properties.isEmpty()) {
|
||||
if (CollUtil.isEmpty(properties)) {
|
||||
log.debug("[evaluateDevicePropertyCondition][设备({}) 无属性数据]", condition.getDeviceId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 获取指定属性
|
||||
// 2.2 获取指定属性
|
||||
IotDevicePropertyDO property = properties.get(condition.getIdentifier());
|
||||
if (property == null || property.getValue() == null) {
|
||||
log.debug("[evaluateDevicePropertyCondition][设备({}) 属性({}) 不存在或值为空]",
|
||||
@@ -105,7 +106,7 @@ public class IotTimerConditionEvaluator {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 使用现有的条件评估逻辑进行比较
|
||||
// 3. 使用现有的条件评估逻辑进行比较
|
||||
boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(
|
||||
property.getValue(), condition.getOperator(), condition.getParam());
|
||||
log.debug("[evaluateDevicePropertyCondition][设备({}) 属性({}) 值({}) 操作符({}) 参数({}) 匹配结果: {}]",
|
||||
@@ -131,21 +132,20 @@ public class IotTimerConditionEvaluator {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 获取设备信息
|
||||
// 2.1 获取设备信息
|
||||
IotDeviceDO device = deviceService.getDevice(condition.getDeviceId());
|
||||
if (device == null) {
|
||||
log.debug("[evaluateDeviceStateCondition][设备({}) 不存在]", condition.getDeviceId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 获取设备状态
|
||||
// 2.2 获取设备状态
|
||||
Integer state = device.getState();
|
||||
if (state == null) {
|
||||
log.debug("[evaluateDeviceStateCondition][设备({}) 状态为空]", condition.getDeviceId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 比较状态
|
||||
// 3. 比较状态
|
||||
boolean matched = IotSceneRuleMatcherHelper.evaluateCondition(
|
||||
state.toString(), condition.getOperator(), condition.getParam());
|
||||
log.debug("[evaluateDeviceStateCondition][设备({}) 状态({}) 操作符({}) 参数({}) 匹配结果: {}]",
|
||||
@@ -160,26 +160,24 @@ public class IotTimerConditionEvaluator {
|
||||
* @return 是否满足条件
|
||||
*/
|
||||
private boolean evaluateCurrentTimeCondition(IotSceneRuleDO.TriggerCondition condition) {
|
||||
// 1. 校验必要参数
|
||||
// 1.1 校验必要参数
|
||||
if (!IotSceneRuleMatcherHelper.isConditionOperatorAndParamValid(condition)) {
|
||||
log.debug("[evaluateCurrentTimeCondition][操作符或参数无效]");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 验证操作符是否为支持的时间操作符
|
||||
// 1.2 验证操作符是否为支持的时间操作符
|
||||
IotSceneRuleConditionOperatorEnum operatorEnum =
|
||||
IotSceneRuleConditionOperatorEnum.operatorOf(condition.getOperator());
|
||||
if (operatorEnum == null) {
|
||||
log.debug("[evaluateCurrentTimeCondition][无效的操作符: {}]", condition.getOperator());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IotSceneRuleTimeHelper.isTimeOperator(operatorEnum)) {
|
||||
log.debug("[evaluateCurrentTimeCondition][不支持的时间操作符: {}]", condition.getOperator());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 执行时间匹配
|
||||
// 2. 执行时间匹配
|
||||
boolean matched = IotSceneRuleTimeHelper.executeTimeMatching(operatorEnum, condition.getParam());
|
||||
log.debug("[evaluateCurrentTimeCondition][操作符({}) 参数({}) 匹配结果: {}]",
|
||||
condition.getOperator(), condition.getParam(), matched);
|
||||
|
||||
@@ -72,7 +72,7 @@ public class IotDeviceMessageUtils {
|
||||
|
||||
/**
|
||||
* 判断消息中是否包含指定的标识符
|
||||
*
|
||||
* <p>
|
||||
* 对于不同消息类型的处理:
|
||||
* - EVENT_POST/SERVICE_INVOKE:检查 params.identifier 是否匹配
|
||||
* - STATE_UPDATE:检查 params.state 是否匹配
|
||||
@@ -212,8 +212,8 @@ public class IotDeviceMessageUtils {
|
||||
* <p>
|
||||
* 服务调用消息的 params 结构通常为:
|
||||
* {
|
||||
* "identifier": "serviceIdentifier",
|
||||
* "inputData": { ... } 或 "inputParams": { ... }
|
||||
* "identifier": "serviceIdentifier",
|
||||
* "inputData": { ... } 或 "inputParams": { ... }
|
||||
* }
|
||||
*
|
||||
* @param message 设备消息
|
||||
@@ -221,6 +221,7 @@ public class IotDeviceMessageUtils {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, Object> extractServiceInputParams(IotDeviceMessage message) {
|
||||
// 1. 参数校验
|
||||
Object params = message.getParams();
|
||||
if (params == null) {
|
||||
return null;
|
||||
@@ -235,13 +236,11 @@ public class IotDeviceMessageUtils {
|
||||
if (inputData instanceof Map) {
|
||||
return (Map<String, Object>) inputData;
|
||||
}
|
||||
|
||||
// 尝试从 inputParams 字段获取
|
||||
Object inputParams = paramsMap.get("inputParams");
|
||||
if (inputParams instanceof Map) {
|
||||
return (Map<String, Object>) inputParams;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user