reactor:【IoT 物联网】移除 plugin 机制
This commit is contained in:
parent
cf52a16f6c
commit
81cbc61f3c
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.api.device;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
|
import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
|
||||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigImportReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigRespVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigStatusReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginConfigService;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - IoT 插件配置")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/iot/plugin-config")
|
|
||||||
@Validated
|
|
||||||
public class PluginConfigController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IotPluginConfigService pluginConfigService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
|
||||||
@Operation(summary = "创建插件配置")
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:create')")
|
|
||||||
public CommonResult<Long> createPluginConfig(@Valid @RequestBody PluginConfigSaveReqVO createReqVO) {
|
|
||||||
return success(pluginConfigService.createPluginConfig(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
|
||||||
@Operation(summary = "更新插件配置")
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
|
||||||
public CommonResult<Boolean> updatePluginConfig(@Valid @RequestBody PluginConfigSaveReqVO updateReqVO) {
|
|
||||||
pluginConfigService.updatePluginConfig(updateReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
|
||||||
@Operation(summary = "删除插件配置")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:delete')")
|
|
||||||
public CommonResult<Boolean> deletePluginConfig(@RequestParam("id") Long id) {
|
|
||||||
pluginConfigService.deletePluginConfig(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得插件配置")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:query')")
|
|
||||||
public CommonResult<PluginConfigRespVO> getPluginConfig(@RequestParam("id") Long id) {
|
|
||||||
IotPluginConfigDO pluginConfig = pluginConfigService.getPluginConfig(id);
|
|
||||||
return success(BeanUtils.toBean(pluginConfig, PluginConfigRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得插件配置分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:query')")
|
|
||||||
public CommonResult<PageResult<PluginConfigRespVO>> getPluginConfigPage(@Valid PluginConfigPageReqVO pageReqVO) {
|
|
||||||
PageResult<IotPluginConfigDO> pageResult = pluginConfigService.getPluginConfigPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, PluginConfigRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/upload-file")
|
|
||||||
@Operation(summary = "上传插件文件")
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
|
||||||
public CommonResult<Boolean> uploadFile(@Valid PluginConfigImportReqVO reqVO) {
|
|
||||||
pluginConfigService.uploadFile(reqVO.getId(), reqVO.getFile());
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update-status")
|
|
||||||
@Operation(summary = "修改插件状态")
|
|
||||||
@PreAuthorize("@ss.hasPermission('iot:plugin-config:update')")
|
|
||||||
public CommonResult<Boolean> updatePluginConfigStatus(@Valid @RequestBody PluginConfigStatusReqVO reqVO) {
|
|
||||||
pluginConfigService.updatePluginStatus(reqVO.getId(), reqVO.getStatus());
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - IoT 插件上传 Request VO")
|
|
||||||
@Data
|
|
||||||
public class PluginConfigImportReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "插件文件不能为空")
|
|
||||||
private MultipartFile file;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - IoT 插件配置分页 Request VO")
|
|
||||||
@Data
|
|
||||||
public class PluginConfigPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "插件名称", example = "http")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "状态", example = "1")
|
|
||||||
@InEnum(IotPluginStatusEnum.class)
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - IoT 插件配置 Response VO")
|
|
||||||
@Data
|
|
||||||
public class PluginConfigRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "主键 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627")
|
|
||||||
private String pluginKey;
|
|
||||||
|
|
||||||
@Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "描述", example = "你猜")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
|
||||||
private Integer deployType;
|
|
||||||
|
|
||||||
@Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
@Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
@Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "设备插件协议类型")
|
|
||||||
private String protocol;
|
|
||||||
|
|
||||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "插件配置项描述信息")
|
|
||||||
private String configSchema;
|
|
||||||
|
|
||||||
@Schema(description = "插件配置信息")
|
|
||||||
private String config;
|
|
||||||
|
|
||||||
@Schema(description = "插件脚本")
|
|
||||||
private String script;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - IoT 插件配置新增/修改 Request VO")
|
|
||||||
@Data
|
|
||||||
public class PluginConfigSaveReqVO {
|
|
||||||
|
|
||||||
// TODO @haohao:新增的字段有点多,每个都需要哇?
|
|
||||||
|
|
||||||
// TODO @haohao:一些枚举字段,需要加枚举校验。例如说,deployType、status、type 等
|
|
||||||
|
|
||||||
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627")
|
|
||||||
private String pluginKey;
|
|
||||||
|
|
||||||
@Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "描述", example = "你猜")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "部署方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
|
||||||
private Integer deployType;
|
|
||||||
|
|
||||||
@Schema(description = "插件包文件名", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String fileName;
|
|
||||||
|
|
||||||
@Schema(description = "插件版本", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
@Schema(description = "插件类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "设备插件协议类型")
|
|
||||||
private String protocol;
|
|
||||||
|
|
||||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@InEnum(IotPluginStatusEnum.class)
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
@Schema(description = "插件配置项描述信息")
|
|
||||||
private String configSchema;
|
|
||||||
|
|
||||||
@Schema(description = "插件配置信息")
|
|
||||||
private String config;
|
|
||||||
|
|
||||||
@Schema(description = "插件脚本")
|
|
||||||
private String script;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - IoT 插件配置状态 Request VO")
|
|
||||||
@Data
|
|
||||||
public class PluginConfigStatusReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@InEnum(IotPluginStatusEnum.class)
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.instance;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
|
||||||
|
|
||||||
// TODO @haohao:后续需要使用下
|
|
||||||
@Schema(description = "管理后台 - IoT 插件实例分页 Request VO")
|
|
||||||
@Data
|
|
||||||
public class PluginInstancePageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "插件主程序编号", example = "23738")
|
|
||||||
private String mainId;
|
|
||||||
|
|
||||||
@Schema(description = "插件id", example = "26498")
|
|
||||||
private Long pluginId;
|
|
||||||
|
|
||||||
@Schema(description = "插件主程序所在ip")
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
@Schema(description = "插件主程序端口")
|
|
||||||
private Integer port;
|
|
||||||
|
|
||||||
@Schema(description = "心跳时间,心路时间超过30秒需要剔除")
|
|
||||||
private Long heartbeatAt;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime[] createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.instance;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
// TODO @haohao:后续需要使用下
|
|
||||||
@Schema(description = "管理后台 - IoT 插件实例 Response VO")
|
|
||||||
@Data
|
|
||||||
public class PluginInstanceRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "主键编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23864")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "插件主程序id", requiredMode = Schema.RequiredMode.REQUIRED, example = "23738")
|
|
||||||
private String mainId;
|
|
||||||
|
|
||||||
@Schema(description = "插件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "26498")
|
|
||||||
private Long pluginId;
|
|
||||||
|
|
||||||
@Schema(description = "插件主程序所在ip", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private String ip;
|
|
||||||
|
|
||||||
@Schema(description = "插件主程序端口", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Integer port;
|
|
||||||
|
|
||||||
@Schema(description = "心跳时间,心路时间超过30秒需要剔除", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private Long heartbeatAt;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.dal.dataobject.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
|
||||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginTypeEnum;
|
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件配置 DO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@TableName("iot_plugin_config")
|
|
||||||
@KeySequence("iot_plugin_config_seq")
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class IotPluginConfigDO extends TenantBaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主键 ID
|
|
||||||
*/
|
|
||||||
@TableId
|
|
||||||
private Long id;
|
|
||||||
/**
|
|
||||||
* 插件包标识符
|
|
||||||
*/
|
|
||||||
private String pluginKey;
|
|
||||||
/**
|
|
||||||
* 插件名称
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
/**
|
|
||||||
* 插件描述
|
|
||||||
*/
|
|
||||||
private String description;
|
|
||||||
/**
|
|
||||||
* 部署方式
|
|
||||||
* <p>
|
|
||||||
* 枚举 {@link IotPluginDeployTypeEnum}
|
|
||||||
*/
|
|
||||||
private Integer deployType;
|
|
||||||
// TODO @芋艿:如果是外置的插件,fileName 和 version 的选择~
|
|
||||||
/**
|
|
||||||
* 插件包文件名
|
|
||||||
*/
|
|
||||||
private String fileName;
|
|
||||||
/**
|
|
||||||
* 插件版本
|
|
||||||
*/
|
|
||||||
private String version;
|
|
||||||
// TODO @芋艿:type 字典的定义
|
|
||||||
/**
|
|
||||||
* 插件类型
|
|
||||||
* <p>
|
|
||||||
* 枚举 {@link IotPluginTypeEnum}
|
|
||||||
*/
|
|
||||||
private Integer type;
|
|
||||||
/**
|
|
||||||
* 设备插件协议类型
|
|
||||||
*/
|
|
||||||
// TODO @芋艿:枚举字段
|
|
||||||
private String protocol;
|
|
||||||
// TODO @haohao:这个字段,是不是直接用 CommonStatus,开启、禁用;然后插件实例那,online 是否在线
|
|
||||||
/**
|
|
||||||
* 状态
|
|
||||||
* <p>
|
|
||||||
* 枚举 {@link CommonStatusEnum}
|
|
||||||
*/
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
// TODO @芋艿:configSchema、config 示例字段
|
|
||||||
/**
|
|
||||||
* 插件配置项描述信息
|
|
||||||
*/
|
|
||||||
private String configSchema;
|
|
||||||
/**
|
|
||||||
* 插件配置信息
|
|
||||||
*/
|
|
||||||
private String config;
|
|
||||||
|
|
||||||
// TODO @芋艿:script 后续的使用
|
|
||||||
/**
|
|
||||||
* 插件脚本
|
|
||||||
*/
|
|
||||||
private String script;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.dal.dataobject.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件实例 DO
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@TableName("iot_plugin_instance")
|
|
||||||
@KeySequence("iot_plugin_instance_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class IotPluginInstanceDO extends TenantBaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主键
|
|
||||||
*/
|
|
||||||
@TableId
|
|
||||||
private Long id;
|
|
||||||
/**
|
|
||||||
* 插件编号
|
|
||||||
* <p>
|
|
||||||
* 关联 {@link IotPluginConfigDO#getId()}
|
|
||||||
*/
|
|
||||||
private Long pluginId;
|
|
||||||
/**
|
|
||||||
* 插件进程编号
|
|
||||||
*
|
|
||||||
* 一般格式是:hostIp@processId@${uuid}
|
|
||||||
*/
|
|
||||||
private String processId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插件实例所在 IP
|
|
||||||
*/
|
|
||||||
private String hostIp;
|
|
||||||
/**
|
|
||||||
* 设备下行端口
|
|
||||||
*/
|
|
||||||
private Integer downstreamPort;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否在线
|
|
||||||
*/
|
|
||||||
private Boolean online;
|
|
||||||
/**
|
|
||||||
* 在线时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime onlineTime;
|
|
||||||
/**
|
|
||||||
* 离线时间
|
|
||||||
*/
|
|
||||||
private LocalDateTime offlineTime;
|
|
||||||
/**
|
|
||||||
* 心跳时间
|
|
||||||
*
|
|
||||||
* 目的:心路时间超过一定时间后,会被进行下线处理
|
|
||||||
*/
|
|
||||||
private LocalDateTime heartbeatTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.dal.mysql.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mapper
|
|
||||||
public interface IotPluginConfigMapper extends BaseMapperX<IotPluginConfigDO> {
|
|
||||||
|
|
||||||
default PageResult<IotPluginConfigDO> selectPage(PluginConfigPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<IotPluginConfigDO>()
|
|
||||||
.likeIfPresent(IotPluginConfigDO::getName, reqVO.getName())
|
|
||||||
.eqIfPresent(IotPluginConfigDO::getStatus, reqVO.getStatus())
|
|
||||||
.orderByDesc(IotPluginConfigDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
default List<IotPluginConfigDO> selectListByStatusAndDeployType(Integer status, Integer deployType) {
|
|
||||||
return selectList(new LambdaQueryWrapperX<IotPluginConfigDO>()
|
|
||||||
.eq(IotPluginConfigDO::getStatus, status)
|
|
||||||
.eq(IotPluginConfigDO::getDeployType, deployType)
|
|
||||||
.orderByAsc(IotPluginConfigDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
default IotPluginConfigDO selectByPluginKey(String pluginKey) {
|
|
||||||
return selectOne(IotPluginConfigDO::getPluginKey, pluginKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.dal.mysql.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
// TODO @li:参考 IotOtaUpgradeRecordMapper 的写法
|
|
||||||
@Mapper
|
|
||||||
public interface IotPluginInstanceMapper extends BaseMapperX<IotPluginInstanceDO> {
|
|
||||||
|
|
||||||
default IotPluginInstanceDO selectByProcessId(String processId) {
|
|
||||||
return selectOne(IotPluginInstanceDO::getProcessId, processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
default List<IotPluginInstanceDO> selectListByHeartbeatTimeLt(LocalDateTime heartbeatTime) {
|
|
||||||
return selectList(new LambdaQueryWrapper<IotPluginInstanceDO>()
|
|
||||||
.lt(IotPluginInstanceDO::getHeartbeatTime, heartbeatTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.iot.dal.redis;
|
package cn.iocoder.yudao.module.iot.dal.redis;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
|
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IoT Redis Key 枚举类
|
* IoT Redis Key 枚举类
|
||||||
|
@ -43,13 +42,4 @@ public interface RedisKeyConstants {
|
||||||
*/
|
*/
|
||||||
String THING_MODEL_LIST = "iot:thing_model_list";
|
String THING_MODEL_LIST = "iot:thing_model_list";
|
||||||
|
|
||||||
/**
|
|
||||||
* 设备插件的插件进程编号的映射,采用 HASH 结构
|
|
||||||
*
|
|
||||||
* KEY 格式:device_plugin_instance_process_ids
|
|
||||||
* HASH KEY:${deviceKey}
|
|
||||||
* VALUE:插件进程编号,对应 {@link IotPluginInstanceDO#getProcessId()} 字段
|
|
||||||
*/
|
|
||||||
String DEVICE_PLUGIN_INSTANCE_PROCESS_IDS = "iot:device_plugin_instance_process_ids";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.dal.redis.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设备插件的插件进程编号的缓存的 Redis DAO
|
|
||||||
*/
|
|
||||||
@Repository
|
|
||||||
public class DevicePluginProcessIdRedisDAO {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private StringRedisTemplate stringRedisTemplate;
|
|
||||||
|
|
||||||
public void put(String deviceKey, String processId) {
|
|
||||||
stringRedisTemplate.opsForHash().put(RedisKeyConstants.DEVICE_PLUGIN_INSTANCE_PROCESS_IDS, deviceKey, processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String get(String deviceKey) {
|
|
||||||
return (String) stringRedisTemplate.opsForHash().get(RedisKeyConstants.DEVICE_PLUGIN_INSTANCE_PROCESS_IDS, deviceKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.job.plugin;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
|
||||||
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
|
|
||||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件实例离线检查 Job
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class IotPluginInstancesJob implements JobHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插件离线超时时间
|
|
||||||
*
|
|
||||||
* TODO 芋艿:暂定 10 分钟,后续看要不要做配置
|
|
||||||
*/
|
|
||||||
public static final Duration OFFLINE_TIMEOUT = Duration.ofMinutes(10);
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IotPluginInstanceService pluginInstanceService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@TenantJob
|
|
||||||
public String execute(String param) {
|
|
||||||
int count = pluginInstanceService.offlineTimeoutPluginInstance(
|
|
||||||
LocalDateTime.now().minus(OFFLINE_TIMEOUT));
|
|
||||||
return StrUtil.format("离线超时插件实例数量为: {}", count);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,25 +1,23 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.device.control;
|
package cn.iocoder.yudao.module.iot.service.device.control;
|
||||||
|
|
||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*;
|
import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceOtaUpgradeReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO;
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
|
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
|
||||||
import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
|
import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
|
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
|
||||||
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
||||||
import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
|
import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
@ -45,8 +43,6 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IotDeviceService deviceService;
|
private IotDeviceService deviceService;
|
||||||
@Resource
|
|
||||||
private IotPluginInstanceService pluginInstanceService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RestTemplate restTemplate;
|
private RestTemplate restTemplate;
|
||||||
|
@ -118,7 +114,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
|
||||||
downstreamReqVO.getIdentifier());
|
downstreamReqVO.getIdentifier());
|
||||||
IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO()
|
IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO()
|
||||||
.setParams((Map<String, Object>) downstreamReqVO.getData());
|
.setParams((Map<String, Object>) downstreamReqVO.getData());
|
||||||
CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
||||||
|
CommonResult<Boolean> result = null;
|
||||||
|
|
||||||
// 3. 发送设备消息
|
// 3. 发送设备消息
|
||||||
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
||||||
|
@ -187,7 +184,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
|
||||||
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
|
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
|
||||||
IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO()
|
IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO()
|
||||||
.setIdentifiers((List<String>) downstreamReqVO.getData());
|
.setIdentifiers((List<String>) downstreamReqVO.getData());
|
||||||
CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
||||||
|
CommonResult<Boolean> result = null;
|
||||||
|
|
||||||
// 3. 发送设备消息
|
// 3. 发送设备消息
|
||||||
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
||||||
|
@ -224,7 +222,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
|
||||||
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
|
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
|
||||||
IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO()
|
IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO()
|
||||||
.setConfig(config);
|
.setConfig(config);
|
||||||
CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
||||||
|
CommonResult<Boolean> result = null;
|
||||||
|
|
||||||
// 3. 发送设备消息
|
// 3. 发送设备消息
|
||||||
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
||||||
|
@ -261,7 +260,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
|
||||||
String url = String.format("ota/%s/%s/upgrade",
|
String url = String.format("ota/%s/%s/upgrade",
|
||||||
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
|
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
|
||||||
IotDeviceOtaUpgradeReqDTO reqDTO = IotDeviceOtaUpgradeReqDTO.build(data);
|
IotDeviceOtaUpgradeReqDTO reqDTO = IotDeviceOtaUpgradeReqDTO.build(data);
|
||||||
CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
// CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
|
||||||
|
CommonResult<Boolean> result = null;
|
||||||
|
|
||||||
// 3. 发送设备消息
|
// 3. 发送设备消息
|
||||||
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
|
||||||
|
@ -279,43 +279,6 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求插件
|
|
||||||
*
|
|
||||||
* @param url URL
|
|
||||||
* @param reqDTO 请求参数,只需要设置子类的参数!
|
|
||||||
* @param device 设备
|
|
||||||
* @return 响应结果
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "unchecked", "HttpUrlsUsage" })
|
|
||||||
private CommonResult<Boolean> requestPlugin(String url, IotDeviceDownstreamAbstractReqDTO reqDTO,
|
|
||||||
IotDeviceDO device) {
|
|
||||||
// 获得设备对应的插件实例
|
|
||||||
IotPluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstanceByDeviceKey(device.getDeviceKey());
|
|
||||||
if (pluginInstance == null) {
|
|
||||||
throw exception(DEVICE_DOWNSTREAM_FAILED, "设备找不到对应的插件实例");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 补充通用参数
|
|
||||||
reqDTO.setRequestId(IdUtil.fastSimpleUUID());
|
|
||||||
|
|
||||||
// 执行请求
|
|
||||||
ResponseEntity<CommonResult<Boolean>> responseEntity;
|
|
||||||
try {
|
|
||||||
responseEntity = restTemplate.postForEntity(
|
|
||||||
String.format("http://%s:%d/%s", pluginInstance.getHostIp(), pluginInstance.getDownstreamPort(),
|
|
||||||
url),
|
|
||||||
reqDTO, (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
|
|
||||||
Assert.isTrue(responseEntity.getStatusCode().is2xxSuccessful(),
|
|
||||||
"HTTP 状态码不是 2xx,而是" + responseEntity.getStatusCode());
|
|
||||||
Assert.notNull(responseEntity.getBody(), "响应结果不能为空");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error("[requestPlugin][设备({}) url({}) 下行消息失败,请求参数({})]", device.getDeviceKey(), url, reqDTO, ex);
|
|
||||||
throw exception(DEVICE_DOWNSTREAM_FAILED, ExceptionUtil.getMessage(ex));
|
|
||||||
}
|
|
||||||
return responseEntity.getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device, Integer code) {
|
private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device, Integer code) {
|
||||||
// 1. 完善消息
|
// 1. 完善消息
|
||||||
message.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())
|
message.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())
|
||||||
|
|
|
@ -19,7 +19,6 @@ import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
||||||
import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
|
import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
|
||||||
import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
|
import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
|
||||||
import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
|
|
||||||
import cn.iocoder.yudao.module.iot.util.MqttSignUtils;
|
import cn.iocoder.yudao.module.iot.util.MqttSignUtils;
|
||||||
import cn.iocoder.yudao.module.iot.util.MqttSignUtils.MqttSignResult;
|
import cn.iocoder.yudao.module.iot.util.MqttSignUtils.MqttSignResult;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -45,8 +44,6 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
|
||||||
private IotDeviceService deviceService;
|
private IotDeviceService deviceService;
|
||||||
@Resource
|
@Resource
|
||||||
private IotDevicePropertyService devicePropertyService;
|
private IotDevicePropertyService devicePropertyService;
|
||||||
@Resource
|
|
||||||
private IotPluginInstanceService pluginInstanceService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IotDeviceProducer deviceProducer;
|
private IotDeviceProducer deviceProducer;
|
||||||
|
@ -315,7 +312,8 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
|
||||||
|
|
||||||
private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) {
|
private void updateDeviceLastTime(IotDeviceDO device, IotDeviceUpstreamAbstractReqDTO reqDTO) {
|
||||||
// 1. 【异步】记录设备与插件实例的映射
|
// 1. 【异步】记录设备与插件实例的映射
|
||||||
pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId());
|
// pluginInstanceService.updateDevicePluginInstanceProcessIdAsync(device.getDeviceKey(), reqDTO.getProcessId());
|
||||||
|
// TODO @芋艿:需要单独补充下;
|
||||||
|
|
||||||
// 2. 【异步】更新设备的最后时间
|
// 2. 【异步】更新设备的最后时间
|
||||||
devicePropertyService.updateDeviceReportTimeAsync(device.getDeviceKey(), LocalDateTime.now());
|
devicePropertyService.updateDeviceReportTimeAsync(device.getDeviceKey(), LocalDateTime.now());
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginDeployTypeEnum;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件配置 Service 接口
|
|
||||||
*
|
|
||||||
* @author haohao
|
|
||||||
*/
|
|
||||||
public interface IotPluginConfigService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建插件配置
|
|
||||||
*
|
|
||||||
* @param createReqVO 创建信息
|
|
||||||
* @return 编号
|
|
||||||
*/
|
|
||||||
Long createPluginConfig(@Valid PluginConfigSaveReqVO createReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新插件配置
|
|
||||||
*
|
|
||||||
* @param updateReqVO 更新信息
|
|
||||||
*/
|
|
||||||
void updatePluginConfig(@Valid PluginConfigSaveReqVO updateReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除插件配置
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
*/
|
|
||||||
void deletePluginConfig(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得插件配置
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 插件配置
|
|
||||||
*/
|
|
||||||
IotPluginConfigDO getPluginConfig(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得插件配置分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 插件配置分页
|
|
||||||
*/
|
|
||||||
PageResult<IotPluginConfigDO> getPluginConfigPage(PluginConfigPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传插件的 JAR 包
|
|
||||||
*
|
|
||||||
* @param id 插件id
|
|
||||||
* @param file 文件
|
|
||||||
*/
|
|
||||||
void uploadFile(Long id, MultipartFile file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新插件的状态
|
|
||||||
*
|
|
||||||
* @param id 插件id
|
|
||||||
* @param status 状态 {@link IotPluginStatusEnum}
|
|
||||||
*/
|
|
||||||
void updatePluginStatus(Long id, Integer status);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得插件配置列表
|
|
||||||
*
|
|
||||||
* @return 插件配置列表
|
|
||||||
*/
|
|
||||||
List<IotPluginConfigDO> getPluginConfigList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据状态和部署类型获得插件配置列表
|
|
||||||
*
|
|
||||||
* @param status 状态 {@link IotPluginStatusEnum}
|
|
||||||
* @param deployType 部署类型 {@link IotPluginDeployTypeEnum}
|
|
||||||
* @return 插件配置列表
|
|
||||||
*/
|
|
||||||
List<IotPluginConfigDO> getPluginConfigListByStatusAndDeployType(Integer status, Integer deployType);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据插件包标识符获取插件配置
|
|
||||||
*
|
|
||||||
* @param pluginKey 插件包标识符
|
|
||||||
* @return 插件配置
|
|
||||||
*/
|
|
||||||
IotPluginConfigDO getPluginConfigByPluginKey(@NotEmpty(message = "插件包标识符不能为空") String pluginKey);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,187 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.config.PluginConfigSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginConfigMapper;
|
|
||||||
import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件配置 Service 实现类
|
|
||||||
*
|
|
||||||
* @author haohao
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
@Slf4j
|
|
||||||
public class IotPluginConfigServiceImpl implements IotPluginConfigService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IotPluginConfigMapper pluginConfigMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IotPluginInstanceService pluginInstanceService;
|
|
||||||
|
|
||||||
// @Resource
|
|
||||||
// private SpringPluginManager springPluginManager;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long createPluginConfig(PluginConfigSaveReqVO createReqVO) {
|
|
||||||
// 1. 校验插件标识唯一性:确保没有其他配置使用相同的 pluginKey(新建时 id 为 null)
|
|
||||||
validatePluginKeyUnique(null, createReqVO.getPluginKey());
|
|
||||||
IotPluginConfigDO pluginConfig = BeanUtils.toBean(createReqVO, IotPluginConfigDO.class);
|
|
||||||
// 2. 插入插件配置到数据库
|
|
||||||
pluginConfigMapper.insert(pluginConfig);
|
|
||||||
return pluginConfig.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updatePluginConfig(PluginConfigSaveReqVO updateReqVO) {
|
|
||||||
// 1. 校验插件配置是否存在:根据传入 ID 判断记录是否存在
|
|
||||||
validatePluginConfigExists(updateReqVO.getId());
|
|
||||||
// 2. 校验插件标识唯一性:确保更新后的 pluginKey 没有被其他记录占用
|
|
||||||
validatePluginKeyUnique(updateReqVO.getId(), updateReqVO.getPluginKey());
|
|
||||||
// 3. 将更新请求对象转换为插件配置数据对象
|
|
||||||
IotPluginConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotPluginConfigDO.class);
|
|
||||||
pluginConfigMapper.updateById(updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验插件标识唯一性
|
|
||||||
*
|
|
||||||
* @param id 当前插件配置的 ID(如果为 null 则说明为新建操作)
|
|
||||||
* @param pluginKey 待校验的插件标识
|
|
||||||
*/
|
|
||||||
private void validatePluginKeyUnique(Long id, String pluginKey) {
|
|
||||||
// 1. 根据 pluginKey 从数据库中查询已有的插件配置
|
|
||||||
IotPluginConfigDO pluginConfig = pluginConfigMapper.selectByPluginKey(pluginKey);
|
|
||||||
// 2. 如果查询到记录且记录的 ID 与当前 ID 不相同,则认为存在重复,抛出异常
|
|
||||||
if (pluginConfig != null && !pluginConfig.getId().equals(id)) {
|
|
||||||
throw exception(PLUGIN_CONFIG_KEY_DUPLICATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deletePluginConfig(Long id) {
|
|
||||||
// 1. 校验存在
|
|
||||||
IotPluginConfigDO pluginConfigDO = validatePluginConfigExists(id);
|
|
||||||
// 2. 未开启状态,才允许删除
|
|
||||||
if (IotPluginStatusEnum.RUNNING.getStatus().equals(pluginConfigDO.getStatus())) {
|
|
||||||
throw exception(PLUGIN_CONFIG_DELETE_FAILED_RUNNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 卸载插件
|
|
||||||
pluginInstanceService.stopAndUnloadPlugin(pluginConfigDO.getPluginKey());
|
|
||||||
// 4. 删除插件文件
|
|
||||||
pluginInstanceService.deletePluginFile(pluginConfigDO);
|
|
||||||
|
|
||||||
// 5. 删除插件配置
|
|
||||||
pluginConfigMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验插件配置是否存在
|
|
||||||
*
|
|
||||||
* @param id 插件配置编号
|
|
||||||
* @return 插件配置
|
|
||||||
*/
|
|
||||||
private IotPluginConfigDO validatePluginConfigExists(Long id) {
|
|
||||||
IotPluginConfigDO pluginConfig = pluginConfigMapper.selectById(id);
|
|
||||||
if (pluginConfig == null) {
|
|
||||||
throw exception(PLUGIN_CONFIG_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
return pluginConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IotPluginConfigDO getPluginConfig(Long id) {
|
|
||||||
return pluginConfigMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<IotPluginConfigDO> getPluginConfigPage(PluginConfigPageReqVO pageReqVO) {
|
|
||||||
return pluginConfigMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void uploadFile(Long id, MultipartFile file) {
|
|
||||||
// 1. 校验插件配置是否存在
|
|
||||||
IotPluginConfigDO pluginConfigDO = validatePluginConfigExists(id);
|
|
||||||
|
|
||||||
// 2.1 停止并卸载旧的插件
|
|
||||||
pluginInstanceService.stopAndUnloadPlugin(pluginConfigDO.getPluginKey());
|
|
||||||
// 2.2 上传新的插件文件,更新插件启用状态文件
|
|
||||||
String pluginKeyNew = pluginInstanceService.uploadAndLoadNewPlugin(file);
|
|
||||||
|
|
||||||
// 3. 校验 file 相关参数,是否完整
|
|
||||||
validatePluginConfigFile(pluginKeyNew);
|
|
||||||
|
|
||||||
// 4. 更新插件配置
|
|
||||||
// IotPluginConfigDO updatedPluginConfig = new IotPluginConfigDO()
|
|
||||||
// .setId(pluginConfigDO.getId())
|
|
||||||
// .setPluginKey(pluginKeyNew)
|
|
||||||
// .setStatus(IotPluginStatusEnum.STOPPED.getStatus()) // TODO @haohao:这个状态,是不是非 stop 哈?
|
|
||||||
// .setFileName(file.getOriginalFilename())
|
|
||||||
// .setScript("") // TODO @haohao:这个设置为 "" 会不会覆盖数据里的哈?应该从插件里读取?未来?
|
|
||||||
// .setConfigSchema(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription())
|
|
||||||
// .setVersion(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getVersion())
|
|
||||||
// .setDescription(springPluginManager.getPlugin(pluginKeyNew).getDescriptor().getPluginDescription());
|
|
||||||
// pluginConfigMapper.updateById(updatedPluginConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验 file 相关参数
|
|
||||||
*
|
|
||||||
* @param pluginKeyNew 插件标识符
|
|
||||||
*/
|
|
||||||
private void validatePluginConfigFile(String pluginKeyNew) {
|
|
||||||
// TODO @haohao:校验 file 相关参数,是否完整,类似:version 之类是不是可以解析到
|
|
||||||
// PluginWrapper plugin = springPluginManager.getPlugin(pluginKeyNew);
|
|
||||||
// if (plugin == null) {
|
|
||||||
// throw exception(PLUGIN_INSTALL_FAILED);
|
|
||||||
// }
|
|
||||||
// if (plugin.getDescriptor().getVersion() == null) {
|
|
||||||
// throw exception(PLUGIN_INSTALL_FAILED);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updatePluginStatus(Long id, Integer status) {
|
|
||||||
// 1. 校验插件配置是否存在
|
|
||||||
IotPluginConfigDO pluginConfigDo = validatePluginConfigExists(id);
|
|
||||||
|
|
||||||
// 2. 更新插件状态
|
|
||||||
pluginInstanceService.updatePluginStatus(pluginConfigDo, status);
|
|
||||||
|
|
||||||
// 3. 更新数据库中的插件状态
|
|
||||||
pluginConfigMapper.updateById(new IotPluginConfigDO().setId(id).setStatus(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IotPluginConfigDO> getPluginConfigList() {
|
|
||||||
return pluginConfigMapper.selectList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IotPluginConfigDO> getPluginConfigListByStatusAndDeployType(Integer status, Integer deployType) {
|
|
||||||
return pluginConfigMapper.selectListByStatusAndDeployType(status, deployType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IotPluginConfigDO getPluginConfigByPluginKey(String pluginKey) {
|
|
||||||
return pluginConfigMapper.selectByPluginKey(pluginKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.plugin;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件实例 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface IotPluginInstanceService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 离线超时插件实例
|
|
||||||
*
|
|
||||||
* @param maxHeartbeatTime 最大心跳时间
|
|
||||||
*/
|
|
||||||
int offlineTimeoutPluginInstance(LocalDateTime maxHeartbeatTime);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止并卸载插件
|
|
||||||
*
|
|
||||||
* @param pluginKey 插件标识符
|
|
||||||
*/
|
|
||||||
void stopAndUnloadPlugin(String pluginKey);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除插件文件
|
|
||||||
*
|
|
||||||
* @param pluginConfigDO 插件配置
|
|
||||||
*/
|
|
||||||
void deletePluginFile(IotPluginConfigDO pluginConfigDO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传并加载新的插件文件
|
|
||||||
*
|
|
||||||
* @param file 插件文件
|
|
||||||
* @return 插件标识符
|
|
||||||
*/
|
|
||||||
String uploadAndLoadNewPlugin(MultipartFile file);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新插件状态
|
|
||||||
*
|
|
||||||
* @param pluginConfigDO 插件配置
|
|
||||||
* @param status 新状态
|
|
||||||
*/
|
|
||||||
void updatePluginStatus(IotPluginConfigDO pluginConfigDO, Integer status);
|
|
||||||
|
|
||||||
// ========== 设备与插件的映射操作 ==========
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新设备对应的插件实例的进程编号
|
|
||||||
*
|
|
||||||
* @param deviceKey 设备 Key
|
|
||||||
* @param processId 进程编号
|
|
||||||
*/
|
|
||||||
void updateDevicePluginInstanceProcessIdAsync(String deviceKey, String processId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得设备对应的插件实例
|
|
||||||
*
|
|
||||||
* @param deviceKey 设备 Key
|
|
||||||
* @return 插件实例
|
|
||||||
*/
|
|
||||||
IotPluginInstanceDO getPluginInstanceByDeviceKey(String deviceKey);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.iot.service.plugin;
|
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginConfigDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.mysql.plugin.IotPluginInstanceMapper;
|
|
||||||
import cn.iocoder.yudao.module.iot.dal.redis.plugin.DevicePluginProcessIdRedisDAO;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IoT 插件实例 Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@Validated
|
|
||||||
@Slf4j
|
|
||||||
public class IotPluginInstanceServiceImpl implements IotPluginInstanceService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IotPluginInstanceMapper pluginInstanceMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DevicePluginProcessIdRedisDAO devicePluginProcessIdRedisDAO;
|
|
||||||
|
|
||||||
// @Resource
|
|
||||||
// private SpringPluginManager pluginManager;
|
|
||||||
|
|
||||||
@Value("${pf4j.pluginsDir}")
|
|
||||||
private String pluginsDir;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int offlineTimeoutPluginInstance(LocalDateTime maxHeartbeatTime) {
|
|
||||||
List<IotPluginInstanceDO> list = pluginInstanceMapper.selectListByHeartbeatTimeLt(maxHeartbeatTime);
|
|
||||||
if (CollUtil.isEmpty(list)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新插件实例为离线
|
|
||||||
int count = 0;
|
|
||||||
for (IotPluginInstanceDO instance : list) {
|
|
||||||
pluginInstanceMapper.updateById(IotPluginInstanceDO.builder().id(instance.getId())
|
|
||||||
.online(false).offlineTime(LocalDateTime.now()).build());
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopAndUnloadPlugin(String pluginKey) {
|
|
||||||
// PluginWrapper plugin = pluginManager.getPlugin(pluginKey);
|
|
||||||
// if (plugin == null) {
|
|
||||||
// log.warn("插件不存在或已卸载: {}", pluginKey);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (plugin.getPluginState().equals(PluginState.STARTED)) {
|
|
||||||
// pluginManager.stopPlugin(pluginKey); // 停止插件
|
|
||||||
// log.info("已停止插件: {}", pluginKey);
|
|
||||||
// }
|
|
||||||
// pluginManager.unloadPlugin(pluginKey); // 卸载插件
|
|
||||||
// log.info("已卸载插件: {}", pluginKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deletePluginFile(IotPluginConfigDO pluginConfigDO) {
|
|
||||||
File file = new File(pluginsDir, pluginConfigDO.getFileName());
|
|
||||||
if (!file.exists()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕
|
|
||||||
if (!file.delete()) {
|
|
||||||
log.error("[deletePluginFile][删除插件文件({}) 失败]", pluginConfigDO.getFileName());
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.error("[deletePluginFile][删除插件文件({}) 失败]", pluginConfigDO.getFileName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String uploadAndLoadNewPlugin(MultipartFile file) {
|
|
||||||
// String pluginKeyNew;
|
|
||||||
// // TODO @haohao:多节点,是不是要上传 s3 之类的存储器;然后定时去加载
|
|
||||||
// Path pluginsPath = Paths.get(pluginsDir);
|
|
||||||
// try {
|
|
||||||
// FileUtil.mkdir(pluginsPath.toFile()); // 创建插件目录
|
|
||||||
// String filename = file.getOriginalFilename();
|
|
||||||
// if (filename != null) {
|
|
||||||
// Path jarPath = pluginsPath.resolve(filename);
|
|
||||||
// Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件
|
|
||||||
//// pluginKeyNew = pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件
|
|
||||||
//// log.info("已加载插件: {}", pluginKeyNew);
|
|
||||||
// } else {
|
|
||||||
// throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED);
|
|
||||||
// }
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// log.error("[uploadAndLoadNewPlugin][上传插件文件失败]", e);
|
|
||||||
// throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED, e);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("[uploadAndLoadNewPlugin][加载插件失败]", e);
|
|
||||||
// throw exception(ErrorCodeConstants.PLUGIN_INSTALL_FAILED, e);
|
|
||||||
// }
|
|
||||||
// return pluginKeyNew;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updatePluginStatus(IotPluginConfigDO pluginConfigDO, Integer status) {
|
|
||||||
// String pluginKey = pluginConfigDO.getPluginKey();
|
|
||||||
// PluginWrapper plugin = pluginManager.getPlugin(pluginKey);
|
|
||||||
//
|
|
||||||
// if (plugin == null) {
|
|
||||||
// // 插件不存在且状态为停止,抛出异常
|
|
||||||
// if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginConfigDO.getStatus())) {
|
|
||||||
// throw exception(ErrorCodeConstants.PLUGIN_STATUS_INVALID);
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 启动插件
|
|
||||||
// if (status.equals(IotPluginStatusEnum.RUNNING.getStatus())
|
|
||||||
// && plugin.getPluginState() != PluginState.STARTED) {
|
|
||||||
// try {
|
|
||||||
// pluginManager.startPlugin(pluginKey);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("[updatePluginStatus][启动插件({}) 失败]", pluginKey, e);
|
|
||||||
// throw exception(ErrorCodeConstants.PLUGIN_START_FAILED, e);
|
|
||||||
// }
|
|
||||||
// log.info("已启动插件: {}", pluginKey);
|
|
||||||
// }
|
|
||||||
// // 停止插件
|
|
||||||
// else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus())
|
|
||||||
// && plugin.getPluginState() == PluginState.STARTED) {
|
|
||||||
// try {
|
|
||||||
// pluginManager.stopPlugin(pluginKey);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("[updatePluginStatus][停止插件({}) 失败]", pluginKey, e);
|
|
||||||
// throw exception(ErrorCodeConstants.PLUGIN_STOP_FAILED, e);
|
|
||||||
// }
|
|
||||||
// log.info("已停止插件: {}", pluginKey);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== 设备与插件的映射操作 ==========
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDevicePluginInstanceProcessIdAsync(String deviceKey, String processId) {
|
|
||||||
devicePluginProcessIdRedisDAO.put(deviceKey, processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IotPluginInstanceDO getPluginInstanceByDeviceKey(String deviceKey) {
|
|
||||||
String processId = devicePluginProcessIdRedisDAO.get(deviceKey);
|
|
||||||
if (StrUtil.isEmpty(processId)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return pluginInstanceMapper.selectByProcessId(processId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -198,28 +198,4 @@ justauth:
|
||||||
cache:
|
cache:
|
||||||
type: REDIS
|
type: REDIS
|
||||||
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
|
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
|
||||||
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
|
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
|
||||||
|
|
||||||
|
|
||||||
--- #################### iot相关配置 TODO 芋艿:再瞅瞅 ####################
|
|
||||||
iot:
|
|
||||||
emq:
|
|
||||||
# 账号
|
|
||||||
username: anhaohao
|
|
||||||
# 密码
|
|
||||||
password: ahh@123456
|
|
||||||
# 主机地址
|
|
||||||
hostUrl: tcp://chaojiniu.top:1883
|
|
||||||
# 客户端Id,不能相同,采用随机数 ${random.value}
|
|
||||||
client-id: ${random.int}
|
|
||||||
# 默认主题
|
|
||||||
default-topic: test
|
|
||||||
# 保持连接
|
|
||||||
keepalive: 60
|
|
||||||
# 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
|
|
||||||
clearSession: true
|
|
||||||
|
|
||||||
|
|
||||||
# 插件配置
|
|
||||||
pf4j:
|
|
||||||
pluginsDir: ${user.home}/plugins # 插件目录
|
|
|
@ -265,9 +265,4 @@ justauth:
|
||||||
cache:
|
cache:
|
||||||
type: REDIS
|
type: REDIS
|
||||||
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
|
prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
|
||||||
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
|
timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
|
||||||
|
|
||||||
--- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 ####################
|
|
||||||
pf4j:
|
|
||||||
# pluginsDir: /tmp/
|
|
||||||
pluginsDir: ../plugins
|
|
|
@ -315,7 +315,4 @@ yudao:
|
||||||
message-bus:
|
message-bus:
|
||||||
type: rocketmq # 消息总线的类型
|
type: rocketmq # 消息总线的类型
|
||||||
|
|
||||||
debug: false
|
debug: false
|
||||||
# 插件配置 TODO 芋艿:【IOT】需要处理下
|
|
||||||
pf4j:
|
|
||||||
pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录
|
|
Loading…
Reference in New Issue