Commit e650e75271cf241721f19014dadb22b3b51e24f0
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
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 | 7 | import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoRespVO; |
| 9 | 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 | 12 | import io.swagger.v3.oas.annotations.Operation; |
| 13 | 13 | import io.swagger.v3.oas.annotations.Parameter; |
| 14 | 14 | import io.swagger.v3.oas.annotations.tags.Tag; |
| ... | ... | @@ -27,7 +27,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 27 | 27 | public class PluginInfoController { |
| 28 | 28 | |
| 29 | 29 | @Resource |
| 30 | - private PluginInfoService pluginInfoService; | |
| 30 | + private IotPluginInfoService pluginInfoService; | |
| 31 | 31 | |
| 32 | 32 | @PostMapping("/create") |
| 33 | 33 | @Operation(summary = "创建插件信息") |
| ... | ... | @@ -58,7 +58,7 @@ public class PluginInfoController { |
| 58 | 58 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 59 | 59 | @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") |
| 60 | 60 | public CommonResult<PluginInfoRespVO> getPluginInfo(@RequestParam("id") Long id) { |
| 61 | - PluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id); | |
| 61 | + IotPluginInfoDO pluginInfo = pluginInfoService.getPluginInfo(id); | |
| 62 | 62 | return success(BeanUtils.toBean(pluginInfo, PluginInfoRespVO.class)); |
| 63 | 63 | } |
| 64 | 64 | |
| ... | ... | @@ -66,7 +66,7 @@ public class PluginInfoController { |
| 66 | 66 | @Operation(summary = "获得插件信息分页") |
| 67 | 67 | @PreAuthorize("@ss.hasPermission('iot:plugin-info:query')") |
| 68 | 68 | public CommonResult<PageResult<PluginInfoRespVO>> getPluginInfoPage(@Valid PluginInfoPageReqVO pageReqVO) { |
| 69 | - PageResult<PluginInfoDO> pageResult = pluginInfoService.getPluginInfoPage(pageReqVO); | |
| 69 | + PageResult<IotPluginInfoDO> pageResult = pluginInfoService.getPluginInfoPage(pageReqVO); | |
| 70 | 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
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 | import com.baomidou.mybatisplus.annotation.TableName; |
| 7 | 7 | import lombok.*; |
| 8 | 8 | |
| 9 | +import java.time.LocalDateTime; | |
| 9 | 10 | |
| 10 | 11 | /** |
| 11 | 12 | * IoT 插件实例 DO |
| ... | ... | @@ -20,40 +21,52 @@ import lombok.*; |
| 20 | 21 | @Builder |
| 21 | 22 | @NoArgsConstructor |
| 22 | 23 | @AllArgsConstructor |
| 23 | -public class PluginInstanceDO extends BaseDO { | |
| 24 | +public class IotPluginInstanceDO extends BaseDO { | |
| 24 | 25 | |
| 25 | 26 | /** |
| 26 | - * 主键ID | |
| 27 | + * 主键 | |
| 27 | 28 | */ |
| 28 | 29 | @TableId |
| 29 | 30 | private Long id; |
| 30 | - // TODO @芋艿:找一个更好的字段名 | |
| 31 | 31 | /** |
| 32 | - * 插件主程序 ID | |
| 33 | - */ | |
| 34 | - private String mainId; | |
| 35 | - /** | |
| 36 | - * 插件 ID | |
| 32 | + * 插件编号 | |
| 37 | 33 | * <p> |
| 38 | - * 关联 {@link PluginInfoDO#getId()} | |
| 34 | + * 关联 {@link IotPluginInfoDO#getId()} | |
| 39 | 35 | */ |
| 40 | 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 | 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 | 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 | 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 | 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 | 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 | 1 | package cn.iocoder.yudao.module.iot.dal.redis; |
| 2 | 2 | |
| 3 | 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 | 7 | * Iot Redis Key 枚举类 |
| ... | ... | @@ -42,4 +43,13 @@ public interface RedisKeyConstants { |
| 42 | 43 | */ |
| 43 | 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 | 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 | 37 | if (CollUtil.isEmpty(properties)) { |
| 38 | 38 | return; |
| 39 | 39 | } |
| ... | ... | @@ -43,11 +43,6 @@ public class DevicePropertyRedisDAO { |
| 43 | 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 | 46 | private static String formatKey(String deviceKey) { |
| 52 | 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 | 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 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 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 | 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 | 8 | import lombok.extern.slf4j.Slf4j; |
| 9 | 9 | import org.pf4j.spring.SpringPluginManager; |
| 10 | 10 | import org.springframework.boot.ApplicationArguments; |
| ... | ... | @@ -20,7 +20,7 @@ import java.util.List; |
| 20 | 20 | public class PluginStart implements ApplicationRunner { |
| 21 | 21 | |
| 22 | 22 | @Resource |
| 23 | - private PluginInfoService pluginInfoService; | |
| 23 | + private IotPluginInfoService pluginInfoService; | |
| 24 | 24 | |
| 25 | 25 | @Resource |
| 26 | 26 | private SpringPluginManager pluginManager; |
| ... | ... | @@ -28,7 +28,7 @@ public class PluginStart implements ApplicationRunner { |
| 28 | 28 | @Override |
| 29 | 29 | public void run(ApplicationArguments args) { |
| 30 | 30 | TenantUtils.executeIgnore(() -> { // 1. 忽略租户上下文执行 |
| 31 | - List<PluginInfoDO> pluginInfoList = pluginInfoService | |
| 31 | + List<IotPluginInfoDO> pluginInfoList = pluginInfoService | |
| 32 | 32 | .getPluginInfoListByStatus(IotPluginStatusEnum.RUNNING.getStatus()); // 2. 获取运行中的插件列表 |
| 33 | 33 | if (CollUtil.isEmpty(pluginInfoList)) { // 3. 检查插件列表是否为空 |
| 34 | 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 | 1 | package cn.iocoder.yudao.module.iot.job.plugin; |
| 2 | 2 | |
| 3 | 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 | 5 | import org.springframework.scheduling.annotation.Scheduled; |
| 6 | 6 | import org.springframework.stereotype.Component; |
| 7 | 7 | |
| ... | ... | @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit; |
| 18 | 18 | public class PluginInstancesJob { |
| 19 | 19 | |
| 20 | 20 | @Resource |
| 21 | - private PluginInstanceService pluginInstanceService; | |
| 21 | + private IotPluginInstanceService pluginInstanceService; | |
| 22 | 22 | |
| 23 | 23 | @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) |
| 24 | 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 | 20 | import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer; |
| 21 | 21 | import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; |
| 22 | 22 | import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService; |
| 23 | +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService; | |
| 23 | 24 | import jakarta.annotation.Resource; |
| 24 | 25 | import lombok.extern.slf4j.Slf4j; |
| 25 | 26 | import org.springframework.stereotype.Service; |
| ... | ... | @@ -43,6 +44,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { |
| 43 | 44 | private IotDeviceService deviceService; |
| 44 | 45 | @Resource |
| 45 | 46 | private IotDevicePropertyService devicePropertyService; |
| 47 | + @Resource | |
| 48 | + private IotPluginInstanceService pluginInstanceService; | |
| 46 | 49 | |
| 47 | 50 | @Resource |
| 48 | 51 | private IotDeviceProducer deviceProducer; |
| ... | ... | @@ -144,10 +147,11 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService { |
| 144 | 147 | } |
| 145 | 148 | |
| 146 | 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 | 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 | 61 | Set<String> getDeviceKeysByReportTime(LocalDateTime maxReportTime); |
| 62 | 62 | |
| 63 | 63 | /** |
| 64 | - * 更新设备上报时间 | |
| 64 | + * 异步更新设备上报时间 | |
| 65 | 65 | * |
| 66 | 66 | * @param deviceKey 设备标识 |
| 67 | 67 | * @param reportTime 上报时间 |
| 68 | 68 | */ |
| 69 | - void updateDeviceReportTime(String deviceKey, LocalDateTime reportTime); | |
| 69 | + void updateDeviceReportTimeAsync(String deviceKey, LocalDateTime reportTime); | |
| 70 | 70 | |
| 71 | 71 | } |
| 72 | 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 | 27 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| 28 | 28 | import jakarta.annotation.Resource; |
| 29 | 29 | import lombok.extern.slf4j.Slf4j; |
| 30 | +import org.springframework.scheduling.annotation.Async; | |
| 30 | 31 | import org.springframework.stereotype.Service; |
| 31 | 32 | |
| 32 | 33 | import java.time.LocalDateTime; |
| ... | ... | @@ -151,7 +152,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { |
| 151 | 152 | LocalDateTimeUtil.toEpochMilli(message.getReportTime())); |
| 152 | 153 | |
| 153 | 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 | 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 | 191 | } |
| 191 | 192 | |
| 192 | 193 | @Override |
| 193 | - public void updateDeviceReportTime(String deviceKey, LocalDateTime reportTime) { | |
| 194 | + @Async | |
| 195 | + public void updateDeviceReportTimeAsync(String deviceKey, LocalDateTime reportTime) { | |
| 194 | 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 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; |
| 5 | 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 | 7 | import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; |
| 8 | 8 | import jakarta.validation.Valid; |
| 9 | 9 | import org.springframework.web.multipart.MultipartFile; |
| ... | ... | @@ -15,10 +15,10 @@ import java.util.List; |
| 15 | 15 | * |
| 16 | 16 | * @author 芋道源码 |
| 17 | 17 | */ |
| 18 | -public interface PluginInfoService { | |
| 18 | +public interface IotPluginInfoService { | |
| 19 | 19 | |
| 20 | 20 | /** |
| 21 | - * 创建IoT 插件信息 | |
| 21 | + * 创建插件信息 | |
| 22 | 22 | * |
| 23 | 23 | * @param createReqVO 创建信息 |
| 24 | 24 | * @return 编号 |
| ... | ... | @@ -26,34 +26,34 @@ public interface PluginInfoService { |
| 26 | 26 | Long createPluginInfo(@Valid PluginInfoSaveReqVO createReqVO); |
| 27 | 27 | |
| 28 | 28 | /** |
| 29 | - * 更新IoT 插件信息 | |
| 29 | + * 更新插件信息 | |
| 30 | 30 | * |
| 31 | 31 | * @param updateReqVO 更新信息 |
| 32 | 32 | */ |
| 33 | 33 | void updatePluginInfo(@Valid PluginInfoSaveReqVO updateReqVO); |
| 34 | 34 | |
| 35 | 35 | /** |
| 36 | - * 删除IoT 插件信息 | |
| 36 | + * 删除插件信息 | |
| 37 | 37 | * |
| 38 | 38 | * @param id 编号 |
| 39 | 39 | */ |
| 40 | 40 | void deletePluginInfo(Long id); |
| 41 | 41 | |
| 42 | 42 | /** |
| 43 | - * 获得IoT 插件信息 | |
| 43 | + * 获得插件信息 | |
| 44 | 44 | * |
| 45 | 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 | 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 | 59 | * 上传插件的 JAR 包 |
| ... | ... | @@ -76,7 +76,7 @@ public interface PluginInfoService { |
| 76 | 76 | * |
| 77 | 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 | 84 | * @param status 状态 {@link IotPluginStatusEnum} |
| 85 | 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 | 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.info.PluginInfoPageReqVO; |
| 6 | 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 | 9 | import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; |
| 10 | 10 | import jakarta.annotation.Resource; |
| 11 | 11 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -28,20 +28,20 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INFO_N |
| 28 | 28 | @Service |
| 29 | 29 | @Validated |
| 30 | 30 | @Slf4j |
| 31 | -public class PluginInfoServiceImpl implements PluginInfoService { | |
| 31 | +public class IotPluginInfoServiceImpl implements IotPluginInfoService { | |
| 32 | 32 | |
| 33 | 33 | @Resource |
| 34 | - private PluginInfoMapper pluginInfoMapper; | |
| 34 | + private IotPluginInfoMapper pluginInfoMapper; | |
| 35 | 35 | |
| 36 | 36 | @Resource |
| 37 | - private PluginInstanceService pluginInstanceService; | |
| 37 | + private IotPluginInstanceService pluginInstanceService; | |
| 38 | 38 | |
| 39 | 39 | @Resource |
| 40 | 40 | private SpringPluginManager pluginManager; |
| 41 | 41 | |
| 42 | 42 | @Override |
| 43 | 43 | public Long createPluginInfo(PluginInfoSaveReqVO createReqVO) { |
| 44 | - PluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, PluginInfoDO.class); | |
| 44 | + IotPluginInfoDO pluginInfo = BeanUtils.toBean(createReqVO, IotPluginInfoDO.class); | |
| 45 | 45 | pluginInfoMapper.insert(pluginInfo); |
| 46 | 46 | return pluginInfo.getId(); |
| 47 | 47 | } |
| ... | ... | @@ -51,14 +51,14 @@ public class PluginInfoServiceImpl implements PluginInfoService { |
| 51 | 51 | // 校验存在 |
| 52 | 52 | validatePluginInfoExists(updateReqVO.getId()); |
| 53 | 53 | // 更新 |
| 54 | - PluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, PluginInfoDO.class); | |
| 54 | + IotPluginInfoDO updateObj = BeanUtils.toBean(updateReqVO, IotPluginInfoDO.class); | |
| 55 | 55 | pluginInfoMapper.updateById(updateObj); |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | 58 | @Override |
| 59 | 59 | public void deletePluginInfo(Long id) { |
| 60 | 60 | // 1.1 校验存在 |
| 61 | - PluginInfoDO pluginInfoDO = validatePluginInfoExists(id); | |
| 61 | + IotPluginInfoDO pluginInfoDO = validatePluginInfoExists(id); | |
| 62 | 62 | // 1.2 停止插件 |
| 63 | 63 | if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { |
| 64 | 64 | throw exception(PLUGIN_INFO_DELETE_FAILED_RUNNING); |
| ... | ... | @@ -74,8 +74,8 @@ public class PluginInfoServiceImpl implements PluginInfoService { |
| 74 | 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 | 79 | if (pluginInfo == null) { |
| 80 | 80 | throw exception(PLUGIN_INFO_NOT_EXISTS); |
| 81 | 81 | } |
| ... | ... | @@ -83,19 +83,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { |
| 83 | 83 | } |
| 84 | 84 | |
| 85 | 85 | @Override |
| 86 | - public PluginInfoDO getPluginInfo(Long id) { | |
| 86 | + public IotPluginInfoDO getPluginInfo(Long id) { | |
| 87 | 87 | return pluginInfoMapper.selectById(id); |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | 90 | @Override |
| 91 | - public PageResult<PluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO) { | |
| 91 | + public PageResult<IotPluginInfoDO> getPluginInfoPage(PluginInfoPageReqVO pageReqVO) { | |
| 92 | 92 | return pluginInfoMapper.selectPage(pageReqVO); |
| 93 | 93 | } |
| 94 | 94 | |
| 95 | 95 | @Override |
| 96 | 96 | public void uploadFile(Long id, MultipartFile file) { |
| 97 | 97 | // 1. 校验插件信息是否存在 |
| 98 | - PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); | |
| 98 | + IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id); | |
| 99 | 99 | |
| 100 | 100 | // 2. 停止并卸载旧的插件 |
| 101 | 101 | pluginInstanceService.stopAndUnloadPlugin(pluginInfoDo.getPluginKey()); |
| ... | ... | @@ -114,9 +114,9 @@ public class PluginInfoServiceImpl implements PluginInfoService { |
| 114 | 114 | * @param pluginKeyNew 插件标识符 |
| 115 | 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 | 120 | .setId(pluginInfoDo.getId()) |
| 121 | 121 | .setPluginKey(pluginKeyNew) |
| 122 | 122 | .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) |
| ... | ... | @@ -133,25 +133,25 @@ public class PluginInfoServiceImpl implements PluginInfoService { |
| 133 | 133 | @Override |
| 134 | 134 | public void updatePluginStatus(Long id, Integer status) { |
| 135 | 135 | // 1. 校验插件信息是否存在 |
| 136 | - PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); | |
| 136 | + IotPluginInfoDO pluginInfoDo = validatePluginInfoExists(id); | |
| 137 | 137 | |
| 138 | 138 | // 2. 更新插件状态 |
| 139 | 139 | pluginInstanceService.updatePluginStatus(pluginInfoDo, status); |
| 140 | 140 | |
| 141 | 141 | // 3. 更新数据库中的插件状态 |
| 142 | - PluginInfoDO updatedPluginInfo = new PluginInfoDO(); | |
| 142 | + IotPluginInfoDO updatedPluginInfo = new IotPluginInfoDO(); | |
| 143 | 143 | updatedPluginInfo.setId(id); |
| 144 | 144 | updatedPluginInfo.setStatus(status); |
| 145 | 145 | pluginInfoMapper.updateById(updatedPluginInfo); |
| 146 | 146 | } |
| 147 | 147 | |
| 148 | 148 | @Override |
| 149 | - public List<PluginInfoDO> getPluginInfoList() { | |
| 149 | + public List<IotPluginInfoDO> getPluginInfoList() { | |
| 150 | 150 | return pluginInfoMapper.selectList(); |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | 153 | @Override |
| 154 | - public List<PluginInfoDO> getPluginInfoListByStatus(Integer status) { | |
| 154 | + public List<IotPluginInfoDO> getPluginInfoListByStatus(Integer status) { | |
| 155 | 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 | 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 | 4 | import org.springframework.web.multipart.MultipartFile; |
| 5 | 5 | |
| 6 | 6 | /** |
| ... | ... | @@ -8,7 +8,7 @@ import org.springframework.web.multipart.MultipartFile; |
| 8 | 8 | * |
| 9 | 9 | * @author 芋道源码 |
| 10 | 10 | */ |
| 11 | -public interface PluginInstanceService { | |
| 11 | +public interface IotPluginInstanceService { | |
| 12 | 12 | |
| 13 | 13 | // TODO @芋艿:这个是否应该放到 plugin 主动心跳,而是 server 自己心跳 |
| 14 | 14 | /** |
| ... | ... | @@ -28,7 +28,7 @@ public interface PluginInstanceService { |
| 28 | 28 | * |
| 29 | 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 | 44 | * @param pluginInfoDo 插件信息 |
| 45 | 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 | 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 | 3 | import cn.hutool.core.io.FileUtil; |
| 4 | 4 | import cn.hutool.core.net.NetUtil; |
| 5 | 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 | 11 | import cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants; |
| 11 | 12 | import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; |
| 12 | 13 | import jakarta.annotation.Resource; |
| ... | ... | @@ -38,16 +39,20 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU |
| 38 | 39 | @Service |
| 39 | 40 | @Validated |
| 40 | 41 | @Slf4j |
| 41 | -public class PluginInstanceServiceImpl implements PluginInstanceService { | |
| 42 | +public class IotPluginInstanceServiceImpl implements IotPluginInstanceService { | |
| 42 | 43 | |
| 43 | 44 | // TODO @haohao:mac@uuid |
| 44 | 45 | public static final String MAIN_ID = IdUtil.fastSimpleUUID(); |
| 45 | 46 | |
| 47 | + // TODO @haohao:不直接操作,通过 Service 哈 | |
| 46 | 48 | @Resource |
| 47 | - private PluginInfoMapper pluginInfoMapper; | |
| 49 | + private IotPluginInfoMapper pluginInfoMapper; | |
| 48 | 50 | |
| 49 | 51 | @Resource |
| 50 | - private PluginInstanceMapper pluginInstanceMapper; | |
| 52 | + private IotPluginInstanceMapper pluginInstanceMapper; | |
| 53 | + | |
| 54 | + @Resource | |
| 55 | + private DevicePluginProcessIdRedisDAO devicePluginProcessIdRedisDAO; | |
| 51 | 56 | |
| 52 | 57 | @Resource |
| 53 | 58 | private SpringPluginManager pluginManager; |
| ... | ... | @@ -73,7 +78,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { |
| 73 | 78 | } |
| 74 | 79 | |
| 75 | 80 | @Override |
| 76 | - public void deletePluginFile(PluginInfoDO pluginInfoDO) { | |
| 81 | + public void deletePluginFile(IotPluginInfoDO pluginInfoDO) { | |
| 77 | 82 | File file = new File(pluginsDir, pluginInfoDO.getFileName()); |
| 78 | 83 | if (!file.exists()) { |
| 79 | 84 | return; |
| ... | ... | @@ -115,7 +120,7 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { |
| 115 | 120 | } |
| 116 | 121 | |
| 117 | 122 | @Override |
| 118 | - public void updatePluginStatus(PluginInfoDO pluginInfoDo, Integer status) { | |
| 123 | + public void updatePluginStatus(IotPluginInfoDO pluginInfoDo, Integer status) { | |
| 119 | 124 | String pluginKey = pluginInfoDo.getPluginKey(); |
| 120 | 125 | PluginWrapper plugin = pluginManager.getPlugin(pluginKey); |
| 121 | 126 | |
| ... | ... | @@ -147,9 +152,9 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { |
| 147 | 152 | List<PluginWrapper> plugins = pluginManager.getPlugins(); |
| 148 | 153 | |
| 149 | 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 | 159 | // 1.3 获取本机 IP 和 MAC 地址,mac@uuid |
| 155 | 160 | String ip = NetUtil.getLocalhostStr(); |
| ... | ... | @@ -161,34 +166,42 @@ public class PluginInstanceServiceImpl implements PluginInstanceService { |
| 161 | 166 | String pluginKey = plugin.getPluginId(); |
| 162 | 167 | |
| 163 | 168 | // 2.1 查找插件信息 |
| 164 | - PluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey); | |
| 169 | + IotPluginInfoDO pluginInfo = pluginInfoMap.get(pluginKey); | |
| 165 | 170 | if (pluginInfo == null) { |
| 166 | 171 | log.error("插件信息不存在,pluginKey = {}", pluginKey); |
| 167 | 172 | continue; |
| 168 | 173 | } |
| 169 | 174 | |
| 170 | 175 | // 2.2 情况一:如果插件实例不存在,则创建 |
| 171 | - PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId, | |
| 176 | + IotPluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(mainId, | |
| 172 | 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 | 208 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/plugininstance/PluginInstanceMapper.xml
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 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 | 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 | 128 | <version>${revision}</version> |
| 129 | 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 | 138 | <dependency> |
| 133 | 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 | 2 | |
| 3 | 3 | import lombok.extern.slf4j.Slf4j; |
| 4 | 4 | import org.springframework.boot.SpringApplication; |
| 5 | +import org.springframework.boot.WebApplicationType; | |
| 5 | 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 6 | 7 | import org.springframework.context.ConfigurableApplicationContext; |
| 7 | 8 | |
| ... | ... | @@ -10,10 +11,12 @@ import org.springframework.context.ConfigurableApplicationContext; |
| 10 | 11 | */ |
| 11 | 12 | @Slf4j |
| 12 | 13 | @SpringBootApplication |
| 13 | -public class HttpPluginSpringbootApplication { | |
| 14 | +public class IotHttpPluginApplication { | |
| 14 | 15 | |
| 15 | 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 | 21 | // 手动获取 VertxService 并启动 |
| 19 | 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 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO; |
| 9 | 9 | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; |
| 10 | +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils; | |
| 10 | 11 | import io.vertx.core.Handler; |
| 11 | 12 | import io.vertx.ext.web.RequestBody; |
| 12 | 13 | import io.vertx.ext.web.RoutingContext; |
| ... | ... | @@ -50,19 +51,17 @@ public class IotDevicePropertyReportVertxHandler implements Handler<RoutingConte |
| 50 | 51 | String id = jsonData.getStr("id"); |
| 51 | 52 | |
| 52 | 53 | try { |
| 53 | - // TODO @haohao:pluginKey 需要设置 | |
| 54 | 54 | // 设备上线 |
| 55 | 55 | deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) |
| 56 | 56 | new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()) |
| 57 | - .setPluginKey("http") | |
| 58 | - .setReportTime(LocalDateTime.now()) | |
| 57 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | |
| 59 | 58 | .setProductKey(productKey).setDeviceName(deviceName)) |
| 60 | 59 | .setState(IotDeviceStateEnum.ONLINE.getState())); |
| 61 | 60 | |
| 62 | 61 | // 属性上报 |
| 63 | 62 | deviceUpstreamApi.reportDeviceProperty(((IotDevicePropertyReportReqDTO) |
| 64 | 63 | new IotDevicePropertyReportReqDTO().setRequestId(IdUtil.fastSimpleUUID()) |
| 65 | - .setPluginKey("http").setReportTime(LocalDateTime.now()) | |
| 64 | + .setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()) | |
| 66 | 65 | .setProductKey(productKey).setDeviceName(deviceName)) |
| 67 | 66 | .setProperties((Map<String, Object>) requestBody.asJsonObject().getMap().get("properties"))); |
| 68 | 67 | ... | ... |