Commit e650e75271cf241721f19014dadb22b3b51e24f0

Authored by YunaiV
1 parent 30ae986c

【代码优化】IoT:设备上行时,增加 processId,用于设备与插件的映射

Showing 25 changed files with 277 additions and 190 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java
@@ -21,9 +21,9 @@ public abstract class IotDeviceUpstreamAbstractReqDTO { @@ -21,9 +21,9 @@ public abstract class IotDeviceUpstreamAbstractReqDTO {
21 private String requestId; 21 private String requestId;
22 22
23 /** 23 /**
24 - * 插件标识 24 + * 插件实例的进程编号
25 */ 25 */
26 - private String pluginKey; 26 + private String processId;
27 27
28 /** 28 /**
29 * 产品标识 29 * 产品标识
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInfoController.java
@@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoImp @@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoImp
7 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; 7 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO;
8 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoRespVO; 8 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoRespVO;
9 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO; 9 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO;
10 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO;  
11 -import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; 10 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
  11 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService;
12 import io.swagger.v3.oas.annotations.Operation; 12 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.Parameter; 13 import io.swagger.v3.oas.annotations.Parameter;
14 import io.swagger.v3.oas.annotations.tags.Tag; 14 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -27,7 +27,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -27,7 +27,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 public class PluginInfoController { 27 public class PluginInfoController {
28 28
29 @Resource 29 @Resource
30 - private PluginInfoService pluginInfoService; 30 + private IotPluginInfoService pluginInfoService;
31 31
32 @PostMapping("/create") 32 @PostMapping("/create")
33 @Operation(summary = "创建插件信息") 33 @Operation(summary = "创建插件信息")
@@ -58,7 +58,7 @@ public class PluginInfoController { @@ -58,7 +58,7 @@ public class PluginInfoController {
58 @Parameter(name = "id", description = "编号", required = true, example = "1024") 58 @Parameter(name = "id", description = "编号", required = true, example = "1024")
59 @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") 59 @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')")
60 public CommonResult<PluginInfoRespVO> getPluginInfo(@RequestParam("id") Long id) { 60 public CommonResult<PluginInfoRespVO> getPluginInfo(@RequestParam("id") Long id) {
61 - PluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id); 61 + IotPluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id);
62 return success(BeanUtils.toBean(pluginInfo, PluginInfoRespVO.class)); 62 return success(BeanUtils.toBean(pluginInfo, PluginInfoRespVO.class));
63 } 63 }
64 64
@@ -66,7 +66,7 @@ public class PluginInfoController { @@ -66,7 +66,7 @@ public class PluginInfoController {
66 @Operation(summary = "获得插件信息分页") 66 @Operation(summary = "获得插件信息分页")
67 @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") 67 @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')")
68 public CommonResult<PageResult<PluginInfoRespVO>> getPluginInfoPage(@Valid PluginInfoPageReqVO pageReqVO) { 68 public CommonResult<PageResult<PluginInfoRespVO>> getPluginInfoPage(@Valid PluginInfoPageReqVO pageReqVO) {
69 - PageResult<PluginInfoDO> pageResult = pluginInfoService.getPluginInfoPage(pageReqVO); 69 + PageResult<IotPluginInfoDO> pageResult = pluginInfoService.getPluginInfoPage(pageReqVO);
70 return success(BeanUtils.toBean(pageResult, PluginInfoRespVO.class)); 70 return success(BeanUtils.toBean(pageResult, PluginInfoRespVO.class));
71 } 71 }
72 72
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/PluginInfoDO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInfoDO.java
@@ -22,7 +22,7 @@ import lombok.*; @@ -22,7 +22,7 @@ import lombok.*;
22 @Builder 22 @Builder
23 @NoArgsConstructor 23 @NoArgsConstructor
24 @AllArgsConstructor 24 @AllArgsConstructor
25 -public class PluginInfoDO extends BaseDO { 25 +public class IotPluginInfoDO extends BaseDO {
26 26
27 /** 27 /**
28 * 主键 ID 28 * 主键 ID
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/PluginInstanceDO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugin/IotPluginInstanceDO.java
@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId; @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 6 import com.baomidou.mybatisplus.annotation.TableName;
7 import lombok.*; 7 import lombok.*;
8 8
  9 +import java.time.LocalDateTime;
9 10
10 /** 11 /**
11 * IoT 插件实例 DO 12 * IoT 插件实例 DO
@@ -20,40 +21,52 @@ import lombok.*; @@ -20,40 +21,52 @@ import lombok.*;
20 @Builder 21 @Builder
21 @NoArgsConstructor 22 @NoArgsConstructor
22 @AllArgsConstructor 23 @AllArgsConstructor
23 -public class PluginInstanceDO extends BaseDO { 24 +public class IotPluginInstanceDO extends BaseDO {
24 25
25 /** 26 /**
26 - * 主键ID 27 + * 主键
27 */ 28 */
28 @TableId 29 @TableId
29 private Long id; 30 private Long id;
30 - // TODO @芋艿:找一个更好的字段名  
31 /** 31 /**
32 - * 插件主程序 ID  
33 - */  
34 - private String mainId;  
35 - /**  
36 - * 插件 ID 32 + * 插件编号
37 * <p> 33 * <p>
38 - * 关联 {@link PluginInfoDO#getId()} 34 + * 关联 {@link IotPluginInfoDO#getId()}
39 */ 35 */
40 private Long pluginId; 36 private Long pluginId;
  37 + /**
  38 + * 插件进程编号
  39 + *
  40 + * 一般格式是:hostIp@processId@${uuid}
  41 + */
  42 + private String processId;
41 43
42 /** 44 /**
43 - * 插件主程序所在 IP 45 + * 插件实例所在 IP
44 */ 46 */
45 - private String ip;  
46 - // TODO @芋艿:这个 port 是否有必要记录 47 + private String hostIp;
47 /** 48 /**
48 - * 插件主程序端口 49 + * 设备下行端口
49 */ 50 */
50 - private Integer port;  
51 - // TODO @芋艿:downstreamPort 增加,目的:用于下行 51 + private Integer downstreamPort;
52 52
53 - // TODO @haohao:字段改成 heartbeatTime,LocalDateTime  
54 /** 53 /**
55 - * 心跳时间,心路时间超过 30 秒需要剔除 54 + * 是否在线
  55 + */
  56 + private Boolean online;
  57 + /**
  58 + * 在线时间
  59 + */
  60 + private LocalDateTime onlineTime;
  61 + /**
  62 + * 离线时间
  63 + */
  64 + private LocalDateTime offlineTime;
  65 + /**
  66 + * 心跳时间
  67 + *
  68 + * 目的:心路时间超过一定时间后,会被进行下线处理
56 */ 69 */
57 - private Long heartbeatAt; 70 + private Long heartbeatTime;
58 71
59 } 72 }
60 \ No newline at end of file 73 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInfoMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +@Mapper
  13 +public interface IotPluginInfoMapper extends BaseMapperX<IotPluginInfoDO> {
  14 +
  15 + default PageResult<IotPluginInfoDO> selectPage(PluginInfoPageReqVO reqVO) {
  16 + return selectPage(reqVO, new LambdaQueryWrapperX<IotPluginInfoDO>()
  17 + .likeIfPresent(IotPluginInfoDO::getName, reqVO.getName())
  18 + .eqIfPresent(IotPluginInfoDO::getStatus, reqVO.getStatus())
  19 + .orderByDesc(IotPluginInfoDO::getId));
  20 + }
  21 +
  22 + default List<IotPluginInfoDO> selectListByStatus(Integer status) {
  23 + return selectList(new LambdaQueryWrapperX<IotPluginInfoDO>()
  24 + .eq(IotPluginInfoDO::getStatus, status)
  25 + .orderByAsc(IotPluginInfoDO::getId));
  26 + }
  27 +
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/IotPluginInstanceMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
  6 +import org.apache.ibatis.annotations.Mapper;
  7 +
  8 +@Mapper
  9 +public interface IotPluginInstanceMapper extends BaseMapperX<IotPluginInstanceDO> {
  10 +
  11 + // TODO @芋艿:方法名,重构
  12 + default IotPluginInstanceDO selectByMainIdAndPluginId(String mainId, Long pluginId) {
  13 + return selectOne(new LambdaQueryWrapperX<IotPluginInstanceDO>()
  14 + .eq(IotPluginInstanceDO::getProcessId, mainId)
  15 + .eq(IotPluginInstanceDO::getPluginId, pluginId));
  16 + }
  17 +
  18 +}
0 \ No newline at end of file 19 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInfoMapper.java deleted
1 -package cn.iocoder.yudao.module.iot.dal.mysql.plugin;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
4 -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;  
5 -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;  
6 -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO;  
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO;  
8 -  
9 -import java.util.List;  
10 -  
11 -import org.apache.ibatis.annotations.Mapper;  
12 -  
13 -/**  
14 - * IoT 插件信息 Mapper  
15 - *  
16 - * @author 芋道源码  
17 - */  
18 -@Mapper  
19 -public interface PluginInfoMapper extends BaseMapperX<PluginInfoDO> {  
20 -  
21 - default PageResult<PluginInfoDO> selectPage(PluginInfoPageReqVO reqVO) {  
22 - return selectPage(reqVO, new LambdaQueryWrapperX<PluginInfoDO>()  
23 - .likeIfPresent(PluginInfoDO::getName, reqVO.getName())  
24 - .eqIfPresent(PluginInfoDO::getStatus, reqVO.getStatus())  
25 - .orderByDesc(PluginInfoDO::getId));  
26 - }  
27 -  
28 - default List<PluginInfoDO> selectListByStatus(Integer status) {  
29 - return selectList(new LambdaQueryWrapperX<PluginInfoDO>()  
30 - .eq(PluginInfoDO::getStatus, status)  
31 - .orderByAsc(PluginInfoDO::getId));  
32 - }  
33 -  
34 -}  
35 \ No newline at end of file 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java deleted
1 -package cn.iocoder.yudao.module.iot.dal.mysql.plugin;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
4 -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;  
5 -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;  
6 -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.instance.PluginInstancePageReqVO;  
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInstanceDO;  
8 -import org.apache.ibatis.annotations.Mapper;  
9 -  
10 -/**  
11 - * IoT 插件实例 Mapper  
12 - *  
13 - * @author 芋道源码  
14 - */  
15 -@Mapper  
16 -public interface PluginInstanceMapper extends BaseMapperX<PluginInstanceDO> {  
17 -  
18 - default PluginInstanceDO selectByMainIdAndPluginId(String mainId, Long pluginId) {  
19 - return selectOne(new LambdaQueryWrapperX<PluginInstanceDO>()  
20 - .eq(PluginInstanceDO::getMainId, mainId)  
21 - .eq(PluginInstanceDO::getPluginId, pluginId));  
22 - }  
23 -  
24 - // TODO @haohao:这个还需要么?相关不用的 VO 可以删除  
25 - default PageResult<PluginInstanceDO> selectPage(PluginInstancePageReqVO reqVO) {  
26 - return selectPage(reqVO, new LambdaQueryWrapperX<PluginInstanceDO>()  
27 - .eqIfPresent(PluginInstanceDO::getMainId, reqVO.getMainId())  
28 - .eqIfPresent(PluginInstanceDO::getPluginId, reqVO.getPluginId())  
29 - .eqIfPresent(PluginInstanceDO::getIp, reqVO.getIp())  
30 - .eqIfPresent(PluginInstanceDO::getPort, reqVO.getPort())  
31 - .eqIfPresent(PluginInstanceDO::getHeartbeatAt, reqVO.getHeartbeatAt())  
32 - .betweenIfPresent(PluginInstanceDO::getCreateTime, reqVO.getCreateTime())  
33 - .orderByDesc(PluginInstanceDO::getId));  
34 - }  
35 -  
36 -}  
37 \ No newline at end of file 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java
1 package cn.iocoder.yudao.module.iot.dal.redis; 1 package cn.iocoder.yudao.module.iot.dal.redis;
2 2
3 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; 3 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
  4 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
4 5
5 /** 6 /**
6 * Iot Redis Key 枚举类 7 * Iot Redis Key 枚举类
@@ -42,4 +43,13 @@ public interface RedisKeyConstants { @@ -42,4 +43,13 @@ public interface RedisKeyConstants {
42 */ 43 */
43 String THING_MODEL_LIST = "thing_model_list"; 44 String THING_MODEL_LIST = "thing_model_list";
44 45
  46 + /**
  47 + * 设备插件的插件进程编号的映射,采用 HASH 结构
  48 + *
  49 + * KEY 格式:device_plugin_instance_process_ids
  50 + * HASH KEY:${deviceKey}
  51 + * VALUE:插件进程编号,对应 {@link IotPluginInstanceDO#getProcessId()} 字段
  52 + */
  53 + String DEVICE_PLUGIN_INSTANCE_PROCESS_IDS = "device_plugin_instance_process_ids";
  54 +
45 } 55 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java
@@ -33,7 +33,7 @@ public class DevicePropertyRedisDAO { @@ -33,7 +33,7 @@ public class DevicePropertyRedisDAO {
33 entry -> JsonUtils.parseObject((String) entry.getValue(), IotDevicePropertyDO.class)); 33 entry -> JsonUtils.parseObject((String) entry.getValue(), IotDevicePropertyDO.class));
34 } 34 }
35 35
36 - public void set(String deviceKey, Map<String, IotDevicePropertyDO> properties) { 36 + public void putAll(String deviceKey, Map<String, IotDevicePropertyDO> properties) {
37 if (CollUtil.isEmpty(properties)) { 37 if (CollUtil.isEmpty(properties)) {
38 return; 38 return;
39 } 39 }
@@ -43,11 +43,6 @@ public class DevicePropertyRedisDAO { @@ -43,11 +43,6 @@ public class DevicePropertyRedisDAO {
43 entry -> JsonUtils.toJsonString(entry.getValue()))); 43 entry -> JsonUtils.toJsonString(entry.getValue())));
44 } 44 }
45 45
46 - public void delete(String deviceKey) {  
47 - String redisKey = formatKey(deviceKey);  
48 - stringRedisTemplate.delete(redisKey);  
49 - }  
50 -  
51 private static String formatKey(String deviceKey) { 46 private static String formatKey(String deviceKey) {
52 return String.format(DEVICE_PROPERTY, deviceKey); 47 return String.format(DEVICE_PROPERTY, deviceKey);
53 } 48 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/plugin/DevicePluginProcessIdRedisDAO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.redis.plugin;
  2 +
  3 +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
  4 +import jakarta.annotation.Resource;
  5 +import org.springframework.data.redis.core.StringRedisTemplate;
  6 +import org.springframework.stereotype.Repository;
  7 +
  8 +/**
  9 + * 设备插件的插件进程编号的缓存的 Redis DAO
  10 + */
  11 +@Repository
  12 +public class DevicePluginProcessIdRedisDAO {
  13 +
  14 + @Resource
  15 + private StringRedisTemplate stringRedisTemplate;
  16 +
  17 + public void put(String deviceKey, String processId) {
  18 + stringRedisTemplate.opsForHash().put(RedisKeyConstants.DEVICE_PLUGIN_INSTANCE_PROCESS_IDS, deviceKey, processId);
  19 + }
  20 +
  21 + public String get(String deviceKey) {
  22 + return (String) stringRedisTemplate.opsForHash().get(RedisKeyConstants.DEVICE_PLUGIN_INSTANCE_PROCESS_IDS, deviceKey);
  23 + }
  24 +
  25 +}
0 \ No newline at end of file 26 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/core/PluginStart.java
@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.iot.framework.plugin.core; @@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.iot.framework.plugin.core;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 4 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
5 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO; 5 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
6 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; 6 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
7 -import cn.iocoder.yudao.module.iot.service.plugin.PluginInfoService; 7 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInfoService;
8 import lombok.extern.slf4j.Slf4j; 8 import lombok.extern.slf4j.Slf4j;
9 import org.pf4j.spring.SpringPluginManager; 9 import org.pf4j.spring.SpringPluginManager;
10 import org.springframework.boot.ApplicationArguments; 10 import org.springframework.boot.ApplicationArguments;
@@ -20,7 +20,7 @@ import java.util.List; @@ -20,7 +20,7 @@ import java.util.List;
20 public class PluginStart implements ApplicationRunner { 20 public class PluginStart implements ApplicationRunner {
21 21
22 @Resource 22 @Resource
23 - private PluginInfoService pluginInfoService; 23 + private IotPluginInfoService pluginInfoService;
24 24
25 @Resource 25 @Resource
26 private SpringPluginManager pluginManager; 26 private SpringPluginManager pluginManager;
@@ -28,7 +28,7 @@ public class PluginStart implements ApplicationRunner { @@ -28,7 +28,7 @@ public class PluginStart implements ApplicationRunner {
28 @Override 28 @Override
29 public void run(ApplicationArguments args) { 29 public void run(ApplicationArguments args) {
30 TenantUtils.executeIgnore(() -> { // 1. 忽略租户上下文执行 30 TenantUtils.executeIgnore(() -> { // 1. 忽略租户上下文执行
31 - List<PluginInfoDO> pluginInfoList = pluginInfoService 31 + List<IotPluginInfoDO> pluginInfoList = pluginInfoService
32 .getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); // 2. 获取运行中的插件列表 32 .getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); // 2. 获取运行中的插件列表
33 if (CollUtil.isEmpty(pluginInfoList)) { // 3. 检查插件列表是否为空 33 if (CollUtil.isEmpty(pluginInfoList)) { // 3. 检查插件列表是否为空
34 log.info("[run] 没有需要启动的插件"); // 4. 日志记录没有插件需要启动 34 log.info("[run] 没有需要启动的插件"); // 4. 日志记录没有插件需要启动
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java
1 package cn.iocoder.yudao.module.iot.job.plugin; 1 package cn.iocoder.yudao.module.iot.job.plugin;
2 2
3 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 3 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
4 -import cn.iocoder.yudao.module.iot.service.plugin.PluginInstanceService; 4 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
5 import org.springframework.scheduling.annotation.Scheduled; 5 import org.springframework.scheduling.annotation.Scheduled;
6 import org.springframework.stereotype.Component; 6 import org.springframework.stereotype.Component;
7 7
@@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit; @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit;
18 public class PluginInstancesJob { 18 public class PluginInstancesJob {
19 19
20 @Resource 20 @Resource
21 - private PluginInstanceService pluginInstanceService; 21 + private IotPluginInstanceService pluginInstanceService;
22 22
23 @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) 23 @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
24 public void updatePluginInstances() { 24 public void updatePluginInstances() {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java
@@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; @@ -20,6 +20,7 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
20 import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer; 20 import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
21 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 21 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
22 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; 22 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
  23 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
23 import jakarta.annotation.Resource; 24 import jakarta.annotation.Resource;
24 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
25 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
@@ -43,6 +44,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @@ -43,6 +44,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
43 private IotDeviceService deviceService; 44 private IotDeviceService deviceService;
44 @Resource 45 @Resource
45 private IotDevicePropertyService devicePropertyService; 46 private IotDevicePropertyService devicePropertyService;
  47 + @Resource
  48 + private IotPluginInstanceService pluginInstanceService;
46 49
47 @Resource 50 @Resource
48 private IotDeviceProducer deviceProducer; 51 private IotDeviceProducer deviceProducer;
@@ -144,10 +147,11 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { @@ -144,10 +147,11 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
144 } 147 }
145 148
146 private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) { 149 private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) {
147 - // 1. TODO 芋艿:插件状态 150 + // 1. 【异步】记录设备与插件实例的映射
  151 + pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId());
148 152
149 - // 2. 更新设备的最后时间  
150 - devicePropertyService.updateDeviceReportTime(device.getDeviceKey(), LocalDateTime.now()); 153 + // 2. 【异步】更新设备的最后时间
  154 + devicePropertyService.updateDeviceReportTimeAsync(device.getDeviceKey(), LocalDateTime.now());
151 } 155 }
152 156
153 private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { 157 private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) {
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyService.java
@@ -61,11 +61,11 @@ public interface IotDevicePropertyService { @@ -61,11 +61,11 @@ public interface IotDevicePropertyService {
61 Set<String> getDeviceKeysByReportTime(LocalDateTime maxReportTime); 61 Set<String> getDeviceKeysByReportTime(LocalDateTime maxReportTime);
62 62
63 /** 63 /**
64 - * 更新设备上报时间 64 + * 异步更新设备上报时间
65 * 65 *
66 * @param deviceKey 设备标识 66 * @param deviceKey 设备标识
67 * @param reportTime 上报时间 67 * @param reportTime 上报时间
68 */ 68 */
69 - void updateDeviceReportTime(String deviceKey, LocalDateTime reportTime); 69 + void updateDeviceReportTimeAsync(String deviceKey, LocalDateTime reportTime);
70 70
71 } 71 }
72 \ No newline at end of file 72 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/data/IotDevicePropertyServiceImpl.java
@@ -27,6 +27,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; @@ -27,6 +27,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
27 import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 27 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
28 import jakarta.annotation.Resource; 28 import jakarta.annotation.Resource;
29 import lombok.extern.slf4j.Slf4j; 29 import lombok.extern.slf4j.Slf4j;
  30 +import org.springframework.scheduling.annotation.Async;
30 import org.springframework.stereotype.Service; 31 import org.springframework.stereotype.Service;
31 32
32 import java.time.LocalDateTime; 33 import java.time.LocalDateTime;
@@ -151,7 +152,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @@ -151,7 +152,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
151 LocalDateTimeUtil.toEpochMilli(message.getReportTime())); 152 LocalDateTimeUtil.toEpochMilli(message.getReportTime()));
152 153
153 // 3.2 保存设备属性【日志】 154 // 3.2 保存设备属性【日志】
154 - deviceDataRedisDAO.set(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey, 155 + deviceDataRedisDAO.putAll(message.getDeviceKey(), convertMap(properties.entrySet(), Map.Entry::getKey,
155 entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build())); 156 entry -> IotDevicePropertyDO.builder().value(entry.getValue()).updateTime(message.getReportTime()).build()));
156 } 157 }
157 158
@@ -190,7 +191,8 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @@ -190,7 +191,8 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService {
190 } 191 }
191 192
192 @Override 193 @Override
193 - public void updateDeviceReportTime(String deviceKey, LocalDateTime reportTime) { 194 + @Async
  195 + public void updateDeviceReportTimeAsync(String deviceKey, LocalDateTime reportTime) {
194 deviceReportTimeRedisDAO.update(deviceKey, reportTime); 196 deviceReportTimeRedisDAO.update(deviceKey, reportTime);
195 } 197 }
196 198
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoService.java
@@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.plugin; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.plugin;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; 4 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO;
5 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO;
6 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO; 6 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
7 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; 7 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 import org.springframework.web.multipart.MultipartFile; 9 import org.springframework.web.multipart.MultipartFile;
@@ -15,10 +15,10 @@ import java.util.List; @@ -15,10 +15,10 @@ import java.util.List;
15 * 15 *
16 * @author 芋道源码 16 * @author 芋道源码
17 */ 17 */
18 -public interface PluginInfoService { 18 +public interface IotPluginInfoService {
19 19
20 /** 20 /**
21 - * 创建IoT 插件信息 21 + * 创建插件信息
22 * 22 *
23 * @param createReqVO 创建信息 23 * @param createReqVO 创建信息
24 * @return 编号 24 * @return 编号
@@ -26,34 +26,34 @@ public interface PluginInfoService { @@ -26,34 +26,34 @@ public interface PluginInfoService {
26 Long createPluginInfo(@Valid PluginInfoSaveReqVO createReqVO); 26 Long createPluginInfo(@Valid PluginInfoSaveReqVO createReqVO);
27 27
28 /** 28 /**
29 - * 更新IoT 插件信息 29 + * 更新插件信息
30 * 30 *
31 * @param updateReqVO 更新信息 31 * @param updateReqVO 更新信息
32 */ 32 */
33 void updatePluginInfo(@Valid PluginInfoSaveReqVO updateReqVO); 33 void updatePluginInfo(@Valid PluginInfoSaveReqVO updateReqVO);
34 34
35 /** 35 /**
36 - * 删除IoT 插件信息 36 + * 删除插件信息
37 * 37 *
38 * @param id 编号 38 * @param id 编号
39 */ 39 */
40 void deletePluginInfo(Long id); 40 void deletePluginInfo(Long id);
41 41
42 /** 42 /**
43 - * 获得IoT 插件信息 43 + * 获得插件信息
44 * 44 *
45 * @param id 编号 45 * @param id 编号
46 - * @return IoT 插件信息 46 + * @return 插件信息
47 */ 47 */
48 - PluginInfoDO getPluginInfo(Long id); 48 + IotPluginInfoDO getPluginInfo(Long id);
49 49
50 /** 50 /**
51 - * 获得IoT 插件信息分页 51 + * 获得插件信息分页
52 * 52 *
53 * @param pageReqVO 分页查询 53 * @param pageReqVO 分页查询
54 - * @return IoT 插件信息分页 54 + * @return 插件信息分页
55 */ 55 */
56 - PageResult<PluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO); 56 + PageResult<IotPluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO);
57 57
58 /** 58 /**
59 * 上传插件的 JAR 包 59 * 上传插件的 JAR 包
@@ -76,7 +76,7 @@ public interface PluginInfoService { @@ -76,7 +76,7 @@ public interface PluginInfoService {
76 * 76 *
77 * @return 插件信息列表 77 * @return 插件信息列表
78 */ 78 */
79 - List<PluginInfoDO> getPluginInfoList(); 79 + List<IotPluginInfoDO> getPluginInfoList();
80 80
81 /** 81 /**
82 * 根据状态获得插件信息列表 82 * 根据状态获得插件信息列表
@@ -84,5 +84,5 @@ public interface PluginInfoService { @@ -84,5 +84,5 @@ public interface PluginInfoService {
84 * @param status 状态 {@link IotPluginStatusEnum} 84 * @param status 状态 {@link IotPluginStatusEnum}
85 * @return 插件信息列表 85 * @return 插件信息列表
86 */ 86 */
87 - List<PluginInfoDO> getPluginInfoListByStatus(Integer status); 87 + List<IotPluginInfoDO> getPluginInfoListByStatus(Integer status);
88 } 88 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInfoServiceImpl.java
@@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; 5 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO;
6 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO; 6 import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoSaveReqVO;
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO;  
8 -import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInfoMapper; 7 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
  8 +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInfoMapper;
9 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; 9 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
10 import jakarta.annotation.Resource; 10 import jakarta.annotation.Resource;
11 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
@@ -28,20 +28,20 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_N @@ -28,20 +28,20 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_N
28 @Service 28 @Service
29 @Validated 29 @Validated
30 @Slf4j 30 @Slf4j
31 -public class PluginInfoServiceImpl implements PluginInfoService { 31 +public class IotPluginInfoServiceImpl implements IotPluginInfoService {
32 32
33 @Resource 33 @Resource
34 - private PluginInfoMapper pluginInfoMapper; 34 + private IotPluginInfoMapper pluginInfoMapper;
35 35
36 @Resource 36 @Resource
37 - private PluginInstanceService pluginInstanceService; 37 + private IotPluginInstanceService pluginInstanceService;
38 38
39 @Resource 39 @Resource
40 private SpringPluginManager pluginManager; 40 private SpringPluginManager pluginManager;
41 41
42 @Override 42 @Override
43 public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { 43 public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) {
44 - PluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, PluginInfoDO.class); 44 + IotPluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, IotPluginInfoDO.class);
45 pluginInfoMapper.insert(pluginInfo); 45 pluginInfoMapper.insert(pluginInfo);
46 return pluginInfo.getId(); 46 return pluginInfo.getId();
47 } 47 }
@@ -51,14 +51,14 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -51,14 +51,14 @@ public class PluginInfoServiceImpl implements PluginInfoService {
51 // 校验存在 51 // 校验存在
52 validatePluginInfoExists(updateReqVO.getId()); 52 validatePluginInfoExists(updateReqVO.getId());
53 // 更新 53 // 更新
54 - PluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, PluginInfoDO.class); 54 + IotPluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, IotPluginInfoDO.class);
55 pluginInfoMapper.updateById(updateObj); 55 pluginInfoMapper.updateById(updateObj);
56 } 56 }
57 57
58 @Override 58 @Override
59 public void deletePluginInfo(Long id) { 59 public void deletePluginInfo(Long id) {
60 // 1.1 校验存在 60 // 1.1 校验存在
61 - PluginInfoDO pluginInfoDO = validatePluginInfoExists(id); 61 + IotPluginInfoDO pluginInfoDO = validatePluginInfoExists(id);
62 // 1.2 停止插件 62 // 1.2 停止插件
63 if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { 63 if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) {
64 throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); 64 throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING);
@@ -74,8 +74,8 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -74,8 +74,8 @@ public class PluginInfoServiceImpl implements PluginInfoService {
74 pluginInfoMapper.deleteById(id); 74 pluginInfoMapper.deleteById(id);
75 } 75 }
76 76
77 - private PluginInfoDO validatePluginInfoExists(Long id) {  
78 - PluginInfoDO pluginInfo = pluginInfoMapper.selectById(id); 77 + private IotPluginInfoDO validatePluginInfoExists(Long id) {
  78 + IotPluginInfoDO pluginInfo = pluginInfoMapper.selectById(id);
79 if (pluginInfo == null) { 79 if (pluginInfo == null) {
80 throw exception(PLUGIN_INFO_NOT_EXISTS); 80 throw exception(PLUGIN_INFO_NOT_EXISTS);
81 } 81 }
@@ -83,19 +83,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -83,19 +83,19 @@ public class PluginInfoServiceImpl implements PluginInfoService {
83 } 83 }
84 84
85 @Override 85 @Override
86 - public PluginInfoDO getPluginInfo(Long id) { 86 + public IotPluginInfoDO getPluginInfo(Long id) {
87 return pluginInfoMapper.selectById(id); 87 return pluginInfoMapper.selectById(id);
88 } 88 }
89 89
90 @Override 90 @Override
91 - public PageResult<PluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO) { 91 + public PageResult<IotPluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO) {
92 return pluginInfoMapper.selectPage(pageReqVO); 92 return pluginInfoMapper.selectPage(pageReqVO);
93 } 93 }
94 94
95 @Override 95 @Override
96 public void uploadFile(Long id, MultipartFile file) { 96 public void uploadFile(Long id, MultipartFile file) {
97 // 1. 校验插件信息是否存在 97 // 1. 校验插件信息是否存在
98 - PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); 98 + IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id);
99 99
100 // 2. 停止并卸载旧的插件 100 // 2. 停止并卸载旧的插件
101 pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); 101 pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey());
@@ -114,9 +114,9 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -114,9 +114,9 @@ public class PluginInfoServiceImpl implements PluginInfoService {
114 * @param pluginKeyNew 插件标识符 114 * @param pluginKeyNew 插件标识符
115 * @param file 文件 115 * @param file 文件
116 */ 116 */
117 - private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) { 117 + private void updatePluginInfo(IotPluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) {
118 // 创建新的插件信息对象并链式设置属性 118 // 创建新的插件信息对象并链式设置属性
119 - PluginInfoDO updatedPluginInfo = new PluginInfoDO() 119 + IotPluginInfoDO updatedPluginInfo = new IotPluginInfoDO()
120 .setId(pluginInfoDo.getId()) 120 .setId(pluginInfoDo.getId())
121 .setPluginKey(pluginKeyNew) 121 .setPluginKey(pluginKeyNew)
122 .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) 122 .setStatus(IotPluginStatusEnum.STOPPED.getStatus())
@@ -133,25 +133,25 @@ public class PluginInfoServiceImpl implements PluginInfoService { @@ -133,25 +133,25 @@ public class PluginInfoServiceImpl implements PluginInfoService {
133 @Override 133 @Override
134 public void updatePluginStatus(Long id, Integer status) { 134 public void updatePluginStatus(Long id, Integer status) {
135 // 1. 校验插件信息是否存在 135 // 1. 校验插件信息是否存在
136 - PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); 136 + IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id);
137 137
138 // 2. 更新插件状态 138 // 2. 更新插件状态
139 pluginInstanceService.updatePluginStatus(pluginInfoDo, status); 139 pluginInstanceService.updatePluginStatus(pluginInfoDo, status);
140 140
141 // 3. 更新数据库中的插件状态 141 // 3. 更新数据库中的插件状态
142 - PluginInfoDO updatedPluginInfo = new PluginInfoDO(); 142 + IotPluginInfoDO updatedPluginInfo = new IotPluginInfoDO();
143 updatedPluginInfo.setId(id); 143 updatedPluginInfo.setId(id);
144 updatedPluginInfo.setStatus(status); 144 updatedPluginInfo.setStatus(status);
145 pluginInfoMapper.updateById(updatedPluginInfo); 145 pluginInfoMapper.updateById(updatedPluginInfo);
146 } 146 }
147 147
148 @Override 148 @Override
149 - public List<PluginInfoDO> getPluginInfoList() { 149 + public List<IotPluginInfoDO> getPluginInfoList() {
150 return pluginInfoMapper.selectList(); 150 return pluginInfoMapper.selectList();
151 } 151 }
152 152
153 @Override 153 @Override
154 - public List<PluginInfoDO> getPluginInfoListByStatus(Integer status) { 154 + public List<IotPluginInfoDO> getPluginInfoListByStatus(Integer status) {
155 return pluginInfoMapper.selectListByStatus(status); 155 return pluginInfoMapper.selectListByStatus(status);
156 } 156 }
157 157
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceService.java
1 package cn.iocoder.yudao.module.iot.service.plugin; 1 package cn.iocoder.yudao.module.iot.service.plugin;
2 2
3 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO; 3 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
4 import org.springframework.web.multipart.MultipartFile; 4 import org.springframework.web.multipart.MultipartFile;
5 5
6 /** 6 /**
@@ -8,7 +8,7 @@ import org.springframework.web.multipart.MultipartFile; @@ -8,7 +8,7 @@ import org.springframework.web.multipart.MultipartFile;
8 * 8 *
9 * @author 芋道源码 9 * @author 芋道源码
10 */ 10 */
11 -public interface PluginInstanceService { 11 +public interface IotPluginInstanceService {
12 12
13 // TODO @芋艿:这个是否应该放到 plugin 主动心跳,而是 server 自己心跳 13 // TODO @芋艿:这个是否应该放到 plugin 主动心跳,而是 server 自己心跳
14 /** 14 /**
@@ -28,7 +28,7 @@ public interface PluginInstanceService { @@ -28,7 +28,7 @@ public interface PluginInstanceService {
28 * 28 *
29 * @param pluginInfoDo 插件信息 29 * @param pluginInfoDo 插件信息
30 */ 30 */
31 - void deletePluginFile(PluginInfoDO pluginInfoDo); 31 + void deletePluginFile(IotPluginInfoDO pluginInfoDo);
32 32
33 /** 33 /**
34 * 上传并加载新的插件文件 34 * 上传并加载新的插件文件
@@ -44,6 +44,16 @@ public interface PluginInstanceService { @@ -44,6 +44,16 @@ public interface PluginInstanceService {
44 * @param pluginInfoDo 插件信息 44 * @param pluginInfoDo 插件信息
45 * @param status 新状态 45 * @param status 新状态
46 */ 46 */
47 - void updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status); 47 + void updatePluginStatus(IotPluginInfoDO pluginInfoDo, Integer status);
  48 +
  49 + // ========== 设备与插件的映射操作 ==========
  50 +
  51 + /**
  52 + * 更新设备对应的插件实例的进程编号
  53 + *
  54 + * @param deviceKey 设备 Key
  55 + * @param processId 进程编号
  56 + */
  57 + void updateDevicePluginInstanceProcessIdAsync(String deviceKey, String processId);
48 58
49 } 59 }
50 \ No newline at end of file 60 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java
@@ -3,10 +3,11 @@ package cn.iocoder.yudao.module.iot.service.plugin; @@ -3,10 +3,11 @@ package cn.iocoder.yudao.module.iot.service.plugin;
3 import cn.hutool.core.io.FileUtil; 3 import cn.hutool.core.io.FileUtil;
4 import cn.hutool.core.net.NetUtil; 4 import cn.hutool.core.net.NetUtil;
5 import cn.hutool.core.util.IdUtil; 5 import cn.hutool.core.util.IdUtil;
6 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInfoDO;  
7 -import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.PluginInstanceDO;  
8 -import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInfoMapper;  
9 -import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInstanceMapper; 6 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
  8 +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInfoMapper;
  9 +import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInstanceMapper;
  10 +import cn.iocoder.yudao.module.iot.dal.redis.plugin.DevicePluginProcessIdRedisDAO;
10 import cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants; 11 import cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants;
11 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; 12 import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
12 import jakarta.annotation.Resource; 13 import jakarta.annotation.Resource;
@@ -38,16 +39,20 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -38,16 +39,20 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
38 @Service 39 @Service
39 @Validated 40 @Validated
40 @Slf4j 41 @Slf4j
41 -public class PluginInstanceServiceImpl implements PluginInstanceService { 42 +public class IotPluginInstanceServiceImpl implements IotPluginInstanceService {
42 43
43 // TODO @haohao:mac@uuid 44 // TODO @haohao:mac@uuid
44 public static final String MAIN_ID = IdUtil.fastSimpleUUID(); 45 public static final String MAIN_ID = IdUtil.fastSimpleUUID();
45 46
  47 + // TODO @haohao:不直接操作,通过 Service 哈
46 @Resource 48 @Resource
47 - private PluginInfoMapper pluginInfoMapper; 49 + private IotPluginInfoMapper pluginInfoMapper;
48 50
49 @Resource 51 @Resource
50 - private PluginInstanceMapper pluginInstanceMapper; 52 + private IotPluginInstanceMapper pluginInstanceMapper;
  53 +
  54 + @Resource
  55 + private DevicePluginProcessIdRedisDAO devicePluginProcessIdRedisDAO;
51 56
52 @Resource 57 @Resource
53 private SpringPluginManager pluginManager; 58 private SpringPluginManager pluginManager;
@@ -73,7 +78,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @@ -73,7 +78,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService {
73 } 78 }
74 79
75 @Override 80 @Override
76 - public void deletePluginFile(PluginInfoDO pluginInfoDO) { 81 + public void deletePluginFile(IotPluginInfoDO pluginInfoDO) {
77 File file = new File(pluginsDir, pluginInfoDO.getFileName()); 82 File file = new File(pluginsDir, pluginInfoDO.getFileName());
78 if (!file.exists()) { 83 if (!file.exists()) {
79 return; 84 return;
@@ -115,7 +120,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @@ -115,7 +120,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService {
115 } 120 }
116 121
117 @Override 122 @Override
118 - public void updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status) { 123 + public void updatePluginStatus(IotPluginInfoDO pluginInfoDo, Integer status) {
119 String pluginKey = pluginInfoDo.getPluginKey(); 124 String pluginKey = pluginInfoDo.getPluginKey();
120 PluginWrapper plugin = pluginManager.getPlugin(pluginKey); 125 PluginWrapper plugin = pluginManager.getPlugin(pluginKey);
121 126
@@ -147,9 +152,9 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @@ -147,9 +152,9 @@ public class PluginInstanceServiceImpl implements PluginInstanceService {
147 List<PluginWrapper> plugins = pluginManager.getPlugins(); 152 List<PluginWrapper> plugins = pluginManager.getPlugins();
148 153
149 // 1.2 获取插件信息列表并转换为 Map 以便快速查找 154 // 1.2 获取插件信息列表并转换为 Map 以便快速查找
150 - List<PluginInfoDO> pluginInfos = pluginInfoMapper.selectList();  
151 - Map<String, PluginInfoDO> pluginInfoMap = pluginInfos.stream()  
152 - .collect(Collectors.toMap(PluginInfoDO::getPluginKey, Function.identity())); 155 + List<IotPluginInfoDO> pluginInfos = pluginInfoMapper.selectList();
  156 + Map<String, IotPluginInfoDO> pluginInfoMap = pluginInfos.stream()
  157 + .collect(Collectors.toMap(IotPluginInfoDO::getPluginKey, Function.identity()));
153 158
154 // 1.3 获取本机 IP 和 MAC 地址,mac@uuid 159 // 1.3 获取本机 IP 和 MAC 地址,mac@uuid
155 String ip = NetUtil.getLocalhostStr(); 160 String ip = NetUtil.getLocalhostStr();
@@ -161,34 +166,42 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { @@ -161,34 +166,42 @@ public class PluginInstanceServiceImpl implements PluginInstanceService {
161 String pluginKey = plugin.getPluginId(); 166 String pluginKey = plugin.getPluginId();
162 167
163 // 2.1 查找插件信息 168 // 2.1 查找插件信息
164 - PluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey); 169 + IotPluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey);
165 if (pluginInfo == null) { 170 if (pluginInfo == null) {
166 log.error("插件信息不存在,pluginKey = {}", pluginKey); 171 log.error("插件信息不存在,pluginKey = {}", pluginKey);
167 continue; 172 continue;
168 } 173 }
169 174
170 // 2.2 情况一:如果插件实例不存在,则创建 175 // 2.2 情况一:如果插件实例不存在,则创建
171 - PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId, 176 + IotPluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId,
172 pluginInfo.getId()); 177 pluginInfo.getId());
173 - if (pluginInstance == null) {  
174 - // 4.4 如果插件实例不存在,则创建  
175 - pluginInstance = PluginInstanceDO.builder()  
176 - .pluginId(pluginInfo.getId())  
177 - .mainId(MAIN_ID + "-" + mac)  
178 - .ip(ip)  
179 - .port(port)  
180 - .heartbeatAt(System.currentTimeMillis())  
181 - .build();  
182 - pluginInstanceMapper.insert(pluginInstance);  
183 - } else {  
184 - // 2.2 情况二:如果存在,则更新 heartbeatAt  
185 - PluginInstanceDO updatePluginInstance = PluginInstanceDO.builder()  
186 - .id(pluginInstance.getId())  
187 - .heartbeatAt(System.currentTimeMillis())  
188 - .build();  
189 - pluginInstanceMapper.updateById(updatePluginInstance);  
190 - } 178 + // TODO @芋艿:稍后优化;
  179 +// if (pluginInstance == null) {
  180 +// // 4.4 如果插件实例不存在,则创建
  181 +// pluginInstance = PluginInstanceDO.builder()
  182 +// .pluginId(pluginInfo.getId())
  183 +// .mainId(MAIN_ID + "-" + mac)
  184 +// .hostIp(ip)
  185 +// .port(port)
  186 +// .heartbeatAt(System.currentTimeMillis())
  187 +// .build();
  188 +// pluginInstanceMapper.insert(pluginInstance);
  189 +// } else {
  190 +// // 2.2 情况二:如果存在,则更新 heartbeatAt
  191 +// PluginInstanceDO updatePluginInstance = PluginInstanceDO.builder()
  192 +// .id(pluginInstance.getId())
  193 +// .heartbeatAt(System.currentTimeMillis())
  194 +// .build();
  195 +// pluginInstanceMapper.updateById(updatePluginInstance);
  196 +// }
191 } 197 }
192 } 198 }
193 199
  200 + // ========== 设备与插件的映射操作 ==========
  201 +
  202 + @Override
  203 + public void updateDevicePluginInstanceProcessIdAsync(String deviceKey, String processId) {
  204 + devicePluginProcessIdRedisDAO.put(deviceKey, processId);
  205 + }
  206 +
194 } 207 }
195 \ No newline at end of file 208 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 -<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInstanceMapper"> 3 +<mapper namespace="cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInstanceMapper">
4 4
5 <!-- 5 <!--
6 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。 6 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.plugin.common.util;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.hutool.system.SystemUtil;
  6 +
  7 +/**
  8 + * IoT 插件的通用工具类
  9 + *
  10 + * 芋道源码
  11 + */
  12 +public class IotPluginCommonUtils {
  13 +
  14 + /**
  15 + * 流程实例的进程编号
  16 + */
  17 + private static String processId;
  18 +
  19 + public static String getProcessId() {
  20 + if (StrUtil.isEmpty(processId)) {
  21 + initProcessId();
  22 + }
  23 + return processId;
  24 + }
  25 +
  26 + private synchronized static void initProcessId() {
  27 + processId = String.format("%s@%d@%s", // IP@PID@${uuid}
  28 + SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID());
  29 + }
  30 +
  31 +}
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/pom.xml
@@ -128,6 +128,12 @@ @@ -128,6 +128,12 @@
128 <version>${revision}</version> 128 <version>${revision}</version>
129 </dependency> 129 </dependency>
130 130
  131 + <!-- Web 相关 -->
  132 + <dependency>
  133 + <groupId>org.springframework.boot</groupId>
  134 + <artifactId>spring-boot-starter-web</artifactId>
  135 + </dependency>
  136 +
131 <!-- 工具类相关 --> 137 <!-- 工具类相关 -->
132 <dependency> 138 <dependency>
133 <groupId>io.vertx</groupId> 139 <groupId>io.vertx</groupId>
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/HttpPluginSpringbootApplication.java renamed to yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/IotHttpPluginApplication.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.plugin.http;
2 2
3 import lombok.extern.slf4j.Slf4j; 3 import lombok.extern.slf4j.Slf4j;
4 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.SpringApplication;
  5 +import org.springframework.boot.WebApplicationType;
5 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 import org.springframework.boot.autoconfigure.SpringBootApplication;
6 import org.springframework.context.ConfigurableApplicationContext; 7 import org.springframework.context.ConfigurableApplicationContext;
7 8
@@ -10,10 +11,12 @@ import org.springframework.context.ConfigurableApplicationContext; @@ -10,10 +11,12 @@ import org.springframework.context.ConfigurableApplicationContext;
10 */ 11 */
11 @Slf4j 12 @Slf4j
12 @SpringBootApplication 13 @SpringBootApplication
13 -public class HttpPluginSpringbootApplication { 14 +public class IotHttpPluginApplication {
14 15
15 public static void main(String[] args) { 16 public static void main(String[] args) {
16 - ConfigurableApplicationContext context = SpringApplication.run(HttpPluginSpringbootApplication.class, args); 17 + SpringApplication application = new SpringApplication(IotHttpPluginApplication.class);
  18 + application.setWebApplicationType(WebApplicationType.NONE);
  19 + ConfigurableApplicationContext context = application.run(args);
17 20
18 // 手动获取 VertxService 并启动 21 // 手动获取 VertxService 并启动
19 // TODO @haohao:可以放在 bean 的 init 里么?回复:会和插件模式冲突 @芋艿,测试下 22 // TODO @haohao:可以放在 bean 的 init 里么?回复:会和插件模式冲突 @芋艿,测试下
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDevicePropertyReportVertxHandler.java
@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi; @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
7 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; 7 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO;
8 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; 8 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO;
9 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; 9 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
  10 +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils;
10 import io.vertx.core.Handler; 11 import io.vertx.core.Handler;
11 import io.vertx.ext.web.RequestBody; 12 import io.vertx.ext.web.RequestBody;
12 import io.vertx.ext.web.RoutingContext; 13 import io.vertx.ext.web.RoutingContext;
@@ -50,19 +51,17 @@ public class IotDevicePropertyReportVertxHandler implements Handler&lt;RoutingConte @@ -50,19 +51,17 @@ public class IotDevicePropertyReportVertxHandler implements Handler&lt;RoutingConte
50 String id = jsonData.getStr("id"); 51 String id = jsonData.getStr("id");
51 52
52 try { 53 try {
53 - // TODO @haohao:pluginKey 需要设置  
54 // 设备上线 54 // 设备上线
55 deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) 55 deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO)
56 new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) 56 new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID())
57 - .setPluginKey("http")  
58 - .setReportTime(LocalDateTime.now()) 57 + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now())
59 .setProductKey(productKey).setDeviceName(deviceName)) 58 .setProductKey(productKey).setDeviceName(deviceName))
60 .setState(IotDeviceStateEnum.ONLINE.getState())); 59 .setState(IotDeviceStateEnum.ONLINE.getState()));
61 60
62 // 属性上报 61 // 属性上报
63 deviceUpstreamApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO) 62 deviceUpstreamApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO)
64 new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID()) 63 new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID())
65 - .setPluginKey("http").setReportTime(LocalDateTime.now()) 64 + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now())
66 .setProductKey(productKey).setDeviceName(deviceName)) 65 .setProductKey(productKey).setDeviceName(deviceName))
67 .setProperties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties"))); 66 .setProperties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties")));
68 67