diff --git a/src/main/java/com/ycwl/basic/controller/pc/DefaultConfigController.java b/src/main/java/com/ycwl/basic/controller/pc/DefaultConfigController.java index 8ddfe5c..f301993 100644 --- a/src/main/java/com/ycwl/basic/controller/pc/DefaultConfigController.java +++ b/src/main/java/com/ycwl/basic/controller/pc/DefaultConfigController.java @@ -1,7 +1,7 @@ package com.ycwl.basic.controller.pc; import com.ycwl.basic.integration.scenic.dto.config.DefaultConfigDTO; -import com.ycwl.basic.integration.scenic.service.DefaultConfigIntegrationService; +import com.ycwl.basic.integration.scenic.service.ScenicDefaultConfigIntegrationService; import com.ycwl.basic.utils.ApiConst; import com.ycwl.basic.utils.ApiResponse; import lombok.RequiredArgsConstructor; @@ -20,7 +20,7 @@ import java.util.List; @RequiredArgsConstructor public class DefaultConfigController { - private final DefaultConfigIntegrationService defaultConfigIntegrationService; + private final ScenicDefaultConfigIntegrationService scenicDefaultConfigIntegrationService; /** * 获取默认配置列表 @@ -29,7 +29,7 @@ public class DefaultConfigController { public ApiResponse> listDefaultConfigs() { log.info("获取默认配置列表"); try { - List configs = defaultConfigIntegrationService.listDefaultConfigs(); + List configs = scenicDefaultConfigIntegrationService.listDefaultConfigs(); return ApiResponse.success(configs); } catch (Exception e) { log.error("获取默认配置列表失败", e); @@ -44,7 +44,7 @@ public class DefaultConfigController { public ApiResponse getDefaultConfig(@PathVariable String configKey) { log.info("获取默认配置, configKey: {}", configKey); try { - DefaultConfigDTO config = defaultConfigIntegrationService.getDefaultConfig(configKey); + DefaultConfigDTO config = scenicDefaultConfigIntegrationService.getDefaultConfig(configKey); return ApiResponse.success(config); } catch (Exception e) { log.error("获取默认配置失败, configKey: {}", configKey, e); @@ -59,7 +59,7 @@ public class DefaultConfigController { public ApiResponse createDefaultConfig(@RequestBody DefaultConfigDTO request) { log.info("创建默认配置, configKey: {}", request.getConfigKey()); try { - DefaultConfigDTO config = defaultConfigIntegrationService.createDefaultConfig(request); + DefaultConfigDTO config = scenicDefaultConfigIntegrationService.createDefaultConfig(request); return ApiResponse.success(config); } catch (Exception e) { log.error("创建默认配置失败, configKey: {}", request.getConfigKey(), e); @@ -75,7 +75,7 @@ public class DefaultConfigController { @RequestBody DefaultConfigDTO request) { log.info("更新默认配置, configKey: {}", configKey); try { - DefaultConfigDTO config = defaultConfigIntegrationService.updateDefaultConfig(configKey, request); + DefaultConfigDTO config = scenicDefaultConfigIntegrationService.updateDefaultConfig(configKey, request); return ApiResponse.success(config); } catch (Exception e) { log.error("更新默认配置失败, configKey: {}", configKey, e); @@ -90,7 +90,7 @@ public class DefaultConfigController { public ApiResponse deleteDefaultConfig(@PathVariable String configKey) { log.info("删除默认配置, configKey: {}", configKey); try { - defaultConfigIntegrationService.deleteDefaultConfig(configKey); + scenicDefaultConfigIntegrationService.deleteDefaultConfig(configKey); return ApiResponse.buildResponse(ApiConst.Code.CODE_SUCCESS.code(), null, "删除成功"); } catch (Exception e) { log.error("删除默认配置失败, configKey: {}", configKey, e); diff --git a/src/main/java/com/ycwl/basic/controller/pc/DeviceV2Controller.java b/src/main/java/com/ycwl/basic/controller/pc/DeviceV2Controller.java index 7649fdb..d97ecf7 100644 --- a/src/main/java/com/ycwl/basic/controller/pc/DeviceV2Controller.java +++ b/src/main/java/com/ycwl/basic/controller/pc/DeviceV2Controller.java @@ -1,6 +1,7 @@ package com.ycwl.basic.controller.pc; import com.ycwl.basic.integration.device.dto.config.*; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.device.dto.device.*; import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService; import com.ycwl.basic.integration.device.service.DeviceIntegrationService; @@ -35,7 +36,7 @@ public class DeviceV2Controller { * 设备V2核心信息分页列表 */ @GetMapping("/") - public ApiResponse listDevices(@RequestParam(defaultValue = "1") Integer page, + public ApiResponse> listDevices(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) String name, @RequestParam(required = false) String no, @@ -51,7 +52,7 @@ public class DeviceV2Controller { } try { - DeviceV2ListResponse response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, isActive, scenicId); + PageResponse response = deviceIntegrationService.listDevices(page, pageSize, name, no, type, isActive, scenicId); return ApiResponse.success(response); } catch (Exception e) { log.error("分页查询设备核心信息列表失败", e); @@ -63,7 +64,7 @@ public class DeviceV2Controller { * 设备V2带配置信息分页列表 */ @GetMapping("/with-config") - public ApiResponse listDevicesWithConfig(@RequestParam(defaultValue = "1") Integer page, + public ApiResponse> listDevicesWithConfig(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) String name, @RequestParam(required = false) String no, @@ -79,7 +80,7 @@ public class DeviceV2Controller { } try { - DeviceV2WithConfigListResponse response = deviceIntegrationService.listDevicesWithConfig(page, pageSize, name, no, type, isActive, scenicId); + PageResponse response = deviceIntegrationService.listDevicesWithConfig(page, pageSize, name, no, type, isActive, scenicId); return ApiResponse.success(response); } catch (Exception e) { log.error("分页查询设备带配置信息列表失败", e); @@ -431,12 +432,12 @@ public class DeviceV2Controller { * 获取景区IPC设备列表 */ @GetMapping("/scenic/{scenicId}/ipc") - public ApiResponse getScenicIpcDevices(@PathVariable Long scenicId, + public ApiResponse> getScenicIpcDevices(@PathVariable Long scenicId, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize) { log.info("获取景区IPC设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize); try { - DeviceV2ListResponse response = deviceIntegrationService.getScenicIpcDevices(scenicId, page, pageSize); + PageResponse response = deviceIntegrationService.getScenicIpcDevices(scenicId, page, pageSize); return ApiResponse.success(response); } catch (Exception e) { log.error("获取景区IPC设备列表失败, scenicId: {}", scenicId, e); @@ -448,12 +449,12 @@ public class DeviceV2Controller { * 获取景区激活设备列表 */ @GetMapping("/scenic/{scenicId}/active") - public ApiResponse getScenicActiveDevices(@PathVariable Long scenicId, + public ApiResponse> getScenicActiveDevices(@PathVariable Long scenicId, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize) { log.info("获取景区激活设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize); try { - DeviceV2ListResponse response = deviceIntegrationService.getScenicActiveDevices(scenicId, page, pageSize); + PageResponse response = deviceIntegrationService.getScenicActiveDevices(scenicId, page, pageSize); return ApiResponse.success(response); } catch (Exception e) { log.error("获取景区激活设备列表失败, scenicId: {}", scenicId, e); @@ -465,12 +466,12 @@ public class DeviceV2Controller { * 获取景区所有设备列表 */ @GetMapping("/scenic/{scenicId}/all") - public ApiResponse getScenicAllDevices(@PathVariable Long scenicId, + public ApiResponse> getScenicAllDevices(@PathVariable Long scenicId, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize) { log.info("获取景区所有设备列表, scenicId: {}, page: {}, pageSize: {}", scenicId, page, pageSize); try { - DeviceV2ListResponse response = deviceIntegrationService.listDevices(page, pageSize, null, null, null, null, scenicId); + PageResponse response = deviceIntegrationService.listDevices(page, pageSize, null, null, null, null, scenicId); return ApiResponse.success(response); } catch (Exception e) { log.error("获取景区所有设备列表失败, scenicId: {}", scenicId, e); diff --git a/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerConfigV2Controller.java b/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerConfigV2Controller.java new file mode 100644 index 0000000..334eda1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerConfigV2Controller.java @@ -0,0 +1,196 @@ +package com.ycwl.basic.controller.pc; + +import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest; +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; +import com.ycwl.basic.integration.render.service.RenderWorkerConfigIntegrationService; +import com.ycwl.basic.utils.ApiResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 渲染工作器配置管理 V2 版本控制器 + * 基于 zt-render-worker 微服务标准接口实现 + * + * @author Claude Code + * @date 2025-09-06 + */ +@Slf4j +@RestController +@RequestMapping("/api/render/worker/config/v2") +@RequiredArgsConstructor +public class RenderWorkerConfigV2Controller { + + private final RenderWorkerConfigIntegrationService configIntegrationService; + + /** + * 获取工作器所有配置 + * + * @param workerId 工作器ID + * @return 工作器配置列表 + */ + @GetMapping("/{workerId}") + public ApiResponse> getWorkerConfigs(@PathVariable Long workerId) { + log.info("获取渲染工作器配置列表, workerId: {}", workerId); + + try { + List configs = configIntegrationService.getWorkerConfigs(workerId); + return ApiResponse.success(configs); + } catch (Exception e) { + log.error("获取渲染工作器配置列表失败, workerId: {}", workerId, e); + return ApiResponse.fail("获取渲染工作器配置列表失败: " + e.getMessage()); + } + } + + /** + * 获取工作器平铺配置 + * + * @param workerId 工作器ID + * @return 平铺配置Map + */ + @GetMapping("/{workerId}/flat") + public ApiResponse> getWorkerFlatConfig(@PathVariable Long workerId) { + log.info("获取渲染工作器平铺配置, workerId: {}", workerId); + + try { + Map flatConfig = configIntegrationService.getWorkerFlatConfig(workerId); + return ApiResponse.success(flatConfig); + } catch (Exception e) { + log.error("获取渲染工作器平铺配置失败, workerId: {}", workerId, e); + return ApiResponse.fail("获取渲染工作器平铺配置失败: " + e.getMessage()); + } + } + + /** + * 根据配置键获取特定配置 + * + * @param workerId 工作器ID + * @param configKey 配置键 + * @return 配置信息 + */ + @GetMapping("/{workerId}/key/{configKey}") + public ApiResponse getWorkerConfigByKey(@PathVariable Long workerId, + @PathVariable String configKey) { + log.info("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey); + + try { + RenderWorkerConfigV2DTO config = configIntegrationService.getWorkerConfigByKey(workerId, configKey); + return ApiResponse.success(config); + } catch (Exception e) { + log.error("根据配置键获取渲染工作器配置失败, workerId: {}, configKey: {}", workerId, configKey, e); + return ApiResponse.fail("根据配置键获取渲染工作器配置失败: " + e.getMessage()); + } + } + + /** + * 创建工作器配置 + * + * @param workerId 工作器ID + * @param config 配置信息 + * @return 创建的配置信息 + */ + @PostMapping("/{workerId}") + public ApiResponse createWorkerConfig(@PathVariable Long workerId, + @Valid @RequestBody RenderWorkerConfigV2DTO config) { + log.info("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey()); + + try { + RenderWorkerConfigV2DTO result = configIntegrationService.createWorkerConfig(workerId, config); + return ApiResponse.success(result); + } catch (Exception e) { + log.error("创建渲染工作器配置失败, workerId: {}", workerId, e); + return ApiResponse.fail("创建渲染工作器配置失败: " + e.getMessage()); + } + } + + /** + * 更新工作器配置 + * + * @param workerId 工作器ID + * @param configId 配置ID + * @param updates 更新内容 + * @return 操作结果 + */ + @PutMapping("/{workerId}/{configId}") + public ApiResponse updateWorkerConfig(@PathVariable Long workerId, + @PathVariable Long configId, + @Valid @RequestBody Map updates) { + log.info("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId); + + try { + configIntegrationService.updateWorkerConfig(workerId, configId, updates); + return ApiResponse.success(null); + } catch (Exception e) { + log.error("更新渲染工作器配置失败, workerId: {}, configId: {}", workerId, configId, e); + return ApiResponse.fail("更新渲染工作器配置失败: " + e.getMessage()); + } + } + + /** + * 删除工作器配置 + * + * @param workerId 工作器ID + * @param configId 配置ID + * @return 操作结果 + */ + @DeleteMapping("/{workerId}/{configId}") + public ApiResponse deleteWorkerConfig(@PathVariable Long workerId, + @PathVariable Long configId) { + log.info("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId); + + try { + configIntegrationService.deleteWorkerConfig(workerId, configId); + return ApiResponse.success(null); + } catch (Exception e) { + log.error("删除渲染工作器配置失败, workerId: {}, configId: {}", workerId, configId, e); + return ApiResponse.fail("删除渲染工作器配置失败: " + e.getMessage()); + } + } + + /** + * 批量更新工作器配置 + * + * @param workerId 工作器ID + * @param request 批量配置请求 + * @return 操作结果 + */ + @PostMapping("/{workerId}/batch") + public ApiResponse batchUpdateWorkerConfigs(@PathVariable Long workerId, + @Valid @RequestBody BatchRenderWorkerConfigRequest request) { + log.info("批量更新渲染工作器配置, workerId: {}, configCount: {}", + workerId, request.getConfigs() != null ? request.getConfigs().size() : 0); + + try { + configIntegrationService.batchUpdateWorkerConfigs(workerId, request); + return ApiResponse.success(null); + } catch (Exception e) { + log.error("批量更新渲染工作器配置失败, workerId: {}", workerId, e); + return ApiResponse.fail("批量更新渲染工作器配置失败: " + e.getMessage()); + } + } + + /** + * 批量平铺更新工作器配置 + * + * @param workerId 工作器ID + * @param flatConfigs 平铺配置Map + * @return 操作结果 + */ + @PostMapping("/{workerId}/flat-batch") + public ApiResponse batchFlatUpdateWorkerConfigs(@PathVariable Long workerId, + @Valid @RequestBody Map flatConfigs) { + log.info("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}", workerId, flatConfigs.size()); + + try { + configIntegrationService.batchFlatUpdateWorkerConfigs(workerId, flatConfigs); + return ApiResponse.success(null); + } catch (Exception e) { + log.error("批量平铺更新渲染工作器配置失败, workerId: {}", workerId, e); + return ApiResponse.fail("批量平铺更新渲染工作器配置失败: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerController.java b/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerController.java deleted file mode 100644 index d200d86..0000000 --- a/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerController.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.ycwl.basic.controller.pc; - -import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity; -import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery; -import com.ycwl.basic.service.pc.RenderWorkerService; -import com.ycwl.basic.utils.ApiResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -/** - * @Author:longbinbin - * @Date:2024/12/3 14:59 - */ -@RestController -@RequestMapping("/api/renderWorker/v1") -// 渲染机管理 -public class RenderWorkerController { - - @Autowired - private RenderWorkerService renderWorkerService; - - // 分页查询渲染机 - @PostMapping("/page") - public ApiResponse pageQuery(@RequestBody RenderWorkerReqQuery renderWorkerReqQuery){ - return renderWorkerService.pageQuery(renderWorkerReqQuery); - } - // 渲染机列表查询 - @PostMapping("/list") - public ApiResponse list(@RequestBody RenderWorkerReqQuery renderWorkerReqQuery){ - return renderWorkerService.list(renderWorkerReqQuery); - } - // 渲染机详情查询 - @GetMapping("/detail/{id}") - public ApiResponse detail(@PathVariable Long id){ - return renderWorkerService.detail(id); - } - - // 渲染机新增 - @PostMapping("/add") - public ApiResponse add(@RequestBody RenderWorkerEntity renderWorker){ - return renderWorkerService.add(renderWorker); - } - - // 渲染机删除 - @DeleteMapping("/delete/{id}") - public ApiResponse deleteById(@PathVariable Long id){ - return renderWorkerService.deleteById(id); - } - - // 渲染机修改 - @PostMapping("/update") - public ApiResponse update(@RequestBody RenderWorkerEntity renderWorker){ - return renderWorkerService.update(renderWorker); - } - - // 渲染机修改状态 - @PutMapping("/updateStatus/{id}") - public ApiResponse updateStatus(@PathVariable Long id) { - return renderWorkerService.updateStatus(id); - } -} diff --git a/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerV2Controller.java b/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerV2Controller.java new file mode 100644 index 0000000..910478b --- /dev/null +++ b/src/main/java/com/ycwl/basic/controller/pc/RenderWorkerV2Controller.java @@ -0,0 +1,142 @@ +package com.ycwl.basic.controller.pc; + +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.render.dto.worker.CreateRenderWorkerRequest; +import com.ycwl.basic.integration.render.dto.worker.RenderWorkerV2DTO; +import com.ycwl.basic.integration.render.dto.worker.UpdateRenderWorkerRequest; +import com.ycwl.basic.integration.render.service.RenderWorkerIntegrationService; +import com.ycwl.basic.utils.ApiResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +/** + * 渲染工作器管理 V2 版本控制器 + * 基于 zt-render-worker 微服务标准接口实现 + * + * @author Claude Code + * @date 2025-09-06 + */ +@Slf4j +@RestController +@RequestMapping("/api/render/worker/v2") +@RequiredArgsConstructor +public class RenderWorkerV2Controller { + + private final RenderWorkerIntegrationService renderWorkerIntegrationService; + + /** + * 分页查询渲染工作器列表 + * + * @param page 页码,从1开始 + * @param pageSize 每页大小,默认10,最大100 + * @param isEnabled 是否启用(0-禁用,1-启用) + * @param name 工作器名称(模糊搜索) + * @return 分页查询结果 + */ + @GetMapping + public ApiResponse> listWorkers( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Integer isEnabled, + @RequestParam(required = false) String name) { + + log.info("分页查询渲染工作器列表, page: {}, pageSize: {}, isEnabled: {}, name: {}", + page, pageSize, isEnabled, name); + + // 参数验证:限制pageSize最大值为100 + if (pageSize > 100) { + pageSize = 100; + } + + try { + PageResponse result = renderWorkerIntegrationService.listWorkers( + page, pageSize, isEnabled, name); + return ApiResponse.success(result); + } catch (Exception e) { + log.error("分页查询渲染工作器列表失败", e); + return ApiResponse.fail("分页查询渲染工作器列表失败: " + e.getMessage()); + } + } + + /** + * 根据ID获取渲染工作器详情 + * + * @param id 工作器ID + * @return 工作器详情 + */ + @GetMapping("/{id}") + public ApiResponse getWorker(@PathVariable Long id) { + log.info("获取渲染工作器详情, id: {}", id); + + try { + RenderWorkerV2DTO worker = renderWorkerIntegrationService.getWorker(id); + return ApiResponse.success(worker); + } catch (Exception e) { + log.error("获取渲染工作器详情失败, id: {}", id, e); + return ApiResponse.fail("获取渲染工作器详情失败: " + e.getMessage()); + } + } + + /** + * 创建渲染工作器 + * + * @param request 创建请求 + * @return 创建的工作器信息 + */ + @PostMapping + public ApiResponse createWorker(@Valid @RequestBody CreateRenderWorkerRequest request) { + log.info("创建渲染工作器, name: {}, key: {}, isActive: {}", + request.getName(), request.getKey(), request.getIsActive()); + + try { + RenderWorkerV2DTO worker = renderWorkerIntegrationService.createWorker(request); + return ApiResponse.success(worker); + } catch (Exception e) { + log.error("创建渲染工作器失败", e); + return ApiResponse.fail("创建渲染工作器失败: " + e.getMessage()); + } + } + + /** + * 更新渲染工作器 + * + * @param id 工作器ID + * @param request 更新请求 + * @return 操作结果 + */ + @PutMapping("/{id}") + public ApiResponse updateWorker(@PathVariable Long id, + @Valid @RequestBody UpdateRenderWorkerRequest request) { + log.info("更新渲染工作器, id: {}, name: {}, isActive: {}", + id, request.getName(), request.getIsActive()); + + try { + renderWorkerIntegrationService.updateWorker(id, request); + return ApiResponse.success(null); + } catch (Exception e) { + log.error("更新渲染工作器失败, id: {}", id, e); + return ApiResponse.fail("更新渲染工作器失败: " + e.getMessage()); + } + } + + /** + * 删除渲染工作器 + * + * @param id 工作器ID + * @return 操作结果 + */ + @DeleteMapping("/{id}") + public ApiResponse deleteWorker(@PathVariable Long id) { + log.info("删除渲染工作器, id: {}", id); + + try { + renderWorkerIntegrationService.deleteWorker(id); + return ApiResponse.success(null); + } catch (Exception e) { + log.error("删除渲染工作器失败, id: {}", id, e); + return ApiResponse.fail("删除渲染工作器失败: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/controller/pc/ScenicV2Controller.java b/src/main/java/com/ycwl/basic/controller/pc/ScenicV2Controller.java index 52b7f8b..15a3e42 100644 --- a/src/main/java/com/ycwl/basic/controller/pc/ScenicV2Controller.java +++ b/src/main/java/com/ycwl/basic/controller/pc/ScenicV2Controller.java @@ -9,9 +9,8 @@ import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterPageResponse; import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest; import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse; import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest; import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService; @@ -52,7 +51,7 @@ public class ScenicV2Controller { * 景区V2核心信息分页列表 */ @GetMapping("/") - public ApiResponse listScenics(@RequestParam(defaultValue = "1") Integer page, + public ApiResponse> listScenics(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) Integer status, @RequestParam(required = false) String name) { @@ -64,7 +63,7 @@ public class ScenicV2Controller { } try { - ScenicV2ListResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name); + PageResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name); return ApiResponse.success(response); } catch (Exception e) { log.error("分页查询景区核心信息列表失败", e); @@ -76,7 +75,7 @@ public class ScenicV2Controller { * 景区V2带配置信息分页列表 */ @GetMapping("/with-config") - public ApiResponse listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page, + public ApiResponse> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) Integer status, @RequestParam(required = false) String name) { @@ -88,7 +87,7 @@ public class ScenicV2Controller { } try { - ScenicV2WithConfigListResponse response = scenicIntegrationService.listScenicsWithConfig(page, pageSize, status, name); + PageResponse response = scenicIntegrationService.listScenicsWithConfig(page, pageSize, status, name); return ApiResponse.success(response); } catch (Exception e) { log.error("分页查询景区带配置信息列表失败", e); @@ -178,11 +177,11 @@ public class ScenicV2Controller { * 只支持根据状态筛选 */ @GetMapping("/list") - public ApiResponse listScenicsByStatus(@RequestParam(required = false) Integer status) { + public ApiResponse> listScenicsByStatus(@RequestParam(required = false) Integer status) { log.info("查询景区列表, status: {}", status); try { // 默认查询1000条数据,第1页 - ScenicV2ListResponse scenics = scenicIntegrationService.listScenics(1, 1000, status, null); + PageResponse scenics = scenicIntegrationService.listScenics(1, 1000, status, null); return ApiResponse.success(scenics); } catch (Exception e) { log.error("查询景区列表失败, status: {}", status, e); diff --git a/src/main/java/com/ycwl/basic/integration/CLAUDE.md b/src/main/java/com/ycwl/basic/integration/CLAUDE.md index 2eb1a1e..0047ced 100644 --- a/src/main/java/com/ycwl/basic/integration/CLAUDE.md +++ b/src/main/java/com/ycwl/basic/integration/CLAUDE.md @@ -23,6 +23,7 @@ The integration package (`com.ycwl.basic.integration`) is responsible for extern Currently implemented: - **Scenic Integration** (`com.ycwl.basic.integration.scenic`): ZT-Scenic microservice integration - **Device Integration** (`com.ycwl.basic.integration.device`): ZT-Device microservice integration +- **Render Worker Integration** (`com.ycwl.basic.integration.render`): ZT-Render-Worker microservice integration ### Integration Pattern @@ -226,10 +227,12 @@ fallbackService.clearAllFallbackCache("zt-scenic"); #### Feign Clients - **DeviceV2Client**: Main device operations (CRUD, filtering, listing) - **DeviceConfigV2Client**: Device configuration management +- **DefaultConfigClient**: Default configuration management #### Services - **DeviceIntegrationService**: High-level device operations (with automatic fallback) - **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback) +- **DefaultConfigIntegrationService**: Default configuration management (with automatic fallback) #### Configuration ```yaml @@ -241,6 +244,13 @@ integration: readTimeout: 10000 retryEnabled: false maxRetries: 3 + render: + enabled: true + serviceName: zt-render-worker + connectTimeout: 5000 + readTimeout: 10000 + retryEnabled: false + maxRetries: 3 ``` ### Usage Examples @@ -369,6 +379,355 @@ fallbackService.clearFallbackCache("zt-device", "device:1001"); fallbackService.clearAllFallbackCache("zt-device"); ``` +## Default Configuration Management (ZT-Device Microservice) + +### Key Components + +#### Default Configuration API +The zt-device microservice provides a comprehensive default configuration management API at `/api/device/config/v2/defaults` that allows: +- Creating and managing default configuration templates +- Batch operations with conflict detection +- Configuration type validation and enforcement +- Usage tracking and analytics + +#### Feign Client +- **DefaultConfigClient**: Default configuration management operations + +#### Service +- **DefaultConfigIntegrationService**: High-level default configuration operations (with automatic fallback for queries) + +### Usage Examples + +#### Basic Default Configuration Operations (with Automatic Fallback) +```java +@Autowired +private DefaultConfigIntegrationService defaultConfigService; + +// Get default configuration list (automatically falls back to cache on failure) +PageResponse configList = defaultConfigService.listDefaultConfigs(1, 10); +log.info("Default configs: total={}, current page={}", + configList.getData().getTotal(), configList.getData().getList().size()); + +// Get specific default configuration (automatically falls back to cache on failure) +DefaultConfigResponse config = defaultConfigService.getDefaultConfig("resolution"); +if (config != null) { + log.info("Default resolution: {}", config.getConfigValue()); +} + +// Create new default configuration (direct operation, fails immediately on error) +DefaultConfigRequest newConfig = new DefaultConfigRequest(); +newConfig.setConfigKey("bitrate"); +newConfig.setConfigValue("2000000"); +newConfig.setConfigType("int"); +newConfig.setDescription("Default video bitrate in bps"); +boolean created = defaultConfigService.createDefaultConfig(newConfig); + +// Update default configuration with conflict detection (direct operation) +Map updates = new HashMap<>(); +updates.put("configValue", "4000000"); +updates.put("description", "Updated default bitrate - high quality"); +DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig("bitrate", updates); + +if (conflict != null) { + log.warn("Configuration update conflict detected:"); + log.warn(" Key: {}, Type: {}, Affected devices: {}", + conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount()); + log.warn(" Current type: {}, Proposed type: {}", + conflict.getCurrentType(), conflict.getProposedType()); + + // Handle conflict - show affected device IDs + if (conflict.getConflictDevices() != null) { + log.warn(" Conflicted device IDs: {}", conflict.getConflictDevices()); + } +} else { + log.info("Configuration updated successfully without conflicts"); +} + +// Delete default configuration (direct operation, fails immediately on error) +boolean deleted = defaultConfigService.deleteDefaultConfig("bitrate"); +``` + +#### Batch Default Configuration Operations +```java +// Using Builder Pattern for batch operations +BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder() + .addVideoConfig("1920x1080", 30, "H265") // Add video configuration group + .addNetworkConfig("192.168.1.100", 554, "RTSP") // Add network configuration group + .addConfig("recording_enabled", "true", "bool", "Enable recording by default") + .addConfig("storage_retention", "30", "int", "Storage retention in days") + .addConfig("quality_profile", "high", "string", "Default video quality profile") + .build(); + +// Execute batch update (direct operation, no fallback) +BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(batchRequest); + +// Process batch results +log.info("Batch operation completed: {} success, {} failed", result.getSuccess(), result.getFailed()); + +// Handle conflicts +if (result.getConflicts() != null && !result.getConflicts().isEmpty()) { + log.warn("Configuration conflicts detected:"); + for (DefaultConfigConflict conflict : result.getConflicts()) { + log.warn(" Key: {}, Type: {}, Devices affected: {}", + conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount()); + } +} + +// Review processed items +if (result.getProcessedItems() != null) { + result.getProcessedItems().forEach(item -> { + if ("success".equals(item.getStatus())) { + log.info("✅ {} {} successfully (type: {})", + item.getConfigKey(), item.getAction(), item.getFinalType()); + } else { + log.warn("❌ {} failed: {}", item.getConfigKey(), item.getMessage()); + } + }); +} + +// Handle errors +if (result.getErrors() != null && !result.getErrors().isEmpty()) { + result.getErrors().forEach(error -> log.error("Batch operation error: {}", error)); +} +``` + +#### Device Type Specific Default Configuration Patterns +```java +// Create IPC camera default configurations +BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder() + .addVideoConfig("1920x1080", 25, "H264") // Standard HD resolution + .addConfig("night_vision", "true", "bool", "Enable night vision") + .addConfig("motion_detection", "true", "bool", "Enable motion detection") + .addConfig("stream_profile", "main", "string", "Default stream profile") + .addConfig("ptz_enabled", "false", "bool", "PTZ control enabled") + .addConfig("audio_enabled", "true", "bool", "Audio recording enabled") + .build(); + +// Create NVR default configurations +BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder() + .addConfig("max_channels", "16", "int", "Maximum supported channels") + .addConfig("storage_mode", "continuous", "string", "Recording storage mode") + .addConfig("backup_enabled", "true", "bool", "Enable automatic backup") + .addConfig("raid_level", "5", "int", "Default RAID level") + .addConfig("disk_quota", "80", "int", "Disk usage quota percentage") + .build(); + +// Apply device-type-specific defaults +BatchDefaultConfigResponse ipcResult = defaultConfigService.batchUpdateDefaultConfigs(ipcDefaults); +BatchDefaultConfigResponse nvrResult = defaultConfigService.batchUpdateDefaultConfigs(nvrDefaults); + +log.info("IPC defaults: {} success, {} failed", ipcResult.getSuccess(), ipcResult.getFailed()); +log.info("NVR defaults: {} success, {} failed", nvrResult.getSuccess(), nvrResult.getFailed()); +``` + +#### Configuration Validation and Management Patterns +```java +// Validate system configuration completeness +PageResponse allDefaults = defaultConfigService.listDefaultConfigs(1, 100); + +// Check for required default configurations +String[] requiredDefaults = { + "resolution", "frameRate", "codec", "bitrate", + "protocol", "port", "username", "password" +}; + +Map configStatus = new HashMap<>(); +for (String required : requiredDefaults) { + boolean exists = allDefaults.getData().getList().stream() + .anyMatch(config -> required.equals(config.getConfigKey())); + configStatus.put(required, exists); + + if (!exists) { + log.warn("Missing required default configuration: {}", required); + } +} + +// Generate configuration completeness report +long totalConfigs = allDefaults.getData().getTotal(); +long completeConfigs = configStatus.values().stream().mapToLong(exists -> exists ? 1 : 0).sum(); +double completeness = (double) completeConfigs / requiredDefaults.length * 100; + +log.info("Configuration completeness: {:.1f}% ({}/{} required configs present)", + completeness, completeConfigs, requiredDefaults.length); +log.info("Total default configurations in system: {}", totalConfigs); + +// Analyze configuration type distribution +Map typeDistribution = allDefaults.getData().getList().stream() + .collect(Collectors.groupingBy( + DefaultConfigResponse::getConfigType, + Collectors.counting() + )); + +log.info("Configuration type distribution: {}", typeDistribution); + +// Find most and least used configurations +DefaultConfigResponse mostUsed = allDefaults.getData().getList().stream() + .max(Comparator.comparing(DefaultConfigResponse::getUsageCount)) + .orElse(null); + +DefaultConfigResponse leastUsed = allDefaults.getData().getList().stream() + .min(Comparator.comparing(DefaultConfigResponse::getUsageCount)) + .orElse(null); + +if (mostUsed != null) { + log.info("Most used default config: {} (used {} times)", + mostUsed.getConfigKey(), mostUsed.getUsageCount()); +} +if (leastUsed != null) { + log.info("Least used default config: {} (used {} times)", + leastUsed.getConfigKey(), leastUsed.getUsageCount()); +} +``` + +#### Advanced Batch Configuration with Error Handling +```java +// Complex batch operation with comprehensive error handling +try { + BatchDefaultConfigRequest complexBatch = defaultConfigService.createBatchConfigBuilder() + .addVideoConfig("3840x2160", 60, "H265") // 4K configuration + .addConfig("hdr_enabled", "true", "bool", "HDR video support") + .addConfig("ai_analysis", "enabled", "string", "AI analysis features") + .addConfig("edge_processing", "true", "bool", "Edge computing enabled") + .addConfig("cloud_sync", "auto", "string", "Cloud synchronization mode") + .build(); + + BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(complexBatch); + + // Detailed result analysis + if (result.getSuccess() == complexBatch.getConfigs().size()) { + log.info("✅ All {} configurations processed successfully", result.getSuccess()); + } else if (result.getSuccess() > 0) { + log.warn("⚠️ Partial success: {} succeeded, {} failed", result.getSuccess(), result.getFailed()); + + // Analyze what succeeded vs failed + if (result.getProcessedItems() != null) { + Map statusCounts = result.getProcessedItems().stream() + .collect(Collectors.groupingBy( + ProcessedConfigItem::getStatus, + Collectors.counting() + )); + log.info("Processing breakdown: {}", statusCounts); + } + } else { + log.error("❌ All configurations failed to process"); + } + + // Handle different types of conflicts + if (result.getConflicts() != null) { + Map> conflictsByType = result.getConflicts().stream() + .collect(Collectors.groupingBy(DefaultConfigConflict::getConflictType)); + + conflictsByType.forEach((conflictType, conflicts) -> { + log.warn("Conflict type '{}' affects {} configurations:", conflictType, conflicts.size()); + conflicts.forEach(conflict -> + log.warn(" {} affects {} devices", conflict.getConfigKey(), conflict.getDeviceCount()) + ); + }); + } + +} catch (Exception e) { + log.error("Batch default configuration operation failed", e); + // Implement retry logic or fallback behavior as needed +} +``` + +#### Fallback Cache Management for Default Configurations +```java +@Autowired +private IntegrationFallbackService fallbackService; + +// Check fallback cache status for default configurations +boolean hasDefaultListCache = fallbackService.hasFallbackCache("zt-device", "defaults:list:1:10"); +boolean hasSpecificConfigCache = fallbackService.hasFallbackCache("zt-device", "defaults:config:resolution"); + +// Get cache statistics +IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-device"); +log.info("Default config fallback cache: {} items, TTL: {} days", + stats.getTotalCacheCount(), stats.getFallbackTtlDays()); + +// Clear specific default configuration cache +fallbackService.clearFallbackCache("zt-device", "defaults:config:resolution"); + +// Clear all default configuration caches +fallbackService.clearAllFallbackCache("zt-device"); +``` + +### Default Configuration Types and Common Keys + +#### Video Configuration Defaults +- `resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720") +- `frameRate`: Video frame rate (integer: 15, 25, 30, 60) +- `codec`: Video codec ("H264", "H265", "MJPEG") +- `bitrate`: Video bitrate in bps (integer) +- `quality`: Video quality level ("low", "medium", "high", "ultra") + +#### Network Configuration Defaults +- `protocol`: Network protocol ("RTSP", "HTTP", "ONVIF") +- `port`: Network port (integer: 554, 80, 8080) +- `timeout`: Connection timeout in seconds (integer) +- `retry_count`: Maximum retry attempts (integer) + +#### Authentication Defaults +- `username`: Default username (string) +- `password`: Default password (string) +- `auth_method`: Authentication method ("basic", "digest", "none") + +#### Storage and Recording Defaults +- `storage_path`: Default storage path (string) +- `recording_enabled`: Enable recording (boolean) +- `retention_days`: Storage retention period (integer) +- `max_file_size`: Maximum file size in MB (integer) + +#### Feature Control Defaults +- `motion_detection`: Enable motion detection (boolean) +- `night_vision`: Enable night vision (boolean) +- `audio_enabled`: Enable audio recording (boolean) +- `ptz_enabled`: Enable PTZ control (boolean) +- `ai_analysis`: AI analysis features ("enabled", "disabled", "auto") + +### Error Handling and Responses + +#### HTTP Status Codes +- **200 OK**: Configuration retrieved/updated successfully +- **201 Created**: New configuration created successfully +- **202 Accepted**: Operation completed with conflicts (check response for details) +- **400 Bad Request**: Invalid request parameters or validation errors +- **404 Not Found**: Configuration key not found +- **409 Conflict**: Configuration conflicts prevent operation (includes conflict details) + +#### Conflict Resolution +When updating default configurations that are actively used by devices, the API performs conflict detection: + +1. **Type Conflicts**: Changing configuration type when devices use different types +2. **Value Validation**: Ensuring new values are compatible with existing device configurations +3. **Dependency Conflicts**: Checking for configuration dependencies and relationships + +The response includes detailed conflict information to help resolve issues: +```java +// Example conflict handling +DefaultConfigConflict conflict = updateResult; +if (conflict != null) { + switch (conflict.getConflictType()) { + case "TYPE_MISMATCH": + log.warn("Type conflict: {} devices using '{}' type, proposed '{}'type", + conflict.getDeviceCount(), conflict.getCurrentType(), conflict.getProposedType()); + // Handle type conversion or device updates + break; + + case "VALUE_RANGE": + log.warn("Value range conflict for key '{}' affects {} devices", + conflict.getConfigKey(), conflict.getDeviceCount()); + // Handle value range adjustments + break; + + case "DEPENDENCY": + log.warn("Dependency conflict detected for '{}'", conflict.getConfigKey()); + // Handle dependency resolution + break; + } +} +``` + ### Enhanced Batch Configuration API Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules. @@ -424,6 +783,23 @@ Each processed item includes: - **IPC**: IP Camera devices for video monitoring - **CUSTOM**: Custom device types for sensors, controllers, etc. +### Testing Default Configuration Integration + +```bash +# Run default configuration integration tests +mvn test -Dtest=DefaultConfigIntegrationServiceTest + +# Run all device integration tests (including default configs) +mvn test -Dtest="com.ycwl.basic.integration.device.*Test" + +# Enable example runner in application-dev.yml +integration: + device: + example: + default-config: + enabled: true +``` + ### Common Configuration Keys - `ip_address`: Device IP address - `resolution`: Video resolution (e.g., "1920x1080", "3840x2160") @@ -534,6 +910,11 @@ integration: enabled: true # Enable fallback for device service ttlDays: 5 # Custom TTL for device (shorter due to dynamic data) # cachePrefix: "device:fallback:" # Optional custom prefix + + render: + enabled: true # Enable fallback for render worker service + ttlDays: 7 # Custom TTL for render worker (medium due to stable worker data) + # cachePrefix: "render:fallback:" # Optional custom prefix # Service configurations scenic: @@ -587,6 +968,205 @@ class ScenicIntegrationServiceTest { ### Integration Testing Use `@SpringBootTest` with test profiles and mock external services. +## Render Worker Integration (ZT-Render-Worker Microservice) + +### Key Components + +#### Feign Clients +- **RenderWorkerV2Client**: Main render worker operations (CRUD, listing) +- **RenderWorkerConfigV2Client**: Render worker configuration management + +#### Services +- **RenderWorkerIntegrationService**: High-level render worker operations (with automatic fallback) +- **RenderWorkerConfigIntegrationService**: Configuration management (with automatic fallback) + +#### Configuration +```yaml +integration: + render: + enabled: true + serviceName: zt-render-worker + connectTimeout: 5000 + readTimeout: 10000 + retryEnabled: false + maxRetries: 3 +``` + +### Usage Examples + +#### Basic Render Worker Operations (with Automatic Fallback) +```java +@Autowired +private RenderWorkerIntegrationService renderWorkerService; + +// Get render worker basic info (automatically falls back to cache on failure) +RenderWorkerV2DTO worker = renderWorkerService.getWorker(workerId); + +// Get render worker with configuration (automatically falls back to cache on failure) +RenderWorkerV2WithConfigDTO workerWithConfig = renderWorkerService.getWorkerWithConfig(workerId); + +// Get render worker by key (automatically falls back to cache on failure) +RenderWorkerV2DTO workerByKey = renderWorkerService.getWorkerByKey("video-renderer-001"); + +// Get render worker with config by key (automatically falls back to cache on failure) +RenderWorkerV2WithConfigDTO workerWithConfigByKey = renderWorkerService.getWorkerWithConfigByKey("video-renderer-001"); + +// Create new render worker (direct operation, fails immediately on error) +CreateRenderWorkerRequest request = new CreateRenderWorkerRequest(); +request.setName("Video Renderer"); +request.setKey("video-renderer-001"); +request.setIsActive(1); +RenderWorkerV2DTO newWorker = renderWorkerService.createWorker(request); + +// Update render worker (direct operation, fails immediately on error) +UpdateRenderWorkerRequest updateRequest = new UpdateRenderWorkerRequest(); +updateRequest.setName("Updated Video Renderer"); +renderWorkerService.updateWorker(workerId, updateRequest); + +// Delete render worker (direct operation, fails immediately on error) +renderWorkerService.deleteWorker(workerId); + +// List render workers (no fallback for list operations) +List workers = renderWorkerService.listWorkers(1, 10, 1, null); + +// List render workers with config (no fallback for list operations) +List workersWithConfig = + renderWorkerService.listWorkersWithConfig(1, 10, 1, null); +``` + +#### Configuration Management (with Automatic Fallback) +```java +@Autowired +private RenderWorkerConfigIntegrationService configService; + +// Get worker configurations (with fallback) +List configs = configService.getWorkerConfigs(workerId); + +// Get flat configuration (automatically falls back to cache on failure) +Map flatConfig = configService.getWorkerFlatConfig(workerId); + +// Get specific configuration by key (with fallback) +RenderWorkerConfigV2DTO config = configService.getWorkerConfigByKey(workerId, "render_quality"); + +// Create configuration (direct operation, fails immediately on error) +RenderWorkerConfigV2DTO newConfig = new RenderWorkerConfigV2DTO(); +newConfig.setConfigKey("max_concurrent_tasks"); +newConfig.setConfigValue("4"); +newConfig.setConfigType("int"); +newConfig.setDescription("Maximum concurrent render tasks"); +newConfig.setIsActive(1); +RenderWorkerConfigV2DTO created = configService.createWorkerConfig(workerId, newConfig); + +// Update configuration (direct operation, fails immediately on error) +Map updates = new HashMap<>(); +updates.put("configValue", "8"); +configService.updateWorkerConfig(workerId, configId, updates); + +// Delete configuration (direct operation, fails immediately on error) +configService.deleteWorkerConfig(workerId, configId); +``` + +#### Enhanced Batch Configuration API +```java +// Using Builder Pattern for batch configuration +BatchRenderWorkerConfigRequest request = configService.createBatchConfigBuilder() + .addRenderConfig("high", "mp4", "1920x1080") // Render settings + .addPerformanceConfig(8, 3600) // Performance settings + .addConfig("output_path", "/data/renders", "string", "Output directory") + .addConfig("enable_gpu", "true", "bool", "Enable GPU acceleration") + .build(); + +// Batch update configurations (direct operation, fails immediately on error) +configService.batchUpdateWorkerConfigs(workerId, request); + +// Batch flat update configurations (direct operation, fails immediately on error) +Map flatUpdates = new HashMap<>(); +flatUpdates.put("render_quality", "ultra"); +flatUpdates.put("max_concurrent_tasks", 12); +flatUpdates.put("enable_preview", true); +configService.batchFlatUpdateWorkerConfigs(workerId, flatUpdates); +``` + +#### Render Worker Management Patterns +```java +// Create and configure render worker in one operation +CreateRenderWorkerRequest workerRequest = new CreateRenderWorkerRequest(); +workerRequest.setName("4K Video Renderer"); +workerRequest.setKey("4k-video-renderer"); +RenderWorkerV2DTO worker = renderWorkerService.createWorker(workerRequest); + +// Configure the worker for 4K video rendering +BatchRenderWorkerConfigRequest config = configService.createBatchConfigBuilder() + .addRenderConfig("ultra", "mp4", "3840x2160") + .addPerformanceConfig(4, 7200) // 4 concurrent tasks, 2 hour timeout + .addConfig("gpu_memory_limit", "8192", "int", "GPU memory limit in MB") + .addConfig("codec", "h265", "string", "Video codec") + .addConfig("bitrate", "50000", "int", "Video bitrate in kbps") + .build(); +configService.batchUpdateWorkerConfigs(worker.getId(), config); + +// Monitor worker configuration completeness (with automatic fallback) +Map workerConfig = configService.getWorkerFlatConfig(worker.getId()); +boolean hasRenderConfig = workerConfig.containsKey("render_quality"); +boolean hasPerformanceConfig = workerConfig.containsKey("max_concurrent_tasks"); +// log configuration status... + +// Get all active workers for monitoring +List activeWorkers = + renderWorkerService.listWorkersWithConfig(1, 100, 1, null); + +// Check worker health and configuration +for (RenderWorkerV2WithConfigDTO activeWorker : activeWorkers) { + Map config = activeWorker.getConfig(); + boolean isConfigured = config.containsKey("render_quality") && + config.containsKey("max_concurrent_tasks"); + // log worker status... +} +``` + +#### Fallback Cache Management for Render Workers +```java +@Autowired +private IntegrationFallbackService fallbackService; + +// Check fallback cache status +boolean hasWorkerCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:1001"); +boolean hasWorkerByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:video-renderer-001"); +boolean hasConfigCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:flat:config:1001"); +boolean hasConfigByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:config:video-renderer-001"); + +// Get cache statistics +IntegrationFallbackService.FallbackCacheStats stats = + fallbackService.getFallbackCacheStats("zt-render-worker"); +log.info("Render worker fallback cache: {} items, TTL: {} days", + stats.getTotalCacheCount(), stats.getFallbackTtlDays()); + +// Clear specific cache +fallbackService.clearFallbackCache("zt-render-worker", "worker:1001"); + +// Clear all render worker caches +fallbackService.clearAllFallbackCache("zt-render-worker"); +``` + +### Render Worker Types and Configuration + +#### Common Configuration Keys +- `render_quality`: Render quality level ("low", "medium", "high", "ultra") +- `render_format`: Output format ("mp4", "avi", "mov", "webm") +- `render_resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720") +- `max_concurrent_tasks`: Maximum concurrent render tasks (integer) +- `task_timeout`: Task timeout in seconds (integer) +- `output_path`: Render output directory path (string) +- `enable_gpu`: Enable GPU acceleration (boolean) +- `gpu_memory_limit`: GPU memory limit in MB (integer) +- `codec`: Video codec ("h264", "h265", "vp9") +- `bitrate`: Video bitrate in kbps (integer) +- `enable_preview`: Enable preview generation (boolean) + +#### Worker Status +- **Active (isActive=1)**: Worker is available for tasks +- **Inactive (isActive=0)**: Worker is disabled + ## Common Development Tasks ### Running Integration Tests @@ -600,6 +1180,10 @@ mvn test -Dtest="com.ycwl.basic.integration.*Test" # Run device integration tests mvn test -Dtest=DeviceIntegrationServiceTest mvn test -Dtest="com.ycwl.basic.integration.device.*Test" + +# Run render worker integration tests +mvn test -Dtest=RenderWorkerIntegrationServiceTest +mvn test -Dtest="com.ycwl.basic.integration.render.*Test" ``` ### Adding New DTOs diff --git a/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java b/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java index a25541e..aa10a5c 100644 --- a/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java +++ b/src/main/java/com/ycwl/basic/integration/common/config/IntegrationProperties.java @@ -26,6 +26,11 @@ public class IntegrationProperties { */ private DeviceConfig device = new DeviceConfig(); + /** + * 渲染工作器服务配置 + */ + private RenderWorkerConfig render = new RenderWorkerConfig(); + @Data public static class ScenicConfig { /** @@ -98,6 +103,32 @@ public class IntegrationProperties { */ private ServiceFallbackConfig scenic = new ServiceFallbackConfig(); private ServiceFallbackConfig device = new ServiceFallbackConfig(); + private ServiceFallbackConfig render = new ServiceFallbackConfig(); + } + + @Data + public static class RenderWorkerConfig { + /** + * 是否启用渲染工作器服务集成 + */ + private boolean enabled = true; + + /** + * 服务名称 + */ + private String serviceName = "zt-render-worker"; + + /** + * 超时配置(毫秒) + */ + private int connectTimeout = 5000; + private int readTimeout = 10000; + + /** + * 重试配置 + */ + private boolean retryEnabled = false; + private int maxRetries = 3; } @Data diff --git a/src/main/java/com/ycwl/basic/integration/common/manager/RenderWorkerConfigManager.java b/src/main/java/com/ycwl/basic/integration/common/manager/RenderWorkerConfigManager.java new file mode 100644 index 0000000..4e0b7f8 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/common/manager/RenderWorkerConfigManager.java @@ -0,0 +1,82 @@ +package com.ycwl.basic.integration.common.manager; + +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; + +import java.util.List; + +/** + * 渲染工作器配置管理器 + * 基于通用ConfigManager实现渲染工作器配置的管理功能 + */ +public class RenderWorkerConfigManager extends ConfigManager { + + public RenderWorkerConfigManager(List configs) { + super(configs); + } + + @Override + protected String getConfigKey(RenderWorkerConfigV2DTO config) { + return config != null ? config.getConfigKey() : null; + } + + @Override + protected Object getConfigValue(RenderWorkerConfigV2DTO config) { + return config != null ? config.getConfigValue() : null; + } + + /** + * 获取渲染工作器配置类型 + */ + public String getConfigType(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null ? config.getConfigType() : null; + } + + /** + * 获取渲染工作器配置描述 + */ + public String getConfigDescription(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null ? config.getDescription() : null; + } + + /** + * 获取渲染工作器配置ID + */ + public Long getConfigId(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null ? config.getId() : null; + } + + /** + * 获取工作器ID + */ + public Long getWorkerId(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null ? config.getWorkerId() : null; + } + + /** + * 检查配置是否启用 + */ + public boolean isActive(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null && config.getIsActive() != null && config.getIsActive() == 1; + } + + /** + * 获取配置的创建时间 + */ + public String getCreateTime(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null ? config.getCreateTime() : null; + } + + /** + * 获取配置的更新时间 + */ + public String getUpdateTime(String key) { + RenderWorkerConfigV2DTO config = findConfigByKey(key); + return config != null ? config.getUpdateTime() : null; + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java b/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java index 2d7d7f1..d5d9541 100644 --- a/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java +++ b/src/main/java/com/ycwl/basic/integration/common/response/CommonResponse.java @@ -12,29 +12,33 @@ import lombok.AllArgsConstructor; public class CommonResponse { private Integer code; private String message; + private Boolean success; private T data; public static CommonResponse success() { - return new CommonResponse<>(200, "OK", null); + return new CommonResponse<>(200, "OK", true, null); } public static CommonResponse success(T data) { - return new CommonResponse<>(200, "OK", data); + return new CommonResponse<>(200, "OK", true, data); } public static CommonResponse success(String message, T data) { - return new CommonResponse<>(200, message, data); + return new CommonResponse<>(200, message, true, data); } public static CommonResponse error(Integer code, String message) { - return new CommonResponse<>(code, message, null); + return new CommonResponse<>(code, message, false, null); } public static CommonResponse error(String message) { - return new CommonResponse<>(5000, message, null); + return new CommonResponse<>(5000, message, false, null); } public boolean isSuccess() { - return code != null && code == 200; + if (success == null) { // compatible + return code != null && code == 200; + } + return success; } } \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/client/DefaultConfigClient.java b/src/main/java/com/ycwl/basic/integration/device/client/DefaultConfigClient.java new file mode 100644 index 0000000..2163c67 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/client/DefaultConfigClient.java @@ -0,0 +1,54 @@ +package com.ycwl.basic.integration.device.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.device.dto.defaults.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 默认配置管理 Feign 客户端 + */ +@FeignClient(name = "zt-device", contextId = "device-default-config", path = "/api/device/config/v2/defaults") +public interface DefaultConfigClient { + + /** + * 获取默认配置列表 + */ + @GetMapping + CommonResponse> listDefaultConfigs(@RequestParam(value = "page", defaultValue = "1") int page, + @RequestParam(value = "pageSize", defaultValue = "10") int pageSize); + + /** + * 根据配置键获取默认配置 + */ + @GetMapping("/{configKey}") + CommonResponse getDefaultConfig(@PathVariable("configKey") String configKey); + + /** + * 创建默认配置 + */ + @PostMapping + CommonResponse createDefaultConfig(@RequestBody DefaultConfigRequest request); + + /** + * 更新默认配置 + */ + @PutMapping("/{configKey}") + CommonResponse> updateDefaultConfig(@PathVariable("configKey") String configKey, + @RequestBody Map updates); + + /** + * 删除默认配置 + */ + @DeleteMapping("/{configKey}") + CommonResponse deleteDefaultConfig(@PathVariable("configKey") String configKey); + + /** + * 批量更新默认配置 + */ + @PostMapping("/batch") + CommonResponse batchUpdateDefaultConfigs(@RequestBody BatchDefaultConfigRequest request); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java b/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java index 0e13675..694cc52 100644 --- a/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java +++ b/src/main/java/com/ycwl/basic/integration/device/client/DeviceV2Client.java @@ -1,6 +1,7 @@ package com.ycwl.basic.integration.device.client; import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.device.dto.device.*; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.*; @@ -55,7 +56,7 @@ public interface DeviceV2Client { * 分页获取设备列表(核心信息) */ @GetMapping("/") - CommonResponse listDevices( + CommonResponse> listDevices( @RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(value = "name", required = false) String name, @@ -68,7 +69,7 @@ public interface DeviceV2Client { * 分页获取设备列表(含配置) */ @GetMapping("/with-config") - CommonResponse listDevicesWithConfig( + CommonResponse> listDevicesWithConfig( @RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(value = "name", required = false) String name, diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/defaults/BatchDefaultConfigRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/BatchDefaultConfigRequest.java new file mode 100644 index 0000000..7b47691 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/BatchDefaultConfigRequest.java @@ -0,0 +1,18 @@ +package com.ycwl.basic.integration.device.dto.defaults; + +import lombok.Data; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; + +/** + * 批量默认配置操作请求模型 + */ +@Data +public class BatchDefaultConfigRequest { + + @NotEmpty(message = "配置列表不能为空") + @Valid + private List configs; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/defaults/BatchDefaultConfigResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/BatchDefaultConfigResponse.java new file mode 100644 index 0000000..39ac042 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/BatchDefaultConfigResponse.java @@ -0,0 +1,23 @@ +package com.ycwl.basic.integration.device.dto.defaults; + +import com.ycwl.basic.integration.device.dto.config.ProcessedConfigItem; +import lombok.Data; + +import java.util.List; + +/** + * 批量默认配置操作响应模型 + */ +@Data +public class BatchDefaultConfigResponse { + + private Integer success; + + private Integer failed; + + private List conflicts; + + private List processedItems; + + private List errors; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigConflict.java b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigConflict.java new file mode 100644 index 0000000..7178b45 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigConflict.java @@ -0,0 +1,24 @@ +package com.ycwl.basic.integration.device.dto.defaults; + +import lombok.Data; + +import java.util.List; + +/** + * 冲突信息模型 + */ +@Data +public class DefaultConfigConflict { + + private String configKey; + + private String conflictType; + + private Integer deviceCount; + + private String currentType; + + private String proposedType; + + private List conflictDevices; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigRequest.java b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigRequest.java new file mode 100644 index 0000000..98843a8 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigRequest.java @@ -0,0 +1,26 @@ +package com.ycwl.basic.integration.device.dto.defaults; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import jakarta.validation.constraints.NotBlank; + +/** + * 默认配置请求模型 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DefaultConfigRequest { + + @NotBlank(message = "配置键不能为空") + private String configKey; + + @NotBlank(message = "配置值不能为空") + private String configValue; + + @NotBlank(message = "配置类型不能为空") + private String configType; + + @NotBlank(message = "配置描述不能为空") + private String description; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigResponse.java new file mode 100644 index 0000000..586c8ac --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/dto/defaults/DefaultConfigResponse.java @@ -0,0 +1,28 @@ +package com.ycwl.basic.integration.device.dto.defaults; + +import lombok.Data; + +/** + * 默认配置响应模型 + */ +@Data +public class DefaultConfigResponse { + + private String id; + + private String configKey; + + private String configValue; + + private String configType; + + private String description; + + private Integer isActive; + + private String createTime; + + private String updateTime; + + private Integer usageCount; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java deleted file mode 100644 index d32b247..0000000 --- a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2ListResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ycwl.basic.integration.device.dto.device; - -import lombok.Data; - -import java.util.List; - -@Data -public class DeviceV2ListResponse { - private List list; - private Integer total; - private Integer page; - private Integer pageSize; -} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java deleted file mode 100644 index d5c7c44..0000000 --- a/src/main/java/com/ycwl/basic/integration/device/dto/device/DeviceV2WithConfigListResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ycwl.basic.integration.device.dto.device; - -import lombok.Data; - -import java.util.List; - -@Data -public class DeviceV2WithConfigListResponse { - private List list; - private Integer total; - private Integer page; - private Integer pageSize; -} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/dto/device/FilterDevicesByConfigsResponse.java b/src/main/java/com/ycwl/basic/integration/device/dto/device/FilterDevicesByConfigsResponse.java index cd957a4..f60fdeb 100644 --- a/src/main/java/com/ycwl/basic/integration/device/dto/device/FilterDevicesByConfigsResponse.java +++ b/src/main/java/com/ycwl/basic/integration/device/dto/device/FilterDevicesByConfigsResponse.java @@ -17,7 +17,7 @@ public class FilterDevicesByConfigsResponse { /** * 总数 */ - private String total; + private Integer total; /** * 页码 diff --git a/src/main/java/com/ycwl/basic/integration/device/example/DefaultConfigIntegrationExample.java b/src/main/java/com/ycwl/basic/integration/device/example/DefaultConfigIntegrationExample.java new file mode 100644 index 0000000..75fc610 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/example/DefaultConfigIntegrationExample.java @@ -0,0 +1,275 @@ +package com.ycwl.basic.integration.device.example; + +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.device.dto.defaults.*; +import com.ycwl.basic.integration.device.service.DeviceDefaultConfigIntegrationService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 默认配置集成服务使用示例 + * + * 通过在 application.yml 中设置 integration.device.example.default-config.enabled=true 来启用 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@ConditionalOnProperty(name = "integration.device.example.default-config.enabled", havingValue = "true") +public class DefaultConfigIntegrationExample implements CommandLineRunner { + + private final DeviceDefaultConfigIntegrationService defaultConfigService; + + @Override + public void run(String... args) throws Exception { + log.info("=== 默认配置集成服务使用示例 ==="); + + try { + // 1. 基础查询操作示例(支持自动 Fallback) + basicQueryExamples(); + + // 2. 配置管理操作示例(直接操作) + configManagementExamples(); + + // 3. 批量操作示例 + batchOperationExamples(); + + // 4. 高级使用模式示例 + advancedUsageExamples(); + + } catch (Exception e) { + log.error("默认配置集成示例执行失败", e); + } + } + + /** + * 基础查询操作示例(支持自动 Fallback) + */ + private void basicQueryExamples() { + log.info("--- 基础查询操作示例(支持自动 Fallback)---"); + + try { + // 获取默认配置列表(自动缓存,服务不可用时返回缓存数据) + PageResponse configList = defaultConfigService.listDefaultConfigs(1, 10); + log.info("默认配置列表: 总数={}, 当前页配置数={}", + configList.getTotal(), configList.getList().size()); + + // 显示配置详情 + for (DefaultConfigResponse config : configList.getList()) { + log.info("配置详情: key={}, value={}, type={}, description={}", + config.getConfigKey(), config.getConfigValue(), + config.getConfigType(), config.getDescription()); + + // 获取单个配置详情(自动缓存,服务不可用时返回缓存数据) + DefaultConfigResponse detailConfig = defaultConfigService.getDefaultConfig(config.getConfigKey()); + if (detailConfig != null) { + log.info("配置详情获取成功: usageCount={}, isActive={}", + detailConfig.getUsageCount(), detailConfig.getIsActive()); + } + break; // 只展示第一个 + } + + } catch (Exception e) { + log.error("基础查询操作失败", e); + } + } + + /** + * 配置管理操作示例(直接操作) + */ + private void configManagementExamples() { + log.info("--- 配置管理操作示例(直接操作)---"); + + String testConfigKey = "example_test_config"; + + try { + // 1. 创建默认配置(直接操作,失败时立即报错) + DefaultConfigRequest createRequest = new DefaultConfigRequest(); + createRequest.setConfigKey(testConfigKey); + createRequest.setConfigValue("1920x1080"); + createRequest.setConfigType("string"); + createRequest.setDescription("示例测试配置 - 默认分辨率"); + + boolean createResult = defaultConfigService.createDefaultConfig(createRequest); + log.info("创建默认配置结果: {}", createResult ? "成功" : "失败"); + + // 2. 更新默认配置(直接操作,可能返回冲突信息) + Map updates = new HashMap<>(); + updates.put("configValue", "3840x2160"); + updates.put("description", "更新后的默认分辨率 - 4K"); + + DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig(testConfigKey, updates); + if (conflict != null) { + log.warn("更新配置存在冲突: configKey={}, conflictType={}, deviceCount={}", + conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount()); + } else { + log.info("配置更新成功,无冲突"); + } + + // 3. 验证更新结果 + DefaultConfigResponse updatedConfig = defaultConfigService.getDefaultConfig(testConfigKey); + if (updatedConfig != null) { + log.info("更新后配置值: {}", updatedConfig.getConfigValue()); + } + + // 4. 删除测试配置(直接操作) + boolean deleteResult = defaultConfigService.deleteDefaultConfig(testConfigKey); + log.info("删除默认配置结果: {}", deleteResult ? "成功" : "失败"); + + } catch (Exception e) { + log.error("配置管理操作失败", e); + } + } + + /** + * 批量操作示例 + */ + private void batchOperationExamples() { + log.info("--- 批量操作示例 ---"); + + try { + // 1. 使用构建器模式创建批量配置 + BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder() + .addVideoConfig("1920x1080", 30, "H264") // 添加视频配置组 + .addNetworkConfig("192.168.1.100", 554, "RTSP") // 添加网络配置组 + .addConfig("recording_enabled", "true", "bool", "是否启用录制") + .addConfig("storage_path", "/data/recordings", "string", "录制存储路径") + .addConfig("max_file_size", "1024", "int", "最大文件大小(MB)") + .build(); + + log.info("准备批量创建 {} 个默认配置", batchRequest.getConfigs().size()); + + // 2. 执行批量更新(直接操作) + BatchDefaultConfigResponse batchResult = defaultConfigService.batchUpdateDefaultConfigs(batchRequest); + + // 3. 处理批量结果 + log.info("批量操作结果: 成功={}, 失败={}", batchResult.getSuccess(), batchResult.getFailed()); + + if (batchResult.getConflicts() != null && !batchResult.getConflicts().isEmpty()) { + log.warn("发现 {} 个配置冲突:", batchResult.getConflicts().size()); + for (DefaultConfigConflict conflict : batchResult.getConflicts()) { + log.warn("冲突配置: key={}, type={}, deviceCount={}", + conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount()); + } + } + + if (batchResult.getProcessedItems() != null) { + log.info("处理详情:"); + batchResult.getProcessedItems().forEach(item -> + log.info(" 配置 {}: status={}, action={}, finalType={}", + item.getConfigKey(), item.getStatus(), item.getAction(), item.getFinalType()) + ); + } + + if (batchResult.getErrors() != null && !batchResult.getErrors().isEmpty()) { + log.error("批量操作错误:"); + batchResult.getErrors().forEach(error -> log.error(" {}", error)); + } + + } catch (Exception e) { + log.error("批量操作失败", e); + } + } + + /** + * 高级使用模式示例 + */ + private void advancedUsageExamples() { + log.info("--- 高级使用模式示例 ---"); + + try { + // 1. 设备类型特定的默认配置模式 + createDeviceTypeSpecificConfigs(); + + // 2. 配置验证和完整性检查模式 + validateConfigCompleteness(); + + // 3. 配置迁移和批量更新模式 + configMigrationPattern(); + + } catch (Exception e) { + log.error("高级使用模式示例失败", e); + } + } + + /** + * 创建设备类型特定的默认配置 + */ + private void createDeviceTypeSpecificConfigs() { + log.info("创建设备类型特定的默认配置..."); + + // IPC摄像头默认配置 + BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder() + .addVideoConfig("1920x1080", 25, "H264") + .addConfig("night_vision", "true", "bool", "夜视功能") + .addConfig("motion_detection", "true", "bool", "移动检测") + .addConfig("stream_profile", "main", "string", "码流类型") + .build(); + + // NVR设备默认配置 + BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder() + .addConfig("max_channels", "16", "int", "最大通道数") + .addConfig("storage_mode", "continuous", "string", "存储模式") + .addConfig("backup_enabled", "true", "bool", "备份启用") + .build(); + + log.info("IPC默认配置项数: {}, NVR默认配置项数: {}", + ipcDefaults.getConfigs().size(), nvrDefaults.getConfigs().size()); + } + + /** + * 配置验证和完整性检查 + */ + private void validateConfigCompleteness() { + log.info("验证配置完整性..."); + + // 获取所有默认配置 + PageResponse allConfigs = defaultConfigService.listDefaultConfigs(1, 100); + + // 检查必需的基础配置是否存在 + String[] requiredConfigs = {"resolution", "frameRate", "codec", "protocol"}; + for (String requiredConfig : requiredConfigs) { + boolean exists = allConfigs.getList().stream() + .anyMatch(config -> requiredConfig.equals(config.getConfigKey())); + log.info("必需配置 {} 存在: {}", requiredConfig, exists ? "✓" : "✗"); + } + + // 统计配置类型分布 + Map typeDistribution = new HashMap<>(); + allConfigs.getList().forEach(config -> + typeDistribution.merge(config.getConfigType(), 1L, Long::sum) + ); + + log.info("配置类型分布: {}", typeDistribution); + } + + /** + * 配置迁移和批量更新模式 + */ + private void configMigrationPattern() { + log.info("配置迁移模式示例..."); + + try { + // 1. 获取需要升级的配置 + PageResponse oldConfigs = defaultConfigService.listDefaultConfigs(1, 50); + + // 2. 创建升级配置批次 + BatchDefaultConfigRequest upgradeRequest = defaultConfigService.createBatchConfigBuilder() + .addConfig("api_version", "v2", "string", "API版本") + .addConfig("security_mode", "enhanced", "string", "安全模式") + .build(); + + // 3. 执行批量升级 + BatchDefaultConfigResponse upgradeResult = defaultConfigService.batchUpdateDefaultConfigs(upgradeRequest); + log.info("配置升级结果: 成功={}, 失败={}", upgradeResult.getSuccess(), upgradeResult.getFailed()); + + } catch (Exception e) { + log.warn("配置迁移示例执行失败(这是正常的,因为是示例代码)", e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java b/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java index 388c93d..638a7ee 100644 --- a/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java +++ b/src/main/java/com/ycwl/basic/integration/device/example/DeviceIntegrationExample.java @@ -1,5 +1,6 @@ package com.ycwl.basic.integration.device.example; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.device.dto.device.*; import com.ycwl.basic.integration.device.dto.config.*; import com.ycwl.basic.integration.device.service.DeviceConfigIntegrationService; @@ -46,7 +47,7 @@ public class DeviceIntegrationExample { log.info("获取设备配置: {}", deviceWithConfig.getName()); // 分页查询景区设备列表 - DeviceV2ListResponse deviceList = deviceService.getScenicIpcDevices(1001L, 1, 10); + PageResponse deviceList = deviceService.getScenicIpcDevices(1001L, 1, 10); log.info("景区设备列表: 总数={}", deviceList.getTotal()); // 启用设备 @@ -80,7 +81,7 @@ public class DeviceIntegrationExample { log.info("更新摄像头1排序为1(置顶)"); // 获取排序后的设备列表 - DeviceV2ListResponse sortedList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId); + PageResponse sortedList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId); log.info("排序后的设备列表:"); for (DeviceV2DTO device : sortedList.getList()) { log.info(" - {}: 排序={}, 类型={}", device.getName(), device.getSort(), device.getType()); @@ -147,7 +148,7 @@ public class DeviceIntegrationExample { log.info("将普通摄像头置顶(排序值: 1)"); // 查看最终排序结果 - DeviceV2ListResponse finalList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId); + PageResponse finalList = deviceService.listDevices(1, 10, null, null, null, 1, scenicId); log.info("最终排序结果:"); for (DeviceV2DTO device : finalList.getList()) { log.info(" - {}: 排序={}", device.getName(), device.getSort()); diff --git a/src/main/java/com/ycwl/basic/integration/device/service/DeviceDefaultConfigIntegrationService.java b/src/main/java/com/ycwl/basic/integration/device/service/DeviceDefaultConfigIntegrationService.java new file mode 100644 index 0000000..0c49612 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/device/service/DeviceDefaultConfigIntegrationService.java @@ -0,0 +1,218 @@ +package com.ycwl.basic.integration.device.service; + +import com.ycwl.basic.integration.common.exception.IntegrationException; +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.common.service.IntegrationFallbackService; +import com.ycwl.basic.integration.device.client.DefaultConfigClient; +import com.ycwl.basic.integration.device.dto.defaults.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Map; + +/** + * 默认配置集成服务 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceDefaultConfigIntegrationService { + + private final DefaultConfigClient defaultConfigClient; + private final IntegrationFallbackService fallbackService; + + private static final String SERVICE_NAME = "zt-device"; + + /** + * 获取默认配置列表(支持 Fallback) + */ + public PageResponse listDefaultConfigs(int page, int pageSize) { + return fallbackService.executeWithFallback( + SERVICE_NAME, + "defaults:list:" + page + ":" + pageSize, + () -> { + CommonResponse> response = defaultConfigClient.listDefaultConfigs(page, pageSize); + return handleResponse(response, "获取默认配置列表失败"); + }, + PageResponse.class + ); + } + + /** + * 根据配置键获取默认配置(支持 Fallback) + */ + public DefaultConfigResponse getDefaultConfig(String configKey) { + return fallbackService.executeWithFallback( + SERVICE_NAME, + "defaults:config:" + configKey, + () -> { + log.info("获取默认配置, configKey: {}", configKey); + CommonResponse response = defaultConfigClient.getDefaultConfig(configKey); + return handleResponse(response, "获取默认配置失败"); + }, + DefaultConfigResponse.class + ); + } + + /** + * 创建默认配置(直接操作,不支持 Fallback) + */ + public boolean createDefaultConfig(DefaultConfigRequest request) { + log.info("创建默认配置, configKey: {}", request.getConfigKey()); + CommonResponse response = defaultConfigClient.createDefaultConfig(request); + String result = handleResponse(response, "创建默认配置失败"); + return result != null; + } + + /** + * 更新默认配置(直接操作,不支持 Fallback) + */ + public DefaultConfigConflict updateDefaultConfig(String configKey, Map updates) { + log.info("更新默认配置, configKey: {}, updates: {}", configKey, updates); + CommonResponse> response = defaultConfigClient.updateDefaultConfig(configKey, updates); + Map result = handleResponse(response, "更新默认配置失败"); + + // 检查是否有冲突信息 + if (result != null && result.containsKey("conflict")) { + Object conflictObj = result.get("conflict"); + if (conflictObj instanceof Map) { + // 将Map转换为DefaultConfigConflict对象 + return mapToDefaultConfigConflict((Map) conflictObj); + } + } + + return null; + } + + /** + * 删除默认配置(直接操作,不支持 Fallback) + */ + public boolean deleteDefaultConfig(String configKey) { + log.info("删除默认配置, configKey: {}", configKey); + CommonResponse response = defaultConfigClient.deleteDefaultConfig(configKey); + String result = handleResponse(response, "删除默认配置失败"); + return result != null; + } + + /** + * 批量更新默认配置(直接操作,不支持 Fallback) + */ + public BatchDefaultConfigResponse batchUpdateDefaultConfigs(BatchDefaultConfigRequest request) { + log.info("批量更新默认配置, configs count: {}", request.getConfigs().size()); + CommonResponse response = defaultConfigClient.batchUpdateDefaultConfigs(request); + return handleResponse(response, "批量更新默认配置失败"); + } + + /** + * 创建批量配置请求构建器 + */ + public BatchDefaultConfigRequestBuilder createBatchConfigBuilder() { + return new BatchDefaultConfigRequestBuilder(); + } + + /** + * 批量配置请求构建器 + */ + public static class BatchDefaultConfigRequestBuilder { + private final BatchDefaultConfigRequest request = new BatchDefaultConfigRequest(); + + public BatchDefaultConfigRequestBuilder() { + request.setConfigs(new ArrayList<>()); + } + + /** + * 添加配置项 + */ + public BatchDefaultConfigRequestBuilder addConfig(String configKey, String configValue, + String configType, String description) { + DefaultConfigRequest item = new DefaultConfigRequest(); + item.setConfigKey(configKey); + item.setConfigValue(configValue); + item.setConfigType(configType); + item.setDescription(description); + request.getConfigs().add(item); + return this; + } + + /** + * 添加视频配置 + */ + public BatchDefaultConfigRequestBuilder addVideoConfig(String resolution, Integer frameRate, String codec) { + addConfig("resolution", resolution, "string", "视频分辨率"); + addConfig("frameRate", frameRate.toString(), "int", "视频帧率"); + addConfig("codec", codec, "string", "视频编码格式"); + return this; + } + + /** + * 添加网络配置 + */ + public BatchDefaultConfigRequestBuilder addNetworkConfig(String ipAddress, Integer port, String protocol) { + addConfig("ipAddress", ipAddress, "string", "IP地址"); + addConfig("port", port.toString(), "int", "端口号"); + addConfig("protocol", protocol, "string", "网络协议"); + return this; + } + + /** + * 构建请求对象 + */ + public BatchDefaultConfigRequest build() { + return request; + } + } + + /** + * 将Map转换为DefaultConfigConflict对象 + */ + @SuppressWarnings("unchecked") + private DefaultConfigConflict mapToDefaultConfigConflict(Map map) { + DefaultConfigConflict conflict = new DefaultConfigConflict(); + + if (map.containsKey("configKey")) { + conflict.setConfigKey((String) map.get("configKey")); + } + if (map.containsKey("conflictType")) { + conflict.setConflictType((String) map.get("conflictType")); + } + if (map.containsKey("deviceCount")) { + Object deviceCount = map.get("deviceCount"); + if (deviceCount instanceof Number) { + conflict.setDeviceCount(((Number) deviceCount).intValue()); + } + } + if (map.containsKey("currentType")) { + conflict.setCurrentType((String) map.get("currentType")); + } + if (map.containsKey("proposedType")) { + conflict.setProposedType((String) map.get("proposedType")); + } + if (map.containsKey("conflictDevices")) { + Object conflictDevices = map.get("conflictDevices"); + if (conflictDevices instanceof Iterable) { + conflict.setConflictDevices(new ArrayList<>()); + for (Object deviceId : (Iterable) conflictDevices) { + if (deviceId instanceof Number) { + conflict.getConflictDevices().add(((Number) deviceId).longValue()); + } + } + } + } + + return conflict; + } + + private T handleResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.isSuccess()) { + String msg = response != null && response.getMessage() != null + ? response.getMessage() + : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + return response.getData(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java b/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java index 976a11e..25d82a8 100644 --- a/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java +++ b/src/main/java/com/ycwl/basic/integration/device/service/DeviceIntegrationService.java @@ -4,6 +4,7 @@ import com.ycwl.basic.integration.common.exception.IntegrationException; import com.ycwl.basic.integration.common.response.CommonResponse; import com.ycwl.basic.integration.common.service.IntegrationFallbackService; import com.ycwl.basic.integration.device.client.DeviceV2Client; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.device.dto.device.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -91,20 +92,20 @@ public class DeviceIntegrationService { handleResponse(response, "删除设备失败"); } - public DeviceV2ListResponse listDevices(Integer page, Integer pageSize, String name, String no, + public PageResponse listDevices(Integer page, Integer pageSize, String name, String no, String type, Integer isActive, Long scenicId) { log.debug("分页查询设备列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", page, pageSize, name, no, type, isActive, scenicId); - CommonResponse response = deviceV2Client.listDevices( + CommonResponse> response = deviceV2Client.listDevices( page, pageSize, name, no, type, isActive, scenicId); return handleResponse(response, "分页查询设备列表失败"); } - public DeviceV2WithConfigListResponse listDevicesWithConfig(Integer page, Integer pageSize, String name, String no, + public PageResponse listDevicesWithConfig(Integer page, Integer pageSize, String name, String no, String type, Integer isActive, Long scenicId) { log.debug("分页查询设备带配置列表, page: {}, pageSize: {}, name: {}, no: {}, type: {}, isActive: {}, scenicId: {}", page, pageSize, name, no, type, isActive, scenicId); - CommonResponse response = deviceV2Client.listDevicesWithConfig( + CommonResponse> response = deviceV2Client.listDevicesWithConfig( page, pageSize, name, no, type, isActive, scenicId); return handleResponse(response, "分页查询设备带配置列表失败"); } @@ -196,14 +197,14 @@ public class DeviceIntegrationService { /** * 获取景区的IPC设备列表 */ - public DeviceV2ListResponse getScenicIpcDevices(Long scenicId, Integer page, Integer pageSize) { + public PageResponse getScenicIpcDevices(Long scenicId, Integer page, Integer pageSize) { return listDevices(page, pageSize, null, null, "IPC", 1, scenicId); } /** * 获取景区的所有激活设备 */ - public DeviceV2ListResponse getScenicActiveDevices(Long scenicId, Integer page, Integer pageSize) { + public PageResponse getScenicActiveDevices(Long scenicId, Integer page, Integer pageSize) { return listDevices(page, pageSize, null, null, null, 1, scenicId); } diff --git a/src/main/java/com/ycwl/basic/integration/questionnaire/config/QuestionnaireIntegrationConfig.java b/src/main/java/com/ycwl/basic/integration/questionnaire/config/QuestionnaireIntegrationConfig.java new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerConfigV2Client.java b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerConfigV2Client.java new file mode 100644 index 0000000..fa478c3 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerConfigV2Client.java @@ -0,0 +1,59 @@ +package com.ycwl.basic.integration.render.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest; +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 渲染工作器配置V2客户端 + */ +@FeignClient(name = "zt-render-worker", contextId = "render-worker-config-v2", path = "/api/render/worker/config/v2") +public interface RenderWorkerConfigV2Client { + + /** + * 获取工作器所有配置 + */ + @GetMapping("/{workerId}") + CommonResponse> getWorkerConfigs(@PathVariable("workerId") Long workerId); + + /** + * 根据配置键获取特定配置 + */ + @GetMapping("/{workerId}/key/{configKey}") + CommonResponse getWorkerConfigByKey(@PathVariable("workerId") Long workerId, + @PathVariable("configKey") String configKey); + + /** + * 创建配置 + */ + @PostMapping("/{workerId}") + CommonResponse createWorkerConfig(@PathVariable("workerId") Long workerId, + @RequestBody RenderWorkerConfigV2DTO config); + + /** + * 更新配置 + */ + @PutMapping("/{workerId}/{id}") + CommonResponse updateWorkerConfig(@PathVariable("workerId") Long workerId, + @PathVariable("id") Long id, + @RequestBody Map updates); + + /** + * 删除配置 + */ + @DeleteMapping("/{workerId}/{id}") + CommonResponse deleteWorkerConfig(@PathVariable("workerId") Long workerId, + @PathVariable("id") Long id); + + /** + * 批量更新配置 + */ + @PostMapping("/{workerId}/batch") + CommonResponse batchUpdateWorkerConfigs(@PathVariable("workerId") Long workerId, + @RequestBody BatchRenderWorkerConfigRequest request); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerV2Client.java b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerV2Client.java new file mode 100644 index 0000000..c6c923c --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/client/RenderWorkerV2Client.java @@ -0,0 +1,76 @@ +package com.ycwl.basic.integration.render.client; + +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.render.dto.worker.*; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +/** + * 渲染工作器V2客户端 + */ +@FeignClient(name = "zt-render-worker", contextId = "render-worker-v2", path = "/api/render/worker/v2") +public interface RenderWorkerV2Client { + + /** + * 获取工作器核心信息 + */ + @GetMapping("/{id}") + CommonResponse getWorker(@PathVariable("id") Long id); + + /** + * 获取工作器含配置信息 + */ + @GetMapping("/{id}/with-config") + CommonResponse getWorkerWithConfig(@PathVariable("id") Long id); + + /** + * 创建工作器 + */ + @PostMapping + CommonResponse createWorker(@RequestBody CreateRenderWorkerRequest request); + + /** + * 更新工作器 + */ + @PutMapping("/{id}") + CommonResponse updateWorker(@PathVariable("id") Long id, + @RequestBody UpdateRenderWorkerRequest request); + + /** + * 删除工作器 + */ + @DeleteMapping("/{id}") + CommonResponse deleteWorker(@PathVariable("id") Long id); + + /** + * 分页查询工作器列表(核心信息) + */ + @GetMapping + CommonResponse> listWorkers(@RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Integer isEnabled, + @RequestParam(required = false) String name); + + /** + * 分页查询工作器列表(含配置信息) + */ + @GetMapping("/with-config") + CommonResponse> listWorkersWithConfig( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Integer isEnabled, + @RequestParam(required = false) String name); + + /** + * 根据key获取工作器核心信息 + */ + @GetMapping("/key/{key}") + CommonResponse getWorkerByKey(@PathVariable("key") String key); + + /** + * 根据key获取工作器完整信息(含配置) + */ + @GetMapping("/key/{key}/with-config") + CommonResponse getWorkerWithConfigByKey(@PathVariable("key") String key); +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/config/RenderWorkerIntegrationConfig.java b/src/main/java/com/ycwl/basic/integration/render/config/RenderWorkerIntegrationConfig.java new file mode 100644 index 0000000..4666cb6 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/config/RenderWorkerIntegrationConfig.java @@ -0,0 +1,17 @@ +package com.ycwl.basic.integration.render.config; + +import com.ycwl.basic.integration.common.config.IntegrationProperties; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +/** + * 渲染工作器集成配置 + */ +@Configuration +@ConditionalOnProperty(prefix = "integration.render", name = "enabled", havingValue = "true", matchIfMissing = true) +@RequiredArgsConstructor +public class RenderWorkerIntegrationConfig { + + private final IntegrationProperties integrationProperties; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/config/BatchRenderWorkerConfigRequest.java b/src/main/java/com/ycwl/basic/integration/render/dto/config/BatchRenderWorkerConfigRequest.java new file mode 100644 index 0000000..c44f5f4 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/config/BatchRenderWorkerConfigRequest.java @@ -0,0 +1,17 @@ +package com.ycwl.basic.integration.render.dto.config; + +import lombok.Data; + +import java.util.List; + +/** + * 批量更新渲染工作器配置请求DTO + */ +@Data +public class BatchRenderWorkerConfigRequest { + + /** + * 配置列表 + */ + private List configs; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/config/RenderWorkerConfigV2DTO.java b/src/main/java/com/ycwl/basic/integration/render/dto/config/RenderWorkerConfigV2DTO.java new file mode 100644 index 0000000..d7ed3b1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/config/RenderWorkerConfigV2DTO.java @@ -0,0 +1,63 @@ +package com.ycwl.basic.integration.render.dto.config; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 渲染工作器配置DTO + */ +@Data +public class RenderWorkerConfigV2DTO { + + /** + * 配置ID + */ + private Long id; + + /** + * 工作器ID + */ + @JsonProperty("workerId") + private Long workerId; + + /** + * 配置键 + */ + @JsonProperty("configKey") + private String configKey; + + /** + * 配置值 + */ + @JsonProperty("configValue") + private String configValue; + + /** + * 配置类型 (string/int/float/bool/json) + */ + @JsonProperty("configType") + private String configType; + + /** + * 描述 + */ + private String description; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("isActive") + private Integer isActive; + + /** + * 创建时间 + */ + @JsonProperty("createTime") + private String createTime; + + /** + * 更新时间 + */ + @JsonProperty("updateTime") + private String updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/CreateRenderWorkerRequest.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/CreateRenderWorkerRequest.java new file mode 100644 index 0000000..6f8e3c6 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/CreateRenderWorkerRequest.java @@ -0,0 +1,31 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import jakarta.validation.constraints.NotBlank; + +/** + * 创建渲染工作器请求DTO + */ +@Data +public class CreateRenderWorkerRequest { + + /** + * 工作器名称 + */ + @NotBlank(message = "工作器名称不能为空") + private String name; + + /** + * 工作器标识 + */ + @NotBlank(message = "工作器标识不能为空") + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("isActive") + private Integer isActive = 1; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2DTO.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2DTO.java new file mode 100644 index 0000000..2b2869b --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2DTO.java @@ -0,0 +1,49 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; + +/** + * 渲染工作器核心信息DTO + */ +@Data +public class RenderWorkerV2DTO { + + /** + * 工作器ID + */ + private Long id; + + /** + * 工作器名称 + */ + private String name; + + /** + * 工作器标识 + */ + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("isActive") + private Integer isActive; + + /** + * 创建时间 + */ + @JsonProperty("createTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** + * 更新时间 + */ + @JsonProperty("updateTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigDTO.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigDTO.java new file mode 100644 index 0000000..9a29bc5 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/RenderWorkerV2WithConfigDTO.java @@ -0,0 +1,55 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 带配置的渲染工作器DTO + */ +@Data +public class RenderWorkerV2WithConfigDTO { + + /** + * 工作器ID + */ + private Long id; + + /** + * 工作器名称 + */ + private String name; + + /** + * 工作器标识 + */ + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("isActive") + private Integer isActive; + + /** + * 创建时间 + */ + @JsonProperty("createTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + /** + * 更新时间 + */ + @JsonProperty("updateTime") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + /** + * 动态配置信息 + */ + private Map config; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/dto/worker/UpdateRenderWorkerRequest.java b/src/main/java/com/ycwl/basic/integration/render/dto/worker/UpdateRenderWorkerRequest.java new file mode 100644 index 0000000..b4e4aae --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/dto/worker/UpdateRenderWorkerRequest.java @@ -0,0 +1,27 @@ +package com.ycwl.basic.integration.render.dto.worker; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 更新渲染工作器请求DTO + */ +@Data +public class UpdateRenderWorkerRequest { + + /** + * 工作器名称 + */ + private String name; + + /** + * 工作器标识 + */ + private String key; + + /** + * 是否启用 (0-禁用,1-启用) + */ + @JsonProperty("isActive") + private Integer isActive; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerConfigIntegrationService.java b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerConfigIntegrationService.java new file mode 100644 index 0000000..0fbe084 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerConfigIntegrationService.java @@ -0,0 +1,287 @@ +package com.ycwl.basic.integration.render.service; + +import com.ycwl.basic.integration.common.exception.IntegrationException; +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.service.IntegrationFallbackService; +import com.ycwl.basic.integration.render.client.RenderWorkerConfigV2Client; +import com.ycwl.basic.integration.render.dto.config.BatchRenderWorkerConfigRequest; +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 渲染工作器配置集成服务 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class RenderWorkerConfigIntegrationService { + + private final RenderWorkerConfigV2Client renderWorkerConfigV2Client; + private final IntegrationFallbackService fallbackService; + + private static final String SERVICE_NAME = "zt-render-worker"; + + /** + * 获取工作器所有配置(带降级) + */ + public List getWorkerConfigs(Long workerId) { + log.info("获取渲染工作器配置列表, workerId: {}", workerId); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:configs:" + workerId, + () -> { + CommonResponse> response = + renderWorkerConfigV2Client.getWorkerConfigs(workerId); + List configs = handleResponse(response, "获取渲染工作器配置列表失败"); + return configs != null ? configs : Collections.emptyList(); + }, + List.class + ); + } + + /** + * 根据配置键获取特定配置(带降级) + */ + public RenderWorkerConfigV2DTO getWorkerConfigByKey(Long workerId, String configKey) { + log.info("根据配置键获取渲染工作器配置, workerId: {}, configKey: {}", workerId, configKey); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:config:" + workerId + ":" + configKey, + () -> { + CommonResponse response = + renderWorkerConfigV2Client.getWorkerConfigByKey(workerId, configKey); + return handleResponse(response, "根据配置键获取渲染工作器配置失败"); + }, + RenderWorkerConfigV2DTO.class + ); + } + + /** + * 获取工作器平铺配置(带降级) + */ + public Map getWorkerFlatConfig(Long workerId) { + log.info("获取渲染工作器平铺配置, workerId: {}", workerId); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:flat:config:" + workerId, + () -> { + List configs = getWorkerConfigsInternal(workerId); + return flattenConfigs(configs); + }, + Map.class + ); + } + + /** + * 创建配置(直接调用,不降级) + */ + public RenderWorkerConfigV2DTO createWorkerConfig(Long workerId, RenderWorkerConfigV2DTO config) { + log.info("创建渲染工作器配置, workerId: {}, configKey: {}", workerId, config.getConfigKey()); + CommonResponse response = + renderWorkerConfigV2Client.createWorkerConfig(workerId, config); + return handleResponse(response, "创建渲染工作器配置失败"); + } + + /** + * 更新配置(直接调用,不降级) + */ + public void updateWorkerConfig(Long workerId, Long configId, Map updates) { + log.info("更新渲染工作器配置, workerId: {}, configId: {}", workerId, configId); + CommonResponse response = + renderWorkerConfigV2Client.updateWorkerConfig(workerId, configId, updates); + handleVoidResponse(response, "更新渲染工作器配置失败"); + } + + /** + * 删除配置(直接调用,不降级) + */ + public void deleteWorkerConfig(Long workerId, Long configId) { + log.info("删除渲染工作器配置, workerId: {}, configId: {}", workerId, configId); + CommonResponse response = + renderWorkerConfigV2Client.deleteWorkerConfig(workerId, configId); + handleVoidResponse(response, "删除渲染工作器配置失败"); + } + + /** + * 批量更新配置(直接调用,不降级) + */ + public void batchUpdateWorkerConfigs(Long workerId, BatchRenderWorkerConfigRequest request) { + log.info("批量更新渲染工作器配置, workerId: {}, configCount: {}", + workerId, request.getConfigs() != null ? request.getConfigs().size() : 0); + CommonResponse response = + renderWorkerConfigV2Client.batchUpdateWorkerConfigs(workerId, request); + handleVoidResponse(response, "批量更新渲染工作器配置失败"); + } + + /** + * 批量平铺更新配置(直接调用,不降级) + */ + public void batchFlatUpdateWorkerConfigs(Long workerId, Map flatConfigs) { + log.info("批量平铺更新渲染工作器配置, workerId: {}, configCount: {}", + workerId, flatConfigs.size()); + + BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest(); + List configs = flatConfigs.entrySet().stream() + .map(entry -> { + RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO(); + config.setConfigKey(entry.getKey()); + config.setConfigValue(String.valueOf(entry.getValue())); + config.setConfigType(determineConfigType(entry.getValue())); + config.setIsActive(1); + return config; + }) + .toList(); + + request.setConfigs(configs); + batchUpdateWorkerConfigs(workerId, request); + } + + /** + * 创建批量配置构建器 + */ + public BatchConfigBuilder createBatchConfigBuilder() { + return new BatchConfigBuilder(); + } + + /** + * 内部获取配置方法(不使用降级) + */ + private List getWorkerConfigsInternal(Long workerId) { + CommonResponse> response = + renderWorkerConfigV2Client.getWorkerConfigs(workerId); + List configs = handleResponse(response, "获取渲染工作器配置列表失败"); + return configs != null ? configs : Collections.emptyList(); + } + + /** + * 将配置列表转换为平铺Map + */ + private Map flattenConfigs(List configs) { + Map flatConfig = new HashMap<>(); + for (RenderWorkerConfigV2DTO config : configs) { + if (config.getIsActive() == 1) { + Object value = convertConfigValue(config.getConfigValue(), config.getConfigType()); + flatConfig.put(config.getConfigKey(), value); + } + } + return flatConfig; + } + + /** + * 根据配置类型转换配置值 + */ + private Object convertConfigValue(String configValue, String configType) { + if (configValue == null) return null; + + return switch (configType) { + case "int" -> Integer.parseInt(configValue); + case "float" -> Double.parseDouble(configValue); + case "bool" -> Boolean.parseBoolean(configValue); + case "json" -> configValue; // 保持JSON字符串格式 + default -> configValue; // string类型或其他 + }; + } + + /** + * 自动判断配置类型 + */ + private String determineConfigType(Object value) { + if (value instanceof Integer) return "int"; + if (value instanceof Double || value instanceof Float) return "float"; + if (value instanceof Boolean) return "bool"; + return "string"; + } + + /** + * 处理通用响应 + */ + private T handleResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + return response.getData(); + } + + /** + * 处理空响应 + */ + private void handleVoidResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + } + + /** + * 批量配置构建器 + */ + public static class BatchConfigBuilder { + private final List configs = new java.util.ArrayList<>(); + + /** + * 添加配置项 + */ + public BatchConfigBuilder addConfig(String key, String value) { + return addConfig(key, value, "string", null); + } + + /** + * 添加配置项(指定类型) + */ + public BatchConfigBuilder addConfig(String key, String value, String type) { + return addConfig(key, value, type, null); + } + + /** + * 添加配置项(完整) + */ + public BatchConfigBuilder addConfig(String key, String value, String type, String description) { + RenderWorkerConfigV2DTO config = new RenderWorkerConfigV2DTO(); + config.setConfigKey(key); + config.setConfigValue(value); + config.setConfigType(type); + config.setDescription(description); + config.setIsActive(1); + configs.add(config); + return this; + } + + /** + * 添加渲染配置 + */ + public BatchConfigBuilder addRenderConfig(String quality, String format, String resolution) { + return addConfig("render_quality", quality, "string", "渲染质量") + .addConfig("render_format", format, "string", "渲染格式") + .addConfig("render_resolution", resolution, "string", "渲染分辨率"); + } + + /** + * 添加性能配置 + */ + public BatchConfigBuilder addPerformanceConfig(Integer maxTasks, Integer timeout) { + return addConfig("max_concurrent_tasks", String.valueOf(maxTasks), "int", "最大并发任务数") + .addConfig("task_timeout", String.valueOf(timeout), "int", "任务超时时间(秒)"); + } + + /** + * 构建批量配置请求 + */ + public BatchRenderWorkerConfigRequest build() { + BatchRenderWorkerConfigRequest request = new BatchRenderWorkerConfigRequest(); + request.setConfigs(configs); + return request; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerIntegrationService.java b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerIntegrationService.java new file mode 100644 index 0000000..5bd1700 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/render/service/RenderWorkerIntegrationService.java @@ -0,0 +1,168 @@ +package com.ycwl.basic.integration.render.service; + +import com.ycwl.basic.integration.common.exception.IntegrationException; +import com.ycwl.basic.integration.common.response.CommonResponse; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.integration.common.service.IntegrationFallbackService; +import com.ycwl.basic.integration.render.client.RenderWorkerV2Client; +import com.ycwl.basic.integration.render.dto.worker.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +/** + * 渲染工作器集成服务 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class RenderWorkerIntegrationService { + + private final RenderWorkerV2Client renderWorkerV2Client; + private final IntegrationFallbackService fallbackService; + + private static final String SERVICE_NAME = "zt-render-worker"; + + /** + * 获取工作器核心信息(带降级) + */ + public RenderWorkerV2DTO getWorker(Long id) { + log.info("获取渲染工作器信息, id: {}", id); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:" + id, + () -> { + CommonResponse response = renderWorkerV2Client.getWorker(id); + return handleResponse(response, "获取渲染工作器信息失败"); + }, + RenderWorkerV2DTO.class + ); + } + + /** + * 获取工作器详细信息(含配置)(带降级) + */ + public RenderWorkerV2WithConfigDTO getWorkerWithConfig(Long id) { + log.info("获取渲染工作器详细信息, id: {}", id); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:config:" + id, + () -> { + CommonResponse response = renderWorkerV2Client.getWorkerWithConfig(id); + return handleResponse(response, "获取渲染工作器详细信息失败"); + }, + RenderWorkerV2WithConfigDTO.class + ); + } + + /** + * 创建工作器(直接调用,不降级) + */ + public RenderWorkerV2DTO createWorker(CreateRenderWorkerRequest request) { + log.info("创建渲染工作器, name: {}, key: {}", request.getName(), request.getKey()); + CommonResponse response = renderWorkerV2Client.createWorker(request); + return handleResponse(response, "创建渲染工作器失败"); + } + + /** + * 更新工作器(直接调用,不降级) + */ + public void updateWorker(Long id, UpdateRenderWorkerRequest request) { + log.info("更新渲染工作器, id: {}, name: {}", id, request.getName()); + CommonResponse response = renderWorkerV2Client.updateWorker(id, request); + handleVoidResponse(response, "更新渲染工作器失败"); + } + + /** + * 删除工作器(直接调用,不降级) + */ + public void deleteWorker(Long id) { + log.info("删除渲染工作器, id: {}", id); + CommonResponse response = renderWorkerV2Client.deleteWorker(id); + handleVoidResponse(response, "删除渲染工作器失败"); + } + + /** + * 分页查询工作器列表(核心信息)(不降级) + */ + public PageResponse listWorkers(Integer page, Integer pageSize, Integer isEnabled, String name) { + log.info("分页查询渲染工作器列表, page: {}, pageSize: {}, isEnabled: {}, name: {}", + page, pageSize, isEnabled, name); + CommonResponse> response = + renderWorkerV2Client.listWorkers(page, pageSize, isEnabled, name); + return handleResponse(response, "查询渲染工作器列表失败"); + } + + /** + * 分页查询工作器列表(含配置信息)(不降级) + */ + public PageResponse listWorkersWithConfig(Integer page, Integer pageSize, + Integer isEnabled, String name) { + log.info("分页查询渲染工作器列表(含配置), page: {}, pageSize: {}, isEnabled: {}, name: {}", + page, pageSize, isEnabled, name); + CommonResponse> response = + renderWorkerV2Client.listWorkersWithConfig(page, pageSize, isEnabled, name); + return handleResponse(response, "查询渲染工作器列表(含配置)失败"); + } + + /** + * 根据key获取工作器核心信息(带降级) + */ + public RenderWorkerV2DTO getWorkerByKey(String key) { + log.info("根据key获取渲染工作器信息, key: {}", key); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:key:" + key, + () -> { + CommonResponse response = renderWorkerV2Client.getWorkerByKey(key); + return handleResponse(response, "根据key获取渲染工作器信息失败"); + }, + RenderWorkerV2DTO.class + ); + } + + /** + * 根据key获取工作器详细信息(含配置)(带降级) + */ + public RenderWorkerV2WithConfigDTO getWorkerWithConfigByKey(String key) { + log.info("根据key获取渲染工作器详细信息, key: {}", key); + return fallbackService.executeWithFallback( + SERVICE_NAME, + "worker:key:config:" + key, + () -> { + CommonResponse response = renderWorkerV2Client.getWorkerWithConfigByKey(key); + return handleResponse(response, "根据key获取渲染工作器详细信息失败"); + }, + RenderWorkerV2WithConfigDTO.class + ); + } + + /** + * 处理通用响应 + */ + private T handleResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + return response.getData(); + } + + /** + * 处理空响应 + */ + private void handleVoidResponse(CommonResponse response, String errorMessage) { + if (response == null || !response.getSuccess()) { + String msg = response != null && response.getMessage() != null ? + response.getMessage() : errorMessage; + Integer code = response != null ? response.getCode() : 5000; + throw new IntegrationException(code, msg, SERVICE_NAME); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/scenic/client/ScenicV2Client.java b/src/main/java/com/ycwl/basic/integration/scenic/client/ScenicV2Client.java index 0405fcf..f2c2d35 100644 --- a/src/main/java/com/ycwl/basic/integration/scenic/client/ScenicV2Client.java +++ b/src/main/java/com/ycwl/basic/integration/scenic/client/ScenicV2Client.java @@ -6,8 +6,7 @@ import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest; import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.*; @@ -38,13 +37,13 @@ public interface ScenicV2Client { CommonResponse filterScenics(@RequestBody ScenicFilterRequest request); @GetMapping("/") - CommonResponse listScenics(@RequestParam(defaultValue = "1") Integer page, + CommonResponse> listScenics(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) Integer status, @RequestParam(required = false) String name); @GetMapping("/with-config") - CommonResponse listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page, + CommonResponse> listScenicsWithConfig(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) Integer status, @RequestParam(required = false) String name); diff --git a/src/main/java/com/ycwl/basic/integration/scenic/dto/scenic/ScenicV2ListResponse.java b/src/main/java/com/ycwl/basic/integration/scenic/dto/scenic/ScenicV2ListResponse.java deleted file mode 100644 index c660579..0000000 --- a/src/main/java/com/ycwl/basic/integration/scenic/dto/scenic/ScenicV2ListResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.ycwl.basic.integration.scenic.dto.scenic; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.List; - -@Data -public class ScenicV2ListResponse { - @JsonProperty("list") - private List list; - - @JsonProperty("total") - private Integer total; - - @JsonProperty("page") - private Integer page; - - @JsonProperty("pageSize") - private Integer pageSize; -} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/scenic/dto/scenic/ScenicV2WithConfigListResponse.java b/src/main/java/com/ycwl/basic/integration/scenic/dto/scenic/ScenicV2WithConfigListResponse.java deleted file mode 100644 index 4540036..0000000 --- a/src/main/java/com/ycwl/basic/integration/scenic/dto/scenic/ScenicV2WithConfigListResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.ycwl.basic.integration.scenic.dto.scenic; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.List; - -@Data -public class ScenicV2WithConfigListResponse { - @JsonProperty("list") - private List list; - - @JsonProperty("total") - private Integer total; - - @JsonProperty("page") - private Integer page; - - @JsonProperty("pageSize") - private Integer pageSize; -} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/scenic/service/DefaultConfigIntegrationService.java b/src/main/java/com/ycwl/basic/integration/scenic/service/ScenicDefaultConfigIntegrationService.java similarity index 98% rename from src/main/java/com/ycwl/basic/integration/scenic/service/DefaultConfigIntegrationService.java rename to src/main/java/com/ycwl/basic/integration/scenic/service/ScenicDefaultConfigIntegrationService.java index c06c020..7c6870e 100644 --- a/src/main/java/com/ycwl/basic/integration/scenic/service/DefaultConfigIntegrationService.java +++ b/src/main/java/com/ycwl/basic/integration/scenic/service/ScenicDefaultConfigIntegrationService.java @@ -13,7 +13,7 @@ import java.util.List; @Slf4j @Service @RequiredArgsConstructor -public class DefaultConfigIntegrationService { +public class ScenicDefaultConfigIntegrationService { private final DefaultConfigClient defaultConfigClient; diff --git a/src/main/java/com/ycwl/basic/integration/scenic/service/ScenicIntegrationService.java b/src/main/java/com/ycwl/basic/integration/scenic/service/ScenicIntegrationService.java index f390712..487918a 100644 --- a/src/main/java/com/ycwl/basic/integration/scenic/service/ScenicIntegrationService.java +++ b/src/main/java/com/ycwl/basic/integration/scenic/service/ScenicIntegrationService.java @@ -10,8 +10,7 @@ import com.ycwl.basic.integration.scenic.dto.filter.ScenicFilterRequest; import com.ycwl.basic.integration.scenic.dto.scenic.CreateScenicRequest; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigListResponse; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.scenic.dto.scenic.UpdateScenicRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -93,15 +92,15 @@ public class ScenicIntegrationService { return handleResponse(response, "筛选景区失败"); } - public ScenicV2ListResponse listScenics(Integer page, Integer pageSize, Integer status, String name) { + public PageResponse listScenics(Integer page, Integer pageSize, Integer status, String name) { log.debug("分页查询景区列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name); - CommonResponse response = scenicV2Client.listScenics(page, pageSize, status, name); + CommonResponse> response = scenicV2Client.listScenics(page, pageSize, status, name); return handleResponse(response, "分页查询景区列表失败"); } - public ScenicV2WithConfigListResponse listScenicsWithConfig(Integer page, Integer pageSize, Integer status, String name) { + public PageResponse listScenicsWithConfig(Integer page, Integer pageSize, Integer status, String name) { log.debug("分页查询景区带配置列表, page: {}, pageSize: {}, status: {}, name: {}", page, pageSize, status, name); - CommonResponse response = scenicV2Client.listScenicsWithConfig(page, pageSize, status, name); + CommonResponse> response = scenicV2Client.listScenicsWithConfig(page, pageSize, status, name); return handleResponse(response, "分页查询景区带配置列表失败"); } diff --git a/src/main/java/com/ycwl/basic/mapper/RenderWorkerMapper.java b/src/main/java/com/ycwl/basic/mapper/RenderWorkerMapper.java deleted file mode 100644 index d27ea7a..0000000 --- a/src/main/java/com/ycwl/basic/mapper/RenderWorkerMapper.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.ycwl.basic.mapper; - -import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity; -import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * @Author:longbinbin - * @Date:2024/11/29 17:22 - * 渲染机管理表 - */ -@Mapper -public interface RenderWorkerMapper { - List list(RenderWorkerReqQuery renderWorkerReqQuery); - RenderWorkerEntity getById(Long id); - int add(RenderWorkerEntity renderWorker); - int deleteById(Long id); - int update(RenderWorkerEntity renderWorker); - int updateStatus(Long id); - - RenderWorkerEntity findByAccessKey(String accessKey); - - int updateHost(Long id, RenderWorkerEntity status); -} diff --git a/src/main/java/com/ycwl/basic/model/pc/renderWorker/entity/RenderWorkerEntity.java b/src/main/java/com/ycwl/basic/model/pc/renderWorker/entity/RenderWorkerEntity.java index 627ff63..fcf8986 100644 --- a/src/main/java/com/ycwl/basic/model/pc/renderWorker/entity/RenderWorkerEntity.java +++ b/src/main/java/com/ycwl/basic/model/pc/renderWorker/entity/RenderWorkerEntity.java @@ -14,50 +14,16 @@ import java.util.Date; * 渲染机管理表 */ @Data -@TableName("render_worker") public class RenderWorkerEntity { - @TableId private Long id; /** * 渲染机名称 */ private String name; - /** - * 系统 - */ - private String platform; - /** - * 运行环境 - */ - private String runtimeVersion; - /** - * 版本 - */ - private String version; /** * 访问秘钥 */ private String accessKey; - /** - * cpu数量 - */ - private Integer cpuCount; - /** - * cpu使用率 - */ - private BigDecimal cpuUsage; - /** - * 内存总量,MB - */ - private BigDecimal memoryTotal; - /** - * 内存余量,MB - */ - private BigDecimal memoryAvailable; - /** - * 支持的功能,逗号隔开 - */ - private String supportFeature; /** * 是否仅用于指定景区,空或0不适用,否则为景区ID */ @@ -66,24 +32,10 @@ public class RenderWorkerEntity { * 是否仅用于测试,0不是,1是 */ private Integer testOnly; - /** - * 是否在线,0不在,1在 - */ - private Integer online; /** * 状态,0禁用,1启用 */ private Integer status; private Date createAt; private Date updateAt; - - - /** - * 存储类型 - */ - private StorageType storeType; - /** - * 存储配置 - */ - private String storeConfigJson; } diff --git a/src/main/java/com/ycwl/basic/repository/RenderWorkerRepository.java b/src/main/java/com/ycwl/basic/repository/RenderWorkerRepository.java index f58dff5..d5ffe88 100644 --- a/src/main/java/com/ycwl/basic/repository/RenderWorkerRepository.java +++ b/src/main/java/com/ycwl/basic/repository/RenderWorkerRepository.java @@ -1,50 +1,50 @@ package com.ycwl.basic.repository; import com.ycwl.basic.utils.JacksonUtil; -import com.ycwl.basic.mapper.RenderWorkerMapper; import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity; import com.ycwl.basic.model.task.req.ClientStatusReqVo; +import com.ycwl.basic.integration.render.dto.worker.RenderWorkerV2DTO; +import com.ycwl.basic.integration.render.service.RenderWorkerIntegrationService; +import com.ycwl.basic.integration.render.service.RenderWorkerConfigIntegrationService; +import com.ycwl.basic.integration.render.dto.config.RenderWorkerConfigV2DTO; +import com.ycwl.basic.integration.common.manager.RenderWorkerConfigManager; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.Date; +import java.util.List; import java.util.concurrent.TimeUnit; +@Slf4j @Component public class RenderWorkerRepository { @Autowired private RedisTemplate redisTemplate; - public static final String RENDER_WORKER_CACHE_KEY = "render_worker:%s"; public static final String RENDER_WORKER_STATUS_CACHE_KEY = "render_worker:host_status:%s"; + @Autowired - private RenderWorkerMapper mapper; + private RenderWorkerIntegrationService renderWorkerIntegrationService; + + @Autowired + private RenderWorkerConfigIntegrationService renderWorkerConfigIntegrationService; public RenderWorkerEntity getWorkerByAccessKey(String accessKey) { - String key = String.format(RENDER_WORKER_CACHE_KEY, accessKey); - if (redisTemplate.hasKey(key)) { - return JacksonUtil.parseObject(redisTemplate.opsForValue().get(key), RenderWorkerEntity.class); - } - RenderWorkerEntity renderWorker = mapper.findByAccessKey(accessKey); - if (renderWorker != null) { - redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS); - redisTemplate.opsForValue().set(String.format(RENDER_WORKER_CACHE_KEY, renderWorker.getId()), JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS); + RenderWorkerV2DTO workerDTO = renderWorkerIntegrationService.getWorkerByKey(accessKey); + if (workerDTO == null) { + return null; } + RenderWorkerEntity renderWorker = convertToEntity(workerDTO); return renderWorker; } public RenderWorkerEntity getWorker(Long id) { - String key = String.format(RENDER_WORKER_CACHE_KEY, id); - if (redisTemplate.hasKey(key)) { - return JacksonUtil.parseObject(redisTemplate.opsForValue().get(key), RenderWorkerEntity.class); - } - RenderWorkerEntity renderWorker = mapper.getById(id); - if (renderWorker != null) { - redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS); - redisTemplate.opsForValue().set(String.format(RENDER_WORKER_CACHE_KEY, renderWorker.getAccessKey()), JacksonUtil.toJSONString(renderWorker), 1, TimeUnit.HOURS); + RenderWorkerV2DTO workerDTO = renderWorkerIntegrationService.getWorker(id); + if (workerDTO == null) { + return null; } + RenderWorkerEntity renderWorker = convertToEntity(workerDTO); return renderWorker; } @@ -54,21 +54,6 @@ public class RenderWorkerRepository { return; } status.setUpdateAt(new Date()); - RenderWorkerEntity worker = new RenderWorkerEntity(); - worker.setCpuCount(status.getCpu_count()); - worker.setCpuUsage(status.getCpu_usage()); - // 上报的是字节,存储的是兆 - worker.setMemoryAvailable(status.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - worker.setMemoryTotal(status.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - - worker.setPlatform(status.getPlatform()); - worker.setRuntimeVersion(status.getRuntime_version()); - worker.setSupportFeature(String.join(",", status.getSupport_feature())); - worker.setVersion(status.getVersion()); - worker.setUpdateAt(status.getUpdateAt()); - if (!redisTemplate.hasKey(key)) { - mapper.updateHost(id, worker); - } redisTemplate.opsForValue().set(key, JacksonUtil.toJSONString(status), 1, TimeUnit.HOURS); } @@ -81,12 +66,34 @@ public class RenderWorkerRepository { return null; } - public void clearCache(Long id) { - RenderWorkerEntity worker = getWorker(id); - redisTemplate.delete(String.format(RENDER_WORKER_CACHE_KEY, id)); - if (worker != null) { - redisTemplate.delete(String.format(RENDER_WORKER_CACHE_KEY, worker.getAccessKey())); + private RenderWorkerEntity convertToEntity(RenderWorkerV2DTO dto) { + if (dto == null) { + return null; } - redisTemplate.delete(String.format(RENDER_WORKER_STATUS_CACHE_KEY, id)); + RenderWorkerEntity entity = new RenderWorkerEntity(); + entity.setId(dto.getId()); + entity.setName(dto.getName()); + entity.setAccessKey(dto.getKey()); + entity.setStatus(dto.getIsActive()); + entity.setCreateAt(dto.getCreateTime()); + entity.setUpdateAt(dto.getUpdateTime()); + return entity; } + + /** + * 获取渲染工作器配置管理器 + * + * @param workerId 工作器ID + * @return RenderWorkerConfigManager实例,如果获取失败返回null + */ + public RenderWorkerConfigManager getWorkerConfigManager(Long workerId) { + try { + List configList = renderWorkerConfigIntegrationService.getWorkerConfigs(workerId); + return new RenderWorkerConfigManager(configList); + } catch (Exception e) { + log.error("获取渲染工作器配置管理器失败, workerId: {}", workerId, e); + return null; + } + } + } diff --git a/src/main/java/com/ycwl/basic/repository/ScenicRepository.java b/src/main/java/com/ycwl/basic/repository/ScenicRepository.java index d9b8f9c..881bfc2 100644 --- a/src/main/java/com/ycwl/basic/repository/ScenicRepository.java +++ b/src/main/java/com/ycwl/basic/repository/ScenicRepository.java @@ -3,7 +3,7 @@ package com.ycwl.basic.repository; import com.ycwl.basic.facebody.enums.FaceBodyAdapterType; import com.ycwl.basic.integration.common.util.ConfigValueUtil; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; -import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2ListResponse; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2WithConfigDTO; import com.ycwl.basic.integration.scenic.service.ScenicIntegrationService; import com.ycwl.basic.integration.scenic.service.ScenicConfigIntegrationService; @@ -212,7 +212,7 @@ public class ScenicRepository { String name = scenicReqQuery.getName(); // 调用 zt-scenic 服务的 list 方法 - ScenicV2ListResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name); + PageResponse response = scenicIntegrationService.listScenics(page, pageSize, status, name); // 将 ScenicV2DTO 列表转换为 ScenicEntity 列表 if (response != null && response.getList() != null) { diff --git a/src/main/java/com/ycwl/basic/service/mobile/impl/AppScenicServiceImpl.java b/src/main/java/com/ycwl/basic/service/mobile/impl/AppScenicServiceImpl.java index d85165b..ef8b490 100644 --- a/src/main/java/com/ycwl/basic/service/mobile/impl/AppScenicServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/mobile/impl/AppScenicServiceImpl.java @@ -5,7 +5,8 @@ import com.github.pagehelper.PageInfo; import com.ycwl.basic.integration.common.manager.DeviceConfigManager; import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO; import com.ycwl.basic.integration.device.service.DeviceIntegrationService; -import com.ycwl.basic.integration.device.dto.device.DeviceV2ListResponse; +import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.mapper.ExtraDeviceMapper; import com.ycwl.basic.mapper.ScenicAccountMapper; import com.ycwl.basic.model.jwt.JwtInfo; @@ -86,7 +87,7 @@ public class AppScenicServiceImpl implements AppScenicService { public ApiResponse deviceCountByScenicId(Long scenicId) { JwtInfo worker = JwtTokenUtil.getWorker(); // 通过zt-device服务获取设备统计 - DeviceV2ListResponse deviceListResponse = deviceIntegrationService.getScenicActiveDevices(scenicId, 1, 1000); + PageResponse deviceListResponse = deviceIntegrationService.getScenicActiveDevices(scenicId, 1, 1000); ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO(); if (deviceListResponse != null && deviceListResponse.getList() != null) { scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size()); @@ -120,7 +121,7 @@ public class AppScenicServiceImpl implements AppScenicService { } // 通过zt-device服务获取设备统计 - DeviceV2ListResponse deviceListResponse = deviceIntegrationService.getScenicActiveDevices(id, 1, 1000); + PageResponse deviceListResponse = deviceIntegrationService.getScenicActiveDevices(id, 1, 1000); ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO(); if (deviceListResponse != null && deviceListResponse.getList() != null) { scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size()); @@ -276,7 +277,7 @@ public class AppScenicServiceImpl implements AppScenicService { @Override public ApiResponse> getDevices(Long scenicId) { - DeviceV2ListResponse deviceV2ListResponse = deviceIntegrationService.listDevices(1, 1000, null, null, null, 1, scenicId); + PageResponse deviceV2ListResponse = deviceIntegrationService.listDevices(1, 1000, null, null, null, 1, scenicId); List deviceRespVOList = deviceV2ListResponse.getList().stream().map(device -> { DeviceRespVO deviceRespVO = new DeviceRespVO(); deviceRespVO.setId(device.getId()); diff --git a/src/main/java/com/ycwl/basic/service/pc/RenderWorkerService.java b/src/main/java/com/ycwl/basic/service/pc/RenderWorkerService.java deleted file mode 100644 index ffd6c13..0000000 --- a/src/main/java/com/ycwl/basic/service/pc/RenderWorkerService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.ycwl.basic.service.pc; - -import com.github.pagehelper.PageInfo; -import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity; -import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery; -import com.ycwl.basic.utils.ApiResponse; - -import java.util.List; - -/** - * @Author:longbinbin - * @Date:2024/12/3 15:07 - */ -public interface RenderWorkerService { - ApiResponse> pageQuery(RenderWorkerReqQuery renderWorkerReqQuery); - ApiResponse> list(RenderWorkerReqQuery renderWorkerReqQuery); - ApiResponse detail(Long id); - ApiResponse add(RenderWorkerEntity renderWorker); - ApiResponse deleteById(Long id); - ApiResponse update(RenderWorkerEntity renderWorker); - ApiResponse updateStatus(Long id); -} diff --git a/src/main/java/com/ycwl/basic/service/pc/impl/RenderWorkerServiceImpl.java b/src/main/java/com/ycwl/basic/service/pc/impl/RenderWorkerServiceImpl.java deleted file mode 100644 index 322b948..0000000 --- a/src/main/java/com/ycwl/basic/service/pc/impl/RenderWorkerServiceImpl.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.ycwl.basic.service.pc.impl; - -import com.github.pagehelper.PageHelper; -import com.github.pagehelper.PageInfo; -import com.ycwl.basic.mapper.RenderWorkerMapper; -import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity; -import com.ycwl.basic.model.pc.renderWorker.req.RenderWorkerReqQuery; -import com.ycwl.basic.model.task.req.ClientStatusReqVo; -import com.ycwl.basic.repository.RenderWorkerRepository; -import com.ycwl.basic.service.pc.RenderWorkerService; -import com.ycwl.basic.utils.ApiResponse; -import com.ycwl.basic.utils.SnowFlakeUtil; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.List; - -/** - * @Author:longbinbin - * @Date:2024/12/3 15:09 - */ -@Service -public class RenderWorkerServiceImpl implements RenderWorkerService { - - @Autowired - private RenderWorkerMapper renderWorkerMapper; - @Autowired - private RenderWorkerRepository renderWorkerRepository; - - @Override - public ApiResponse> pageQuery(RenderWorkerReqQuery renderWorkerReqQuery) { - PageHelper.startPage(renderWorkerReqQuery.getPageNum(), renderWorkerReqQuery.getPageSize()); - List list = renderWorkerMapper.list(renderWorkerReqQuery); - list.forEach(worker -> { - ClientStatusReqVo clientStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId()); - if (clientStatus == null) { - return; - } - worker.setCpuCount(clientStatus.getCpu_count()); - worker.setCpuUsage(clientStatus.getCpu_usage()); - // 上报的是字节,存储的是兆 - worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - - worker.setPlatform(clientStatus.getPlatform()); - worker.setRuntimeVersion(clientStatus.getRuntime_version()); - worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature())); - worker.setVersion(clientStatus.getVersion()); - worker.setUpdateAt(clientStatus.getUpdateAt()); - }); - PageInfo pageInfo = new PageInfo<>(list); - return ApiResponse.success(pageInfo); - } - - @Override - public ApiResponse> list(RenderWorkerReqQuery renderWorkerReqQuery) { - List list = renderWorkerMapper.list(renderWorkerReqQuery); - list.forEach(worker -> { - ClientStatusReqVo clientStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId()); - if (clientStatus == null) { - return; - } - worker.setCpuCount(clientStatus.getCpu_count()); - worker.setCpuUsage(clientStatus.getCpu_usage()); - // 上报的是字节,存储的是兆 - worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - - worker.setPlatform(clientStatus.getPlatform()); - worker.setRuntimeVersion(clientStatus.getRuntime_version()); - worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature())); - worker.setVersion(clientStatus.getVersion()); - worker.setUpdateAt(clientStatus.getUpdateAt()); - }); - return ApiResponse.success(list); - } - - @Override - public ApiResponse detail(Long id) { - RenderWorkerEntity worker = renderWorkerMapper.getById(id); - - ClientStatusReqVo clientStatus = renderWorkerRepository.getWorkerHostStatus(worker.getId()); - if (clientStatus != null) { - worker.setCpuCount(clientStatus.getCpu_count()); - worker.setCpuUsage(clientStatus.getCpu_usage()); - // 上报的是字节,存储的是兆 - worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING)); - - worker.setPlatform(clientStatus.getPlatform()); - worker.setRuntimeVersion(clientStatus.getRuntime_version()); - worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature())); - worker.setVersion(clientStatus.getVersion()); - worker.setUpdateAt(clientStatus.getUpdateAt()); - } - return ApiResponse.success(worker); - } - - @Override - public ApiResponse add(RenderWorkerEntity renderWorker) { - renderWorker.setId(SnowFlakeUtil.getLongId()); - if (StringUtils.isEmpty(renderWorker.getAccessKey())) { - renderWorker.setAccessKey(SnowFlakeUtil.getId()); - } - renderWorker.setStatus(0); - int add = renderWorkerMapper.add(renderWorker); - if (add == 0) { - return ApiResponse.fail("渲染机添加失败"); - }else { - return ApiResponse.success(add); - } - } - - @Override - public ApiResponse deleteById(Long id) { - renderWorkerRepository.clearCache(id); - return ApiResponse.success(renderWorkerMapper.deleteById(id)); - } - - @Override - public ApiResponse update(RenderWorkerEntity renderWorker) { - renderWorkerRepository.clearCache(renderWorker.getId()); - int update = renderWorkerMapper.update(renderWorker); - if (update == 0) { - return ApiResponse.fail("渲染机修改失败"); - }else { - return ApiResponse.success(update); - } - } - - @Override - public ApiResponse updateStatus(Long id) { - renderWorkerRepository.clearCache(id); - return ApiResponse.success(renderWorkerMapper.updateStatus(id)); - } -} diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java index 3e07afd..c65b0ed 100644 --- a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java @@ -2,7 +2,8 @@ package com.ycwl.basic.service.task.impl; import cn.hutool.core.date.DateUtil; import cn.hutool.crypto.digest.MD5; -import com.ycwl.basic.integration.common.manager.DeviceConfigManager; +import com.ycwl.basic.integration.common.manager.RenderWorkerConfigManager; +import com.ycwl.basic.integration.common.manager.ScenicConfigManager; import com.ycwl.basic.utils.JacksonUtil; import com.ycwl.basic.biz.OrderBiz; import com.ycwl.basic.biz.TaskStatusBiz; @@ -12,7 +13,6 @@ import com.ycwl.basic.constant.TaskConstant; import com.ycwl.basic.mapper.FaceMapper; import com.ycwl.basic.mapper.FaceSampleMapper; import com.ycwl.basic.mapper.MemberMapper; -import com.ycwl.basic.mapper.RenderWorkerMapper; import com.ycwl.basic.mapper.SourceMapper; import com.ycwl.basic.mapper.TaskMapper; import com.ycwl.basic.mapper.TemplateMapper; @@ -83,6 +83,8 @@ import java.util.stream.Collectors; @Slf4j @Service public class TaskTaskServiceImpl implements TaskService { + private static final String WORKER_SELF_HOSTED_CACHE_KEY = "worker_self_hosted_scenic:%s"; + private static final int CACHE_EXPIRE_MINUTES = 3; @Autowired private TaskMapper taskMapper; @Autowired @@ -121,13 +123,40 @@ public class TaskTaskServiceImpl implements TaskService { private DeviceRepository deviceRepository; @Autowired private VideoReUploader videoReUploader; + @Autowired + private RedisTemplate redisTemplate; private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) { String accessKey = req.getAccessKey(); if (accessKey == null) { return null; } - return repository.getWorkerByAccessKey(accessKey); + RenderWorkerEntity worker = repository.getWorkerByAccessKey(accessKey); + if (worker == null) { + return null; + } + if (worker.getStatus() != 1) { + return null; + } + return worker; + } + + private boolean isWorkerSelfHostedScenic(Long scenicId) { + String cacheKey = String.format(WORKER_SELF_HOSTED_CACHE_KEY, scenicId); + String cachedValue = redisTemplate.opsForValue().get(cacheKey); + + if (cachedValue != null) { + return Boolean.parseBoolean(cachedValue); + } + + // 缓存中没有,查询配置 + ScenicConfigManager config = scenicRepository.getScenicConfigManager(scenicId); + boolean workerSelfHostedScenic = Boolean.TRUE.equals(config.getBoolean("worker_self_hosted")); + + // 缓存结果,设置30分钟过期 + redisTemplate.opsForValue().set(cacheKey, String.valueOf(workerSelfHostedScenic), CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES); + + return workerSelfHostedScenic; } @Override @@ -136,7 +165,6 @@ public class TaskTaskServiceImpl implements TaskService { if (worker == null) { return null; } - worker.setOnline(1); worker.setName(null); worker.setStatus(null); // get status @@ -162,21 +190,25 @@ public class TaskTaskServiceImpl implements TaskService { } else { updTemplateList = templateRepository.getAllEnabledTemplateList(); } + RenderWorkerConfigManager configManager = repository.getWorkerConfigManager(worker.getId()); try { if (lock.tryLock(2, TimeUnit.SECONDS)) { try { List taskList; - if (worker.getScenicOnly() != null) { - taskList = taskMapper.selectNotRunningByScenicList(worker.getScenicOnly()); + if (Strings.isNotBlank(configManager.getString("scenic_only"))) { + taskList = taskMapper.selectNotRunningByScenicList(configManager.getString("scenic_only")); } else { - taskList = taskMapper.selectNotRunning(); + var _taskList = taskMapper.selectNotRunning(); + taskList = _taskList.stream().filter(task -> { + boolean workerSelfHostedScenic = isWorkerSelfHostedScenic(task.getScenicId()); + return !workerSelfHostedScenic; + }).limit(1).toList(); } resp.setTasks(taskList); resp.setTemplates(updTemplateList); taskList.forEach(task -> { taskMapper.assignToWorker(task.getId(), worker.getId()); videoTaskRepository.clearTaskCache(task.getId()); - repository.clearCache(worker.getId()); }); } finally { lock.unlock(); @@ -551,10 +583,11 @@ public class TaskTaskServiceImpl implements TaskService { if (worker == null) { return null; } + RenderWorkerConfigManager config = repository.getWorkerConfigManager(worker.getId()); IStorageAdapter adapter; try { - adapter = StorageFactory.get(worker.getStoreType()); - adapter.loadConfig(JacksonUtil.parseObject(worker.getStoreConfigJson(), Map.class)); + adapter = StorageFactory.get(config.getString("store_type")); + adapter.loadConfig(config.getObject("store_config_json", Map.class)); } catch (Exception e) { adapter = scenicService.getScenicStorageAdapter(task.getScenicId()); } diff --git a/src/main/java/com/ycwl/basic/task/VideoPieceCleaner.java b/src/main/java/com/ycwl/basic/task/VideoPieceCleaner.java index 243d5be..4b73243 100644 --- a/src/main/java/com/ycwl/basic/task/VideoPieceCleaner.java +++ b/src/main/java/com/ycwl/basic/task/VideoPieceCleaner.java @@ -5,7 +5,7 @@ import com.ycwl.basic.device.DeviceFactory; import com.ycwl.basic.device.operator.IDeviceStorageOperator; import com.ycwl.basic.integration.common.manager.DeviceConfigManager; import com.ycwl.basic.integration.device.service.DeviceIntegrationService; -import com.ycwl.basic.integration.device.dto.device.DeviceV2ListResponse; +import com.ycwl.basic.integration.common.response.PageResponse; import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO; import java.util.stream.Collectors; import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity; @@ -37,9 +37,8 @@ public class VideoPieceCleaner { public void clean() { log.info("开始删除视频文件"); // 通过zt-device服务获取所有激活设备 - DeviceV2ListResponse deviceListResponse = deviceIntegrationService.listDevices(1, 10000, null, null, null, 1, null); - List deviceList; - if (deviceListResponse == null) { + PageResponse deviceListResponse = deviceIntegrationService.listDevices(1, 10000, null, null, null, 1, null); + if (deviceListResponse == null || deviceListResponse.getList() == null) { return; } for (DeviceV2DTO device : deviceListResponse.getList()) { diff --git a/src/main/resources/mapper/RenderWorkerMapper.xml b/src/main/resources/mapper/RenderWorkerMapper.xml deleted file mode 100644 index 4e47bf2..0000000 --- a/src/main/resources/mapper/RenderWorkerMapper.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - insert into render_worker(id, `name`, platform, runtime_version, version, access_key, - cpu_count, cpu_usage, memory_total, memory_available, support_feature, scenic_only, test_only, `online`, `status`) - VALUES (#{id}, #{name}, #{platform}, #{runtimeVersion}, #{version}, #{accessKey}, - #{cpuCount}, #{cpuUsage}, #{memoryTotal}, #{memoryAvailable}, #{supportFeature}, #{scenicOnly}, #{testOnly}, #{online}, #{status}) - - - - update render_worker - - - name = #{name}, - - - platform = #{platform}, - - - runtime_version = #{runtimeVersion}, - - - version = #{version}, - - - access_key = #{accessKey}, - - - cpu_count = #{cpuCount}, - - - cpu_usage = #{cpuUsage}, - - - memory_total = #{memoryTotal}, - - - memory_available = #{memoryAvailable}, - - - support_feature = #{supportFeature}, - - - scenic_only = #{scenicOnly}, - - - test_only = #{testOnly}, - - - `online` = #{online}, - - - where id = #{id} - - - update render_worker - set status = (CASE - status - WHEN 1 THEN - 0 - WHEN 0 THEN - 1 - ELSE null - END) - where id = #{id} - - - update render_worker - set platform = #{status.platform}, - runtime_version = #{status.runtimeVersion}, - version = #{status.version}, - cpu_count = #{status.cpuCount}, - cpu_usage = #{status.cpuUsage}, - memory_total = #{status.memoryTotal}, - memory_available = #{status.memoryAvailable}, - support_feature = #{status.supportFeature}, - update_at = #{status.updateAt} - where id = #{id} - - - delete from render_worker where id = #{id} - - - - - - \ No newline at end of file diff --git a/src/main/resources/mapper/TaskMapper.xml b/src/main/resources/mapper/TaskMapper.xml index dbfa2ee..6e51e0f 100644 --- a/src/main/resources/mapper/TaskMapper.xml +++ b/src/main/resources/mapper/TaskMapper.xml @@ -84,14 +84,6 @@ from task where status = 0 and worker_id is null - and NOT EXISTS ( - SELECT 1 - FROM render_worker rw - WHERE - rw.status = 1 - AND FIND_IN_SET(task.scenic_id, rw.scenic_only) > 0 -- 检查scenic_id是否在逗号分隔的字符串中 - ) - limit 1