diff --git a/plugins/enabled.txt b/plugins/enabled.txt index b62400a815..a5ecb93796 100644 --- a/plugins/enabled.txt +++ b/plugins/enabled.txt @@ -1 +1,2 @@ +http-plugin http-plugin@0.0.1 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInstanceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInstanceController.java deleted file mode 100644 index dc6433c7f9..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/PluginInstanceController.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.plugin; - -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstancePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; -import cn.iocoder.yudao.module.iot.service.plugin.PluginInstanceService; -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.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.io.IOException; -import java.util.List; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT 插件实例") -@RestController -@RequestMapping("/iot/plugin-instance") -@Validated -public class PluginInstanceController { - - @Resource - private PluginInstanceService pluginInstanceService; - - @PostMapping("/create") - @Operation(summary = "创建IoT 插件实例") - @PreAuthorize("@ss.hasPermission('iot:plugin-instance:create')") - public CommonResult createPluginInstance(@Valid @RequestBody PluginInstanceSaveReqVO createReqVO) { - return success(pluginInstanceService.createPluginInstance(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新IoT 插件实例") - @PreAuthorize("@ss.hasPermission('iot:plugin-instance:update')") - public CommonResult updatePluginInstance(@Valid @RequestBody PluginInstanceSaveReqVO updateReqVO) { - pluginInstanceService.updatePluginInstance(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除IoT 插件实例") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:plugin-instance:delete')") - public CommonResult deletePluginInstance(@RequestParam("id") Long id) { - pluginInstanceService.deletePluginInstance(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得IoT 插件实例") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:plugin-instance:query')") - public CommonResult getPluginInstance(@RequestParam("id") Long id) { - PluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstance(id); - return success(BeanUtils.toBean(pluginInstance, PluginInstanceRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得IoT 插件实例分页") - @PreAuthorize("@ss.hasPermission('iot:plugin-instance:query')") - public CommonResult> getPluginInstancePage(@Valid PluginInstancePageReqVO pageReqVO) { - PageResult pageResult = pluginInstanceService.getPluginInstancePage(pageReqVO); - return success(BeanUtils.toBean(pageResult, PluginInstanceRespVO.class)); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java index af1ee3e146..514ba4f1f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoRespVO.java @@ -16,9 +16,9 @@ public class PluginInfoRespVO { @ExcelProperty("主键 ID") private Long id; - @Schema(description = "插件包 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") - @ExcelProperty("插件包 ID") - private String pluginId; + @Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") + @ExcelProperty("插件包标识符") + private String pluginKey; @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") @ExcelProperty("插件名称") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java index b35c45abcf..9a98481306 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugin/vo/PluginInfoSaveReqVO.java @@ -10,8 +10,8 @@ public class PluginInfoSaveReqVO { @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") private Long id; - @Schema(description = "插件包id", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") - private String pluginId; + @Schema(description = "插件包标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "24627") + private String pluginKey; @Schema(description = "插件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") private String name; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java index c503a830f2..fbdf2a1dc2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininfo/PluginInfoDO.java @@ -29,12 +29,10 @@ public class PluginInfoDO extends BaseDO { */ @TableId private Long id; - // TODO @haohao:这个是不是改成类似 key 之类的字段哈? - // 回复:默认是 pluginId,可以不用改 /** - * 插件包 ID + * 插件包标识符 */ - private String pluginId; + private String pluginKey; /** * 插件名称 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java index 17f295a55f..507b91f2a0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/plugininstance/PluginInstanceDO.java @@ -1,12 +1,13 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; -// TODO @haohao:一些必要的关联、枚举 + /** * IoT 插件实例 DO * @@ -33,6 +34,8 @@ public class PluginInstanceDO extends BaseDO { private String mainId; /** * 插件id + *

+ * 关联 {@link PluginInfoDO#getId()} */ private Long pluginId; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java index 7eee95509e..249082032d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/plugin/PluginInstanceMapper.java @@ -15,6 +15,12 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface PluginInstanceMapper extends BaseMapperX { + default PluginInstanceDO selectByMainIdAndPluginId(String mainId, Long pluginId) { + return selectOne(new LambdaQueryWrapperX() + .eq(PluginInstanceDO::getMainId, mainId) + .eq(PluginInstanceDO::getPluginId, pluginId)); + } + default PageResult selectPage(PluginInstancePageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .eqIfPresent(PluginInstanceDO::getMainId, reqVO.getMainId()) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 66adc3c9fc..4f1d5e3e29 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.framework.plugin; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; +import cn.iocoder.yudao.module.iot.framework.plugin.listener.CustomPluginStateListener; import lombok.extern.slf4j.Slf4j; import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; @@ -30,7 +31,9 @@ public class UnifiedConfiguration { @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) public SpringPluginManager pluginManager() { log.info("[init][实例化 SpringPluginManager]"); - return new SpringPluginManager(); + SpringPluginManager springPluginManager = new SpringPluginManager(); + springPluginManager.addPluginStateListener(new CustomPluginStateListener()); + return springPluginManager; } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java new file mode 100644 index 0000000000..c0802d7f57 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/listener/CustomPluginStateListener.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.iot.framework.plugin.listener; + +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginStateEvent; +import org.pf4j.PluginStateListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class CustomPluginStateListener implements PluginStateListener { + + @Override + public void pluginStateChanged(PluginStateEvent event) { + // 1. 获取插件ID + String pluginId = event.getPlugin().getPluginId(); + // 2. 获取插件旧状态 + String oldState = event.getOldState().toString(); + // 3. 获取插件新状态 + String newState = event.getPluginState().toString(); + // 4. 打印日志信息 + log.info("插件的状态 '{}' 已更改为 '{}' 至 '{}'", pluginId, oldState, newState); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java new file mode 100644 index 0000000000..ca8398e51c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/plugin/PluginInstancesJob.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.job.plugin; + + +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.service.plugin.PluginInstanceService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +/** + * 插件实例 Job + * + * @author 芋道源码 + */ +@Component +public class PluginInstancesJob { + + @Resource + private PluginInstanceService pluginInstanceService; + + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS) + public void updatePluginInstances() { + TenantUtils.executeIgnore(() -> { + pluginInstanceService.updatePluginInstances(); + }); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java index 40ed4a156f..56b7e95e1f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoService.java @@ -71,9 +71,9 @@ public interface PluginInfoService { void updatePluginStatus(Long id, Integer status); /** - * 获得启用的插件列表 + * 获得插件信息列表 * - * @return 插件列表-插件id + * @return 插件信息列表 */ - List getEnabledPlugins(); + List getPluginInfoList(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java index d9a9eaaff7..4e7f2e9961 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInfoServiceImpl.java @@ -76,7 +76,7 @@ public class PluginInfoServiceImpl implements PluginInfoService { } // 卸载插件 - PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginId()); + PluginWrapper plugin = pluginManager.getPlugin(pluginInfoDO.getPluginKey()); if (plugin != null) { // 查询插件是否是启动状态 if (plugin.getPluginState().equals(PluginState.STARTED)) { @@ -127,30 +127,30 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 2. 获取插件 ID - String pluginId = pluginInfoDo.getPluginId(); + // 2. 获取插件标识 + String pluginKey = pluginInfoDo.getPluginKey(); // 3. 停止并卸载旧的插件 - stopAndUnloadPlugin(pluginId); + stopAndUnloadPlugin(pluginKey); // 4. 上传新的插件文件 - String pluginIdNew = uploadAndLoadNewPlugin(file); + String pluginKeyNew = uploadAndLoadNewPlugin(file); // 5. 更新插件启用状态文件 - updatePluginStatusFile(pluginIdNew, false); + updatePluginStatusFile(pluginKeyNew, false); // 6. 更新插件信息 - updatePluginInfo(pluginInfoDo, pluginIdNew, file); + updatePluginInfo(pluginInfoDo, pluginKeyNew, file); } // 停止并卸载旧的插件 - private void stopAndUnloadPlugin(String pluginId) { - PluginWrapper plugin = pluginManager.getPlugin(pluginId); + private void stopAndUnloadPlugin(String pluginKey) { + PluginWrapper plugin = pluginManager.getPlugin(pluginKey); if (plugin != null) { if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(pluginId); // 停止插件 + pluginManager.stopPlugin(pluginKey); // 停止插件 } - pluginManager.unloadPlugin(pluginId); // 卸载插件 + pluginManager.unloadPlugin(pluginKey); // 卸载插件 } } @@ -175,18 +175,18 @@ public class PluginInfoServiceImpl implements PluginInfoService { } // 更新插件状态文件 - private void updatePluginStatusFile(String pluginIdNew, boolean isEnabled) { + private void updatePluginStatusFile(String pluginKeyNew, boolean isEnabled) { Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; try { - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginKeyNew); if (pluginWrapper == null) { throw exception(PLUGIN_INSTALL_FAILED); } - String pluginInfo = pluginIdNew + "@" + pluginWrapper.getDescriptor().getVersion(); + String pluginInfo = pluginKeyNew + "@" + pluginWrapper.getDescriptor().getVersion(); List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) : new ArrayList<>(); List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) @@ -209,13 +209,13 @@ public class PluginInfoServiceImpl implements PluginInfoService { } // 更新插件信息 - private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginIdNew, MultipartFile file) { - pluginInfoDo.setPluginId(pluginIdNew); + private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginKeyNew, MultipartFile file) { + pluginInfoDo.setPluginKey(pluginKeyNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); pluginInfoDo.setFileName(file.getOriginalFilename()); pluginInfoDo.setScript(""); - PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginIdNew).getDescriptor(); + PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginKeyNew).getDescriptor(); pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription()); pluginInfoDo.setVersion(pluginDescriptor.getVersion()); pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); @@ -232,23 +232,23 @@ public class PluginInfoServiceImpl implements PluginInfoService { throw exception(PLUGIN_STATUS_INVALID); } - // 3. 获取插件ID和插件实例 - String pluginId = pluginInfoDo.getPluginId(); - PluginWrapper plugin = pluginManager.getPlugin(pluginId); + // 3. 获取插件标识和插件实例 + String pluginKey = pluginInfoDo.getPluginKey(); + PluginWrapper plugin = pluginManager.getPlugin(pluginKey); // 4. 根据状态更新插件 if (plugin != null) { // 4.1 如果目标状态是运行且插件未启动,则启动插件 if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { - pluginManager.startPlugin(pluginId); - updatePluginStatusFile(pluginId, true); // 更新插件状态文件为启用 + pluginManager.startPlugin(pluginKey); + updatePluginStatusFile(pluginKey, true); // 更新插件状态文件为启用 } // 4.2 如果目标状态是停止且插件已启动,则停止插件 else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { - pluginManager.stopPlugin(pluginId); - updatePluginStatusFile(pluginId, false); // 更新插件状态文件为禁用 + pluginManager.stopPlugin(pluginKey); + updatePluginStatusFile(pluginKey, false); // 更新插件状态文件为禁用 } } else { // 5. 插件不存在且状态为停止,抛出异常 @@ -263,11 +263,8 @@ public class PluginInfoServiceImpl implements PluginInfoService { } @Override - public List getEnabledPlugins() { - return pluginInfoMapper.selectList().stream() - .filter(pluginInfoDO -> IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) - .map(PluginInfoDO::getPluginId) - .toList(); + public List getPluginInfoList() { + return pluginInfoMapper.selectList(null); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java index 97346f9b73..5655f1d3ad 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceService.java @@ -1,11 +1,5 @@ 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.PluginInstancePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; -import jakarta.validation.Valid; - /** * IoT 插件实例 Service 接口 * @@ -13,42 +7,9 @@ import jakarta.validation.Valid; */ public interface PluginInstanceService { - /** - * 创建IoT 插件实例 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createPluginInstance(@Valid PluginInstanceSaveReqVO createReqVO); - /** * 更新IoT 插件实例 - * - * @param updateReqVO 更新信息 */ - void updatePluginInstance(@Valid PluginInstanceSaveReqVO updateReqVO); - - /** - * 删除IoT 插件实例 - * - * @param id 编号 - */ - void deletePluginInstance(Long id); - - /** - * 获得IoT 插件实例 - * - * @param id 编号 - * @return IoT 插件实例 - */ - PluginInstanceDO getPluginInstance(Long id); - - /** - * 获得IoT 插件实例分页 - * - * @param pageReqVO 分页查询 - * @return IoT 插件实例分页 - */ - PageResult getPluginInstancePage(PluginInstancePageReqVO pageReqVO); + void updatePluginInstances(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java index 7b26948d0a..52d79207b8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/PluginInstanceServiceImpl.java @@ -1,17 +1,19 @@ 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.PluginInstancePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.plugin.vo.PluginInstanceSaveReqVO; +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.IdUtil; +import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininstance.PluginInstanceDO; import cn.iocoder.yudao.module.iot.dal.mysql.plugin.PluginInstanceMapper; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.pf4j.PluginWrapper; +import org.pf4j.spring.SpringPluginManager; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTANCE_NOT_EXISTS; +import java.util.List; /** * IoT 插件实例 Service 实现类 @@ -20,51 +22,79 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PLUGIN_INSTAN */ @Service @Validated +@Slf4j public class PluginInstanceServiceImpl implements PluginInstanceService { + /** + * 主程序id + */ + public static final String MAIN_ID = IdUtil.fastSimpleUUID(); + + @Resource + private PluginInfoService pluginInfoService; @Resource private PluginInstanceMapper pluginInstanceMapper; + @Resource + private SpringPluginManager pluginManager; + + @Value("${server.port:48080}") + private int port; + @Override - public Long createPluginInstance(PluginInstanceSaveReqVO createReqVO) { - // 插入 - PluginInstanceDO pluginInstance = BeanUtils.toBean(createReqVO, PluginInstanceDO.class); - pluginInstanceMapper.insert(pluginInstance); - // 返回 - return pluginInstance.getId(); - } + public void updatePluginInstances() { + // 1. 查询 pf4j 插件列表 + List plugins = pluginManager.getPlugins(); - @Override - public void updatePluginInstance(PluginInstanceSaveReqVO updateReqVO) { - // 校验存在 - validatePluginInstanceExists(updateReqVO.getId()); - // 更新 - PluginInstanceDO updateObj = BeanUtils.toBean(updateReqVO, PluginInstanceDO.class); - pluginInstanceMapper.updateById(updateObj); - } + // 2. 查询插件信息列表 + List pluginInfos = pluginInfoService.getPluginInfoList(); - @Override - public void deletePluginInstance(Long id) { - // 校验存在 - validatePluginInstanceExists(id); - // 删除 - pluginInstanceMapper.deleteById(id); - } + // 动态获取主程序的 IP 和端口 + String mainIp = getLocalIpAddress(); - private void validatePluginInstanceExists(Long id) { - if (pluginInstanceMapper.selectById(id) == null) { - throw exception(PLUGIN_INSTANCE_NOT_EXISTS); + // 3. 遍历插件列表,并保存为插件实例 + for (PluginWrapper plugin : plugins) { + String pluginKey = plugin.getPluginId(); + PluginInfoDO pluginInfo = pluginInfos.stream() + .filter(pluginInfoDO -> pluginInfoDO.getPluginKey().equals(pluginKey)) + .findFirst() + .orElse(null); + + // 4. 如果插件信息不存在,则跳过 + if (pluginInfo == null) { + continue; + } + + // 5. 查询插件实例 + PluginInstanceDO pluginInstance = pluginInstanceMapper.selectByMainIdAndPluginId(MAIN_ID, pluginInfo.getId()); + + // 6. 如果插件实例不存在,则创建 + if (pluginInstance == null) { + pluginInstance = new PluginInstanceDO(); + pluginInstance.setPluginId(pluginInfo.getId()); + pluginInstance.setMainId(MAIN_ID); + pluginInstance.setIp(mainIp); + pluginInstance.setPort(port); + pluginInstance.setHeartbeatAt(System.currentTimeMillis()); + pluginInstanceMapper.insert(pluginInstance); + } else { + // 7. 如果插件实例存在,则更新 + pluginInstance.setHeartbeatAt(System.currentTimeMillis()); + pluginInstanceMapper.updateById(pluginInstance); + } } } - @Override - public PluginInstanceDO getPluginInstance(Long id) { - return pluginInstanceMapper.selectById(id); - } - - @Override - public PageResult getPluginInstancePage(PluginInstancePageReqVO pageReqVO) { - return pluginInstanceMapper.selectPage(pageReqVO); + private String getLocalIpAddress() { + try { + List ipList = NetUtil.localIpv4s().stream() + .filter(ip -> !ip.startsWith("0.0") && !ip.startsWith("127.") && !ip.startsWith("169.254") && !ip.startsWith("255.255.255.255")) + .toList(); + return ipList.isEmpty() ? "127.0.0.1" : ipList.get(0); + } catch (Exception e) { + log.error("获取本地IP地址失败", e); + return "127.0.0.1"; // 默认值 + } } } \ No newline at end of file