package cn.yinlihupo.controller.project; import cn.yinlihupo.common.core.BaseResponse; import cn.yinlihupo.common.enums.AsyncTaskStatus; import cn.yinlihupo.common.sse.SseChannelManager; import cn.yinlihupo.common.sse.SseMessage; import cn.yinlihupo.common.util.ResultUtils; import cn.yinlihupo.service.project.ProjectInitAsyncService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.util.HashMap; import java.util.Map; /** * 项目初始化 SSE 控制器 * 使用通用 SSE 通道管理器,通过 userId 绑定,type 字段区分业务 */ @Slf4j @RestController @RequestMapping("/api/v1/project-init") @RequiredArgsConstructor public class ProjectInitSseController { private final ProjectInitAsyncService projectInitAsyncService; private final SseChannelManager sseChannelManager; /** * 消息类型常量 */ private static final String MESSAGE_TYPE = "project-init"; /** * 通过 SSE 提交项目初始化任务 * 使用通用 SSE 通道,通过 userId 推送进度 * * @param userId 用户ID * @param file 项目资料文件 * @return 提交结果 */ @PostMapping("/sse/submit-task") public BaseResponse> submitTaskWithSse(@RequestParam("userId") String userId, @RequestParam("file") MultipartFile file) { log.info("用户通过SSE提交任务, userId: {}, 文件名: {}", userId, file.getOriginalFilename()); if (file.isEmpty()) { return ResultUtils.error("上传文件不能为空"); } // 检查用户是否在线 if (!sseChannelManager.isOnline(userId)) { return ResultUtils.error("用户未建立SSE连接,请先调用 /api/v1/sse/connect/" + userId); } try { // 提交异步任务,带进度回调 String taskId = projectInitAsyncService.submitPreviewTask(file, taskVO -> { // 构建消息并推送 SseMessage message = SseMessage.of(MESSAGE_TYPE, "progress", userId, taskVO); sseChannelManager.send(userId, message); // 任务完成或失败,推送完成事件 if (isTaskFinished(taskVO.getStatus())) { SseMessage completeMessage = SseMessage.of(MESSAGE_TYPE, "complete", userId, taskVO); sseChannelManager.send(userId, completeMessage); } }); // 推送任务提交成功事件 Map submittedData = new HashMap<>(); submittedData.put("taskId", taskId); submittedData.put("message", "任务已提交"); SseMessage submittedMessage = SseMessage.of(MESSAGE_TYPE, "submitted", userId, submittedData); sseChannelManager.send(userId, submittedMessage); log.info("任务提交成功并通过SSE推送, userId: {}, taskId: {}", userId, taskId); Map result = new HashMap<>(); result.put("taskId", taskId); result.put("message", "任务已提交,进度将通过SSE推送"); return ResultUtils.success("提交成功", result); } catch (Exception e) { log.error("提交任务失败, userId: {}, error: {}", userId, e.getMessage(), e); // 推送错误事件 Map errorData = new HashMap<>(); errorData.put("error", e.getMessage()); SseMessage errorMessage = SseMessage.of(MESSAGE_TYPE, "error", userId, errorData); sseChannelManager.send(userId, errorMessage); return ResultUtils.error("提交失败: " + e.getMessage()); } } // ==================== 工具方法 ==================== private boolean isTaskFinished(String status) { return AsyncTaskStatus.COMPLETED.getCode().equals(status) || AsyncTaskStatus.FAILED.getCode().equals(status) || AsyncTaskStatus.CANCELLED.getCode().equals(status); } private void sendErrorAndClose(String userId, String errorMessage) { Map errorData = new HashMap<>(); errorData.put("error", errorMessage); SseMessage errorMessage_obj = SseMessage.of(MESSAGE_TYPE, "error", userId, errorData); sseChannelManager.send(userId, errorMessage_obj); sseChannelManager.closeChannel(userId); } }