fusenapi/server/websocket/internal/logic/ws_render_image_logic.go
laodaming a022e5a8d9 fix
2023-08-16 12:16:23 +08:00

269 lines
9.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package logic
import (
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/service/repositories"
"fusenapi/utils/hash"
"fusenapi/utils/websocket_data"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
"strconv"
)
// 云渲染属性
type renderProperty struct {
renderImageTask map[string]string //需要渲染的图片任务 key是taskId val 是renderId
renderImageTaskCtlChan chan renderImageControlChanItem //渲染任务新增移除的控制通道
}
// 渲染任务新增移除的控制通道的数据
type renderImageControlChanItem struct {
Option int // 0删除 1添加
TaskId string //map的key
RenderId string // map的val
}
// 渲染发送到组装数据组装数据
func (w *wsConnectItem) renderImage(data []byte) {
var renderImageData websocket_data.RenderImageReqMsg
if err := json.Unmarshal(data, &renderImageData); err != nil {
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket render image message:"+string(data)))
logx.Error("invalid format of websocket render image message", err)
return
}
logx.Info("收到请求云渲染图片数据:", renderImageData)
if renderImageData.RenderId == "" {
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket render image message:render_id is empty"))
logx.Error("invalid format of websocket render image message:render_id is empty")
return
}
if renderImageData.RenderData.ProductId <= 0 {
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket render image message:product_id "))
logx.Error("invalid format of websocket render image message:product_id")
return
}
if renderImageData.RenderData.TemplateTag == "" {
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket render image message:template_tag "))
logx.Error("invalid format of websocket render image message:template_tag")
return
}
//获取上传最近的logo
userMaterial, err := w.svcCtx.AllModels.FsUserMaterial.FindLatestOne(w.ctx, w.userId, w.guestId)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "failed to get user logo"))
logx.Error("failed to get user logo")
return
}
//使用默认logo(id=0)
userMaterialDefault, err := w.svcCtx.AllModels.FsUserMaterial.FindOneById(w.ctx, 0)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "default logo is not exists"))
return
}
logx.Error("default logo is not exists")
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "failed to get default logo"))
return
}
renderImageData.RenderData.Logo = *userMaterialDefault.ResourceUrl
} else {
renderImageData.RenderData.Logo = *userMaterial.ResourceUrl
}
//用户id赋值
renderImageData.RenderData.UserId = w.userId
renderImageData.RenderData.GuestId = w.guestId
//生成任务id
taskId := hash.JsonHashKey(renderImageData.RenderData)
//查询有没有缓存的资源,有就返回######################
resource, err := w.svcCtx.AllModels.FsResource.FindOneById(w.ctx, taskId)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("failed to find render resource:", err)
return
}
} else {
//返回给客户端
b := w.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
RenderId: renderImageData.RenderId,
Image: *resource.ResourceUrl,
})
//发送数据到out chan
w.sendToOutChan(b)
return
}
//###########################################
//把需要渲染的图片任务加进去
w.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{
Option: 1, //0删除 1添加
TaskId: taskId,
RenderId: renderImageData.RenderId,
}
//组装数据
go w.assembleRenderData(taskId, renderImageData)
}
// 组装数据发送给unity
func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.RenderImageReqMsg) {
defer func() {
if err := recover(); err != nil {
logx.Error("MqConsumerRenderAssemble panic:", err)
}
}()
//根据templateTag获取templateTagId(后续模板表的tag改成template_tag后可能就不需要这个步骤了)
templateTag, err := w.svcCtx.AllModels.FsProductTemplateTags.FindOneByTagName(w.ctx, info.RenderData.TemplateTag)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("can`t find template tag info by template tag:", info.RenderData.TemplateTag)
return
}
logx.Error("failed to get template tag info")
return
}
//获取模板(模板标签下的对一个物料的的模板)
productTemplate, err := w.svcCtx.AllModels.FsProductTemplateV2.FindOneByProductIdTagIdWithSizeTable(w.ctx, info.RenderData.ProductId, fmt.Sprintf("%d", templateTag.Id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("template info is not found")
return
}
logx.Error("failed to get template info:", err)
return
}
//获取刀版图
res, err := w.svcCtx.Repositories.ImageHandle.LogoCombine(w.ctx, &repositories.LogoCombineReq{
UserId: info.RenderData.UserId,
GuestId: info.RenderData.GuestId,
TemplateId: productTemplate.Id,
TemplateTag: info.RenderData.TemplateTag,
Website: info.RenderData.Website,
Slogan: info.RenderData.Slogan,
Address: info.RenderData.Address,
Phone: info.RenderData.Phone,
})
if err != nil {
logx.Error("合成刀版图失败:", err)
return
}
combineImage := "" //刀版图
if res != nil && res.ResourceUrl != nil {
combineImage = *res.ResourceUrl
} else {
logx.Error("合成刀版图失败,合成的刀版图是空指针:", err)
return
}
logx.Info("合成刀版图成功:", *res.ResourceUrl)
//获取渲染设置信息
element, err := w.svcCtx.AllModels.FsProductTemplateElement.FindOneByModelId(w.ctx, *productTemplate.ModelId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("element info is not found,model_id = ?", *productTemplate.ModelId)
return
}
logx.Error("failed to get element list,", err)
return
}
//组装数据
refletion := -1
if element.Refletion != nil && *element.Refletion != "" {
refletion, err = strconv.Atoi(*element.Refletion)
}
//组装data数据
var mode map[string]interface{}
if element.Mode != nil && *element.Mode != "" {
if err = json.Unmarshal([]byte(*element.Mode), &mode); err != nil {
logx.Error("faile to parse element mode json:", err)
return
}
}
tempData := make([]map[string]interface{}, 0, 3)
if element.Base != nil && *element.Base != "" {
tempData = append(tempData, map[string]interface{}{
"name": "model",
"data": "0," + combineImage + "," + *element.Base,
"type": "other",
"layer": "0",
"is_update": 1,
"mode": mode["model"],
})
}
if element.Shadow != nil && *element.Shadow != "" {
tempData = append(tempData, map[string]interface{}{
"name": "shadow",
"data": *element.Shadow,
"type": "other",
"layer": "0",
"is_update": 0,
"mode": mode["shadow"],
})
}
if element.ModelP != nil && *element.ModelP != "" {
tempData = append(tempData, map[string]interface{}{
"name": "model_P",
"data": "0," + *element.ModelP,
"type": "other",
"layer": "0",
"is_update": 0,
"mode": mode["model_P"],
})
}
result := []interface{}{
map[string]interface{}{
"light": *element.Light,
"refletion": refletion,
"scale": *element.Scale,
"sku_id": info.RenderData.ProductId,
"tid": *element.Title,
"rotation": *element.Rotation,
"filePath": "", //todo 文件路径,针对千人千面
"data": tempData,
},
}
sendData := map[string]interface{}{
"id": taskId,
"order_id": 0,
"user_id": info.RenderData.UserId,
"guest_id": info.RenderData.GuestId,
"sku_ids": []int64{info.RenderData.ProductId},
"tids": []string{*element.Title},
"data": result,
"is_thousand_face": 0,
"folder": "", //todo 千人千面需要使用
}
/*b, _ := json.Marshal(sendData)
if err = rabbitmq.SendMsg(constants.RABBIT_MQ_TO_UNITY, b); err != nil {
logx.Error("发送渲染组装数据到rabbitmq失败", err)
return nil
}
logx.Info("发送渲染组装数据到unity成功")*/
// todo 请求unity接口 /api/render/queue/push
logx.Info(sendData["id"])
//模拟发送回去(unity部署后要去掉)
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
RenderId: info.RenderId,
Image: "https://fusenh5.kayue.cn:8011/storage/test/final_k8TgMUxauc_temp.png",
}))
return
}
// 操作连接中渲染任务的增加/删除
func (w *wsConnectItem) operationRenderTask() {
for {
select {
case <-w.closeChan:
return
case data := <-w.renderProperty.renderImageTaskCtlChan:
switch data.Option {
case 0: //删除任务
delete(w.renderProperty.renderImageTask, data.TaskId)
case 1: //新增任务
w.renderProperty.renderImageTask[data.TaskId] = data.RenderId
}
}
}
}