You've already forked FrameTour-BE
渲染端渲染流程
This commit is contained in:
7
src/main/java/com/ycwl/basic/constant/TaskConstant.java
Normal file
7
src/main/java/com/ycwl/basic/constant/TaskConstant.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.constant;
|
||||
|
||||
public class TaskConstant {
|
||||
public static final String TASK_TEMPLATE_KEY_PFX="task:template:cache:";
|
||||
public static final String TASK_ONLINE_WORKER_KEY_PFX="task:online_worker:";
|
||||
public static final String TASK_WORKER_TASK_KEY_PFX="task:worker:task:";
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.ycwl.basic.controller.task;
|
||||
|
||||
import com.ycwl.basic.annotation.IgnoreToken;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.model.task.req.TaskReqVo;
|
||||
import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
|
||||
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
|
||||
import com.ycwl.basic.service.task.TaskService;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@IgnoreToken
|
||||
@RestController
|
||||
@RequestMapping("/task/v1/")
|
||||
public class TaskTaskController {
|
||||
|
||||
@Autowired
|
||||
private TaskService taskService;
|
||||
@PostMapping("/sync")
|
||||
public ApiResponse<TaskSyncRespVo> sync(@RequestBody TaskReqVo req) {
|
||||
TaskSyncRespVo respVo = taskService.handleSyncTask(req);
|
||||
if (respVo == null) {
|
||||
return ApiResponse.fail("错误");
|
||||
}
|
||||
return ApiResponse.success(respVo);
|
||||
}
|
||||
|
||||
@PostMapping("/template/{templateId}")
|
||||
public ApiResponse<TemplateRespVO> getTemplateById(@PathVariable Long templateId, @RequestBody WorkerAuthReqVo req) {
|
||||
return ApiResponse.success(taskService.workerGetTemplate(templateId, req));
|
||||
}
|
||||
|
||||
@PostMapping("/{taskId}/uploadUrl")
|
||||
public ApiResponse<String> getUploadUrl(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
|
||||
return ApiResponse.success(taskService.getUploadUrl(taskId, req));
|
||||
}
|
||||
|
||||
@PostMapping("/{taskId}/success")
|
||||
public ApiResponse taskSuccess(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
|
||||
taskService.taskSuccess(taskId, req);
|
||||
return ApiResponse.success("OK");
|
||||
}
|
||||
|
||||
@PostMapping("/{taskId}/fail")
|
||||
public ApiResponse taskFail(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
|
||||
taskService.taskFail(taskId, req);
|
||||
return ApiResponse.success("OK");
|
||||
}
|
||||
|
||||
@PostMapping("/test/createRenderTask/{scenicId}/{templateId}/{faceId}")
|
||||
public ApiResponse<String> createRenderTask(@PathVariable Long scenicId, @PathVariable Long templateId, @PathVariable Long faceId) {
|
||||
taskService.createRenderTask(scenicId, templateId, faceId);
|
||||
return ApiResponse.success("ok");
|
||||
}
|
||||
}
|
@ -19,4 +19,6 @@ public interface RenderWorkerMapper {
|
||||
int deleteById(Long id);
|
||||
int update(RenderWorkerEntity renderWorker);
|
||||
int updateStatus(Long id);
|
||||
|
||||
RenderWorkerEntity findByAccessKey(String accessKey);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.task.req.TaskReqQuery;
|
||||
import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -41,4 +42,9 @@ public interface TaskMapper {
|
||||
* @return
|
||||
*/
|
||||
int countByMemberIdStauFinish(String userId);
|
||||
|
||||
List<TaskRespVO> selectNotRunning();
|
||||
|
||||
void assignToWorker(@Param("taskId") Long taskId, @Param("workerId") Long workerId);
|
||||
void deassign(@Param("taskId") Long taskId);
|
||||
}
|
||||
|
@ -55,4 +55,5 @@ public class FaceSampleRespVO {
|
||||
private Date createAt;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateAt;
|
||||
private Long sourceId;
|
||||
}
|
||||
|
@ -70,4 +70,5 @@ public class MemberRespVO {
|
||||
private Date createDate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateAt;
|
||||
private Integer orderCount;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import java.util.Date;
|
||||
@Data
|
||||
@ApiModel(value = "订单查询对象")
|
||||
public class OrderReqQuery extends BaseQueryParameterReq {
|
||||
private Long id;
|
||||
private Long memberId;
|
||||
@ApiModelProperty("用户昵称")
|
||||
private String memberNickname;
|
||||
|
@ -24,6 +24,10 @@ public class TaskEntity {
|
||||
* 用户ID,可以不和用户关联
|
||||
*/
|
||||
private Long memberId;
|
||||
/**
|
||||
* 人脸ID,face.id
|
||||
*/
|
||||
private Long faceId;
|
||||
/**
|
||||
* 模板ID
|
||||
*/
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.ycwl.basic.model.task.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ClientStatusReqVo {
|
||||
private String platform;
|
||||
private String runtime_version;
|
||||
private String version;
|
||||
private Integer cpu_count;
|
||||
private BigDecimal cpu_usage;
|
||||
private BigDecimal memory_total;
|
||||
private BigDecimal memory_available;
|
||||
private List<String> support_feature;
|
||||
}
|
10
src/main/java/com/ycwl/basic/model/task/req/TaskReqVo.java
Normal file
10
src/main/java/com/ycwl/basic/model/task/req/TaskReqVo.java
Normal file
@ -0,0 +1,10 @@
|
||||
package com.ycwl.basic.model.task.req;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class TaskReqVo extends WorkerAuthReqVo {
|
||||
private ClientStatusReqVo clientStatus;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.ycwl.basic.model.task.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WorkerAuthReqVo {
|
||||
private String accessKey;
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.ycwl.basic.model.task.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TaskItemRespVo {
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.ycwl.basic.model.task.resp;
|
||||
|
||||
import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class TaskSyncRespVo {
|
||||
private List<TaskRespVO> tasks = new ArrayList<>();
|
||||
private List<TemplateRespVO> templates = new ArrayList<>();
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
package com.ycwl.basic.service.impl.task;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ycwl.basic.constant.TaskConstant;
|
||||
import com.ycwl.basic.mapper.pc.FaceMapper;
|
||||
import com.ycwl.basic.mapper.pc.FaceSampleMapper;
|
||||
import com.ycwl.basic.mapper.pc.RenderWorkerMapper;
|
||||
import com.ycwl.basic.mapper.pc.SourceMapper;
|
||||
import com.ycwl.basic.mapper.pc.TaskMapper;
|
||||
import com.ycwl.basic.mapper.pc.TemplateMapper;
|
||||
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
|
||||
import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
|
||||
import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
|
||||
import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
|
||||
import com.ycwl.basic.model.pc.task.entity.TaskEntity;
|
||||
import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
|
||||
import com.ycwl.basic.model.pc.template.req.TemplateReqQuery;
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.model.task.req.ClientStatusReqVo;
|
||||
import com.ycwl.basic.model.task.req.TaskReqVo;
|
||||
import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
|
||||
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
|
||||
import com.ycwl.basic.service.task.TaskService;
|
||||
import com.ycwl.basic.utils.OssUtil;
|
||||
import com.ycwl.basic.utils.SnowFlakeUtil;
|
||||
import lombok.NonNull;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class TaskTaskServiceImpl implements TaskService {
|
||||
@Autowired
|
||||
private TemplateMapper templateMapper;
|
||||
@Autowired
|
||||
private RenderWorkerMapper renderWorkerMapper;
|
||||
@Autowired
|
||||
private TaskMapper taskMapper;
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private FaceMapper faceMapper;
|
||||
@Autowired
|
||||
private FaceSampleMapper faceSampleMapper;
|
||||
@Autowired
|
||||
private SourceMapper sourceMapper;
|
||||
@Autowired
|
||||
private OssUtil ossUtil;
|
||||
|
||||
private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
|
||||
String accessKey = req.getAccessKey();
|
||||
if (accessKey == null) {
|
||||
return null;
|
||||
}
|
||||
RenderWorkerEntity worker = renderWorkerMapper.findByAccessKey(accessKey);
|
||||
return worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskSyncRespVo handleSyncTask(@NonNull TaskReqVo req) {
|
||||
RenderWorkerEntity worker = getWorker(req);
|
||||
if (worker == null) {
|
||||
return null;
|
||||
}
|
||||
worker.setOnline(1);
|
||||
worker.setName(null);
|
||||
worker.setStatus(null);
|
||||
// get status
|
||||
ClientStatusReqVo clientStatus = req.getClientStatus();
|
||||
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(new Date());
|
||||
redisTemplate.opsForValue().set(TaskConstant.TASK_ONLINE_WORKER_KEY_PFX + worker.getId(), JSON.toJSONString(clientStatus), 60, TimeUnit.SECONDS);
|
||||
}
|
||||
renderWorkerMapper.update(worker);
|
||||
TaskSyncRespVo resp = new TaskSyncRespVo();
|
||||
// Template
|
||||
String cacheJson = redisTemplate.opsForValue().get(TaskConstant.TASK_TEMPLATE_KEY_PFX + worker.getId());
|
||||
if (cacheJson == null) {
|
||||
List<TemplateRespVO> templateList = templateMapper.list(new TemplateReqQuery());
|
||||
for (TemplateRespVO template : templateList) {
|
||||
template.setChildren(templateMapper.getByPid(template.getId()));
|
||||
}
|
||||
resp.setTemplates(templateList);
|
||||
redisTemplate.opsForValue().set(TaskConstant.TASK_TEMPLATE_KEY_PFX + worker.getId(), JSON.toJSONString(templateList), 60, TimeUnit.SECONDS);
|
||||
} else {
|
||||
resp.setTemplates(JSON.parseArray(cacheJson, TemplateRespVO.class));
|
||||
}
|
||||
List<TaskRespVO> taskList = taskMapper.selectNotRunning();
|
||||
resp.setTasks(taskList);
|
||||
taskList.forEach(task -> {
|
||||
taskMapper.assignToWorker(task.getId(), worker.getId());
|
||||
});
|
||||
// return Task
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRenderTask(Long scenicId, Long templateId, Long faceId) {
|
||||
// 有人脸,找视频
|
||||
if (faceId == null) {
|
||||
return;
|
||||
}
|
||||
FaceRespVO faceRespVO = faceMapper.getById(faceId);
|
||||
if (faceRespVO == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, List<SourceRespVO>> sourcesMap = Arrays.stream(faceRespVO.getMatchSampleIds().split(","))
|
||||
.map(Long::valueOf)
|
||||
.map(sampleId -> {
|
||||
return faceSampleMapper.getById(sampleId);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.map(FaceSampleRespVO::getSourceId)
|
||||
.map(sourceId -> sourceMapper.getById(sourceId))
|
||||
.collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
|
||||
TaskEntity taskEntity = new TaskEntity();
|
||||
taskEntity.setId(SnowFlakeUtil.getLongId());
|
||||
taskEntity.setFaceId(faceId);
|
||||
taskEntity.setMemberId(faceRespVO.getMemberId());
|
||||
taskEntity.setTemplateId(templateId);
|
||||
taskEntity.setScenicId(scenicId);
|
||||
taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
|
||||
taskEntity.setStatus(0);
|
||||
taskMapper.add(taskEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateRespVO workerGetTemplate(@NonNull Long templateId, @NonNull WorkerAuthReqVo req) {
|
||||
if (templateId == null) {
|
||||
return null;
|
||||
}
|
||||
RenderWorkerEntity worker = getWorker(req);
|
||||
if (worker == null) {
|
||||
return null;
|
||||
}
|
||||
TemplateRespVO respVO = templateMapper.getById(templateId);
|
||||
respVO.setChildren(templateMapper.getByPid(templateId));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskSuccess(@NonNull Long taskId, @NonNull WorkerAuthReqVo req) {
|
||||
TaskRespVO task = taskMapper.getById(taskId);
|
||||
if (task == null) {
|
||||
return;
|
||||
}
|
||||
RenderWorkerEntity worker = getWorker(req);
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
TaskEntity taskUpdate = new TaskEntity();
|
||||
taskUpdate.setId(taskId);
|
||||
taskUpdate.setStatus(1);
|
||||
taskUpdate.setWorkerId(worker.getId());
|
||||
taskMapper.update(taskUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskFail(Long taskId, WorkerAuthReqVo req) {
|
||||
TaskRespVO task = taskMapper.getById(taskId);
|
||||
if (task == null) {
|
||||
return;
|
||||
}
|
||||
RenderWorkerEntity worker = getWorker(req);
|
||||
if (worker == null) {
|
||||
return;
|
||||
}
|
||||
TaskEntity taskUpdate = new TaskEntity();
|
||||
taskUpdate.setId(taskId);
|
||||
taskUpdate.setStatus(2);
|
||||
taskUpdate.setWorkerId(worker.getId());
|
||||
taskMapper.update(taskUpdate);
|
||||
taskMapper.deassign(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUploadUrl(Long taskId, WorkerAuthReqVo req) {
|
||||
TaskRespVO task = taskMapper.getById(taskId);
|
||||
if (task == null) {
|
||||
return null;
|
||||
}
|
||||
String filename = task.getId() + "_" + task.getScenicId() + ".mp4";
|
||||
if (StringUtils.isBlank(task.getVideoUrl())) {
|
||||
// 生成
|
||||
String url = ossUtil.generateUrlOfFile("user-video/", filename);
|
||||
TaskEntity updateTask = new TaskEntity();
|
||||
updateTask.setId(taskId);
|
||||
updateTask.setVideoUrl(url);
|
||||
taskMapper.update(updateTask);
|
||||
}
|
||||
return ossUtil.generateSignedUrlForUpload("user-video/", filename);
|
||||
}
|
||||
}
|
19
src/main/java/com/ycwl/basic/service/task/TaskService.java
Normal file
19
src/main/java/com/ycwl/basic/service/task/TaskService.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.ycwl.basic.service.task;
|
||||
|
||||
import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
|
||||
import com.ycwl.basic.model.task.req.TaskReqVo;
|
||||
import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
|
||||
import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
|
||||
|
||||
public interface TaskService {
|
||||
TaskSyncRespVo handleSyncTask(TaskReqVo req);
|
||||
void createRenderTask(Long scenicId, Long templateId, Long faceId);
|
||||
|
||||
TemplateRespVO workerGetTemplate(Long templateId, WorkerAuthReqVo req);
|
||||
|
||||
void taskSuccess(Long taskId, WorkerAuthReqVo req);
|
||||
|
||||
void taskFail(Long taskId, WorkerAuthReqVo req);
|
||||
|
||||
String getUploadUrl(Long taskId, WorkerAuthReqVo req);
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
package com.ycwl.basic.utils;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.aliyun.oss.ClientException;
|
||||
import com.aliyun.oss.HttpMethod;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.OSSException;
|
||||
@ -12,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@ -27,7 +30,15 @@ public class OssUtil {
|
||||
* @return
|
||||
*/
|
||||
public String uploadFile(InputStream inputStream, String filename) {
|
||||
String uploadFileName = ossConfig.getObjectName() + filename;
|
||||
return uploadFile(inputStream, ossConfig.getObjectName(), filename);
|
||||
}
|
||||
|
||||
public String uploadAssetFile(InputStream inputStream, String filename) {
|
||||
return uploadFile(inputStream, "assets/", filename);
|
||||
}
|
||||
|
||||
public String uploadFile(InputStream inputStream, String path, String filename) {
|
||||
String uploadFileName = path + filename;
|
||||
OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
|
||||
try {
|
||||
PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), uploadFileName, inputStream);
|
||||
@ -57,6 +68,24 @@ public class OssUtil {
|
||||
return BizCodeEnum.UPLOAD_FAILED.getMessage();
|
||||
}
|
||||
|
||||
public String generateSignedUrlForDownload(String path, String filename) {
|
||||
String downloadFile = path + filename;
|
||||
return generateSignedUrl(downloadFile, HttpMethod.GET);
|
||||
}
|
||||
|
||||
public String generateSignedUrlForUpload(String path, String filename) {
|
||||
String uploadFileName = path + filename;
|
||||
return generateSignedUrl(uploadFileName, HttpMethod.PUT);
|
||||
}
|
||||
|
||||
public String generateSignedUrl(String objectName, HttpMethod method) {
|
||||
OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
|
||||
return ossClient.generatePresignedUrl(ossConfig.getBucketName(), objectName, DateUtil.offsetHour(new Date(), 1), method).toString();
|
||||
}
|
||||
public String generateUrlOfFile(String path, String filename) {
|
||||
String objectName = path + filename;
|
||||
return ossConfig.getUrl() + objectName;
|
||||
}
|
||||
|
||||
public boolean deleteFile(String filename) {
|
||||
// 填写文件完整路径。文件完整路径中不能包含Bucket名称。
|
||||
|
Reference in New Issue
Block a user