Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into feature/auth

This commit is contained in:
eson 2023-08-17 14:10:20 +08:00
commit d012ef5f83
48 changed files with 444 additions and 471 deletions

View File

@ -4,17 +4,16 @@ type RABBIT_MQ string
// 消息队列队列名
const (
//组装渲染数据队列
RABBIT_MQ_ASSEMBLE_RENDER_DATA RABBIT_MQ = "RABBIT_MQ_ASSEMBLE_RENDER_DATA"
//渲染结果数据队列
RABBIT_MQ_RENDER_RESULT_DATA RABBIT_MQ = "RABBIT_MQ_RENDER_RESULT_DATA"
//原来发送到unity渲染的队列
RABBIT_MQ_TO_UNITY RABBIT_MQ = "newTaskQueue"
//组装渲染数据队列
/*RABBIT_MQ_ASSEMBLE_RENDER_DATA RABBIT_MQ = "RABBIT_MQ_ASSEMBLE_RENDER_DATA"
//渲染结果数据队列
RABBIT_MQ_RENDER_RESULT_DATA RABBIT_MQ = "RABBIT_MQ_RENDER_RESULT_DATA"*/
)
// 队列列表
var MqQueueArr = []RABBIT_MQ{
RABBIT_MQ_ASSEMBLE_RENDER_DATA,
RABBIT_MQ_RENDER_RESULT_DATA,
RABBIT_MQ_TO_UNITY,
/*
RABBIT_MQ_ASSEMBLE_RENDER_DATA,
RABBIT_MQ_RENDER_RESULT_DATA,
*/
}

View File

@ -5,7 +5,7 @@ import "context"
// TODO: 使用model的属性做你想做的
type GetTagPropByProductIdsWithProductTagRsp struct {
FsProductTagProp
Title string `json:"title"`
TemplateTag string `json:"template_tag"`
}
func (p *FsProductTagPropModel) GetTagPropByProductIdsWithProductTag(ctx context.Context, productIds []int64) (resp []GetTagPropByProductIdsWithProductTagRsp, err error) {
@ -14,7 +14,7 @@ func (p *FsProductTagPropModel) GetTagPropByProductIdsWithProductTag(ctx context
}
err = p.db.WithContext(ctx).Table(p.name+" as p ").
Joins("left join fs_product_template_tags as t on p.template_tag_id = t.id").
Select("p.*,t.title as title").
Select("p.*,t.template_tag as template_tag").
Where("p.product_id in (?) and p.status = ? and t.status = ?", productIds, 1, 1).
Find(&resp).Error
return resp, err

View File

@ -6,26 +6,26 @@ import (
// fs_product_template_element 云渲染配置表
type FsProductTemplateElement struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
Title *string `gorm:"default:'';" json:"title"` // 产品模板名称
ProductTemplateId *int64 `gorm:"index;default:0;" json:"product_template_id"` // 产品模板id
Main *string `gorm:"default:'';" json:"main"` //
Second *string `gorm:"default:'';" json:"second"` //
Base *string `gorm:"default:'';" json:"base"` //
Paper *string `gorm:"default:'';" json:"paper"` //
Spoon *string `gorm:"default:'';" json:"spoon"` //
Fork *string `gorm:"default:'';" json:"fork"` //
Toothpick *string `gorm:"default:'';" json:"toothpick"` //
Chopsticks *string `gorm:"default:'';" json:"chopsticks"` //
Shadow *string `gorm:"default:'';" json:"shadow"` //
Cover *string `gorm:"default:'';" json:"cover"` //
Cover1 *string `gorm:"default:'';" json:"cover1"` //
Mode *string `gorm:"default:'';" json:"mode"` //
Light *int64 `gorm:"default:0;" json:"light"` //
Rotation *string `gorm:"default:'';" json:"rotation"` //
Scale *string `gorm:"default:'';" json:"scale"` //
ModelP *string `gorm:"default:'';" json:"model_p"` // 配件对应的云渲染贴图数据
Refletion *string `gorm:"default:'';" json:"refletion"` // 反射探头组
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // id
Title *string `gorm:"default:'';" json:"title"` // 产品模板名称
ModelId *int64 `gorm:"index;default:0;" json:"model_id"` // 模型id
Main *string `gorm:"default:'';" json:"main"` //
Second *string `gorm:"default:'';" json:"second"` //
Base *string `gorm:"default:'';" json:"base"` //
Paper *string `gorm:"default:'';" json:"paper"` //
Spoon *string `gorm:"default:'';" json:"spoon"` //
Fork *string `gorm:"default:'';" json:"fork"` //
Toothpick *string `gorm:"default:'';" json:"toothpick"` //
Chopsticks *string `gorm:"default:'';" json:"chopsticks"` //
Shadow *string `gorm:"default:'';" json:"shadow"` //
Cover *string `gorm:"default:'';" json:"cover"` //
Cover1 *string `gorm:"default:'';" json:"cover1"` //
Mode *string `gorm:"default:'';" json:"mode"` //
Light *int64 `gorm:"default:0;" json:"light"` //
Rotation *string `gorm:"default:'';" json:"rotation"` //
Scale *string `gorm:"default:'';" json:"scale"` //
ModelP *string `gorm:"default:'';" json:"model_p"` // 配件对应的云渲染贴图数据
Refletion *string `gorm:"default:'';" json:"refletion"` // 反射探头组
}
type FsProductTemplateElementModel struct {
db *gorm.DB

View File

@ -7,7 +7,7 @@ import "context"
func (e *FsProductTemplateElementModel) FindOneByModelId(ctx context.Context, modelId int64) (resp *FsProductTemplateElement, err error) {
err = e.db.WithContext(ctx).Model(&FsProductTemplateElement{}).
//以前的神仙员工把表model_id变成product_template_id
Where("`product_template_id` = ?", modelId).
Where("`model_id` = ?", modelId).
Take(&resp).Error
return resp, err
}

View File

@ -6,12 +6,12 @@ import (
// fs_product_template_tags 模板标签表
type FsProductTemplateTags struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // ID
Title *string `gorm:"unique_key;default:'';" json:"title"` // 标题
Cover *string `gorm:"default:'';" json:"cover"` // 封面图
Status *int64 `gorm:"default:0;" json:"status"` // 状态 1可用
CreateAt *int64 `gorm:"default:0;" json:"create_at"` // 创建时间
Groups *string `gorm:"default:'';" json:"groups"` // 分组信息
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // ID
TemplateTag *string `gorm:"unique_key;default:'';" json:"template_tag"` // 标题
Cover *string `gorm:"default:'';" json:"cover"` // 封面图
Status *int64 `gorm:"default:0;" json:"status"` // 状态 1可用
CreateAt *int64 `gorm:"default:0;" json:"create_at"` // 创建时间
Groups *string `gorm:"default:'';" json:"groups"` // 分组信息
}
type FsProductTemplateTagsModel struct {
db *gorm.DB

View File

@ -36,14 +36,18 @@ func (pt *FsProductTemplateTagsModel) GetListByTagNames(ctx context.Context, tag
if len(tagNames) == 0 {
return nil, nil
}
db := pt.db.WithContext(ctx).Model(&FsProductTemplateTags{}).Where("`title` in (?) and `status` = ?", tagNames, 1)
db := pt.db.WithContext(ctx).Model(&FsProductTemplateTags{}).Where("`template_tag` in (?) and `status` = ?", tagNames, 1)
if orderBy != "" {
db = db.Order(orderBy)
}
err = db.Limit(limit).Find(&resp).Error
return resp, err
}
func (pt *FsProductTemplateTagsModel) FindOneByTagName(ctx context.Context, tagName string) (resp *FsProductTemplateTags, err error) {
err = pt.db.WithContext(ctx).Model(&FsProductTemplateTags{}).Where("`title` = ? and `status` = ?", tagName, 1).Take(&resp).Error
func (pt *FsProductTemplateTagsModel) FindOneByTagName(ctx context.Context, tagName string, fields ...string) (resp *FsProductTemplateTags, err error) {
db := pt.db.WithContext(ctx).Model(&FsProductTemplateTags{}).Where("`template_tag` = ? and `status` = ?", tagName, 1)
if len(fields) != 0 {
db = db.Select(fields[0])
}
err = db.Take(&resp).Error
return resp, err
}

View File

@ -20,10 +20,9 @@ type FsProductTemplateV2 struct {
IsPublic *int64 `gorm:"default:0;" json:"is_public"` // 是否可公用1:可以0不可以
Status *int64 `gorm:"default:0;" json:"status"` // 状态1正常 2异常
Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间
Tag *string `gorm:"default:'';" json:"tag"` //
TemplateTag *string `gorm:"default:'';" json:"template_tag"` //
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除
SwitchInfo *string `gorm:"default:'';" json:"switch_info"` //
GroupOptions *string `gorm:"default:'';" json:"group_options"` //
Version *int64 `gorm:"index;default:0;" json:"version"` // 默认1
}
type FsProductTemplateV2Model struct {

View File

@ -113,9 +113,9 @@ func (t *FsProductTemplateV2Model) GetProductTemplateListByParams(ctx context.Co
// 获取第一个尺寸下的模板
func (t *FsProductTemplateV2Model) FindOneByProductIdTagIdWithSizeTable(ctx context.Context, productId int64, templateTag string) (resp *FsProductTemplateV2, err error) {
err = t.db.WithContext(ctx).Table(t.name+" as t").
Joins("left join fs_product_size as s on t.product_id = s.product_id").
Joins("inner join fs_product_size as s on t.product_id = s.product_id").
Select("t.*").
Where("t.product_id = ? and t.tag = ? ", productId, templateTag).
Where("t.product_id = ? and t.template_tag = ? ", productId, templateTag).
Where("t.status = ? and t.is_del = ?", 1, 0).
Where("s.status = ?", 1).
Order("s.sort ASC").
@ -126,7 +126,7 @@ func (t *FsProductTemplateV2Model) FindAllByModelIdsTemplateTag(ctx context.Cont
if len(modelIds) == 0 {
return
}
db := t.db.WithContext(ctx).Model(&FsProductTemplateV2{}).Where("`model_id` in (?) and `tag` = ? and `is_del` = ? and `status` = ?", modelIds, templateTag, 0, 1)
db := t.db.WithContext(ctx).Model(&FsProductTemplateV2{}).Where("`model_id` in (?) and `template_tag` = ? and `is_del` = ? and `status` = ?", modelIds, templateTag, 0, 1)
if len(fields) != 0 {
db = db.Select(fields[0])
}
@ -143,7 +143,7 @@ func (t *FsProductTemplateV2Model) FindAllByModelIdsTemplateTag(ctx context.Cont
// 获取产品在指定模板标签下的所有模板
func (t *FsProductTemplateV2Model) GetListByProductAndTemplateTag(ctx context.Context, templateTagId string, productId int64, fields ...string) (resp []FsProductTemplateV2, err error) {
db := t.db.WithContext(ctx).Model(&FsProductTemplateV2{}).
Where("tag = ? and product_id = ? and status = ? and is_del = ?", templateTagId, productId, 1, 0)
Where("template_tag = ? and product_id = ? and status = ? and is_del = ?", templateTagId, productId, 1, 0)
if len(fields) > 0 {
db = db.Select(fields[0])
}

View File

@ -18,6 +18,7 @@ type FsResource struct {
MetaKey1 *string `gorm:"index;default:'';" json:"meta_key1"` // 需要关键信息查询的自定义属性1,可以动态增加
ApiType *int64 `gorm:"default:1;" json:"api_type"` // 调用类型1=对外2=对内
BucketName *string `gorm:"default:'';" json:"bucket_name"` // 存储桶名: 1=持久 2=缓存
Source *string `gorm:"default:'';" json:"source"` // 来源
}
type FsResourceModel struct {
db *gorm.DB

View File

@ -16,8 +16,8 @@ type FsTags struct {
Icon *string `gorm:"default:'';" json:"icon"` // 标签图标
Status *int64 `gorm:"default:1;" json:"status"` // 状态 1可用
Description *string `gorm:"default:'';" json:"description"` // 介绍 Seo
RecommendProduct *string `gorm:"default:'';" json:"recommend_product"` //
RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` //
RecommendProduct *string `gorm:"default:'';" json:"recommend_product"` // 推荐产品id例如: 1,3,4,5
RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` // 推荐排序例如:1324
Category *int64 `gorm:"default:1;" json:"category"` // 分类1前台用的 2后台用的
}
type FsTagsModel struct {

View File

@ -66,7 +66,7 @@ func (l *GetMapLibraryListLogic) GetMapLibraryList(req *types.Request, userinfo
if tagIndex, ok := mapTag[*v.TagId]; ok {
data.Tag = &types.MapLibraryListTag{
Id: templateTagList[tagIndex].Id,
Title: *templateTagList[tagIndex].Title,
Title: *templateTagList[tagIndex].TemplateTag,
}
}
//解析info

View File

@ -83,7 +83,7 @@ func (l *GetProductTemplateTagsLogic) GetProductTemplateTags(req *types.GetProdu
for _, v := range productTemplateTags {
list = append(list, types.GetProductTemplateTagsRsp{
Id: v.Id,
TemplateTag: *v.Title,
TemplateTag: *v.TemplateTag,
Cover: *v.Cover,
})
}

View File

@ -8,7 +8,6 @@ import (
"fusenapi/utils/basic"
"fusenapi/utils/format"
"gorm.io/gorm"
"strconv"
"strings"
"context"
@ -62,13 +61,7 @@ func (l *GetTemplatevDetailLogic) GetTemplatevDetail(req *types.GetTemplatevDeta
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product template info")
}
//获取模板标签
templateTagModel := gmodel.NewFsProductTemplateTagsModel(l.svcCtx.MysqlConn)
tagId, err := strconv.ParseInt(*templatev2Info.Tag, 10, 64)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "parse int tag id err")
}
templateTagInfo, err := templateTagModel.FindOne(l.ctx, tagId, "id,title")
templateTagInfo, err := l.svcCtx.AllModels.FsProductTemplateTags.FindOneByTagName(l.ctx, *templatev2Info.TemplateTag, "id,title")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "template tag info is not exists")
@ -125,7 +118,7 @@ func (l *GetTemplatevDetailLogic) GetTemplatevDetail(req *types.GetTemplatevDeta
}
templateInfoRsp["tag"] = map[string]interface{}{
"id": templateTagInfo.Id,
"title": *templateTagInfo.Title,
"title": *templateTagInfo.TemplateTag,
}
response := types.GetTemplatevDetailRsp{
ProductModelInfo: productModelInfoRsp,

View File

@ -109,8 +109,8 @@ func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, useri
tagIds := make([]int64, 0, len(productTemplateList))
for _, v := range productTemplateList {
mapTemplateModelId[*v.ModelId] = struct{}{}
if v.Tag != nil && *v.Tag != "" {
tagId, err := strconv.ParseInt(*v.Tag, 10, 64)
if v.TemplateTag != nil && *v.TemplateTag != "" {
tagId, err := strconv.ParseInt(*v.TemplateTag, 10, 64)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "tag is not a number")
@ -296,7 +296,7 @@ func (l *GetProductInfoLogic) GetProductInfo(req *types.GetProductInfoReq, useri
partListRsp = append(partListRsp, thisInfo)
}
tagName := ""
if tagData, ok := mapTag[*tmp.Tag]; ok {
if tagData, ok := mapTag[*tmp.TemplateTag]; ok {
tagName = *tagData.Title
}
//按照材质和尺寸来存放模板信息

View File

@ -127,7 +127,7 @@ func (l *GetRecommandProductListLogic) GetRecommandProductList(req *types.GetRec
mapTagProp := make(map[int64][]types.CoverDefaultItem)
for _, v := range productTagPropList {
mapTagProp[*v.ProductId] = append(mapTagProp[*v.ProductId], types.CoverDefaultItem{
Tag: v.Title,
Tag: v.TemplateTag,
Cover: *v.Cover,
})
}

View File

@ -138,7 +138,7 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
}
for _, v := range productTagPropList {
mapTagProp[*v.ProductId] = append(mapTagProp[*v.ProductId], types.CoverDefaultItem{
Tag: v.Title,
Tag: v.TemplateTag,
Cover: *v.Cover,
})
}
@ -312,6 +312,10 @@ func (l *GetTagProductListLogic) organizationLevelRelation(minLevel int, mapTagL
//最终值提取最高级别那一层出来
rspList := make([]types.TagItem, 0, len(mapTagLevel))
for prefix, _ := range mapTop {
//大类下没有任何产品则不显示
if len(mapTagLevel[prefix].TagProductList) == 0 {
continue
}
rspList = append(rspList, *mapTagLevel[prefix])
}
//排序

View File

@ -67,6 +67,15 @@ func (l *GetTemplateByPidLogic) GetTemplateByPid(req *types.GetTemplateByPidReq,
} else { //指定物料
sizeIds = append(sizeIds, req.ProductSizeId)
}
//获取templatetag信息
templateTagInfo, err := l.svcCtx.AllModels.FsProductTemplateTags.FindOne(l.ctx, req.ProductTemplateTagId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "template tag is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "failed to get template tag")
}
//根据尺寸id获取模型
modelList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllBySizeIdsTag(l.ctx, sizeIds, constants.TAG_MODEL)
if err != nil {
@ -83,7 +92,7 @@ func (l *GetTemplateByPidLogic) GetTemplateByPid(req *types.GetTemplateByPidReq,
mapModel[v.Id] = k
}
//查询模型ids下对应tag标签的模板
templateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByModelIdsTemplateTag(l.ctx, modelIds, fmt.Sprintf("%d", req.ProductTemplateTagId), "")
templateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByModelIdsTemplateTag(l.ctx, modelIds, *templateTagInfo.TemplateTag, "")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get template list")

View File

@ -156,7 +156,7 @@ func (l *HomePageRecommendProductListLogic) HomePageRecommendProductList(req *ty
mapTagProp := make(map[int64][]types.CoverDefaultItem)
for _, v := range productTagPropList {
mapTagProp[*v.ProductId] = append(mapTagProp[*v.ProductId], types.CoverDefaultItem{
Tag: v.Title,
Tag: v.TemplateTag,
Cover: *v.Cover,
})
}

View File

@ -1,179 +0,0 @@
package consumer
import (
"context"
"encoding/json"
"errors"
"fmt"
"fusenapi/constants"
"fusenapi/initalize"
"fusenapi/server/render/internal/svc"
"fusenapi/service/repositories"
"fusenapi/utils/websocket_data"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
"strconv"
)
// 这里请求的py接口返回数据
type pythonApiRsp struct {
Id string `json:"id"` //物料模板的id
LogoUrl string `json:"logo_url"` //logo地址
Result string `json:"result"` //图片base64
}
// 消费渲染需要组装的数据
type MqConsumerRenderAssemble struct {
}
func (m *MqConsumerRenderAssemble) Run(ctx context.Context, data []byte) error {
defer func() {
if err := recover(); err != nil {
logx.Error("MqConsumerRenderAssemble panic:", err)
}
}()
logx.Info("收到需要组装的消息:", string(data))
var parseInfo websocket_data.AssembleRenderData
if err := json.Unmarshal(data, &parseInfo); err != nil {
logx.Error("MqConsumerRenderAssemble数据格式错误:", err)
return nil //不返回错误就删除消息
}
val := ctx.Value("svcctx")
if val == nil {
logx.Error("svcctx is nil")
return nil //不返回错误就删除消息
}
svcCtx, ok := val.(*svc.ServiceContext)
if !ok {
logx.Error("svcctx is nil!!")
return nil //不返回错误就删除消息
}
rabbitmq := initalize.RabbitMqHandle{}
//根据templateTag获取templateTagId(后续模板表的tag改成template_tag后可能就不需要这个步骤了)
templateTag, err := svcCtx.AllModels.FsProductTemplateTags.FindOneByTagName(ctx, parseInfo.RenderData.TemplateTag)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("can`t find template tag info by template tag:", parseInfo.RenderData.TemplateTag)
return nil
}
logx.Error("failed to get template tag info")
return nil
}
//获取模板(模板标签下的对一个物料的的模板)
productTemplate, err := svcCtx.AllModels.FsProductTemplateV2.FindOneByProductIdTagIdWithSizeTable(ctx, parseInfo.RenderData.ProductId, fmt.Sprintf("%d", templateTag.Id))
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("template info is not found")
return nil //不返回错误就删除消息
}
logx.Error("failed to get template info:", err)
return nil //不返回错误就删除消息
}
//获取刀版图
res, err := svcCtx.Repositories.ImageHandle.LogoCombine(ctx, &repositories.LogoCombineReq{
UserId: parseInfo.RenderData.UserId,
GuestId: parseInfo.RenderData.GuestId,
TemplateId: productTemplate.Id,
TemplateTag: parseInfo.RenderData.TemplateTag,
Website: parseInfo.RenderData.Website,
Slogan: parseInfo.RenderData.Slogan,
Address: parseInfo.RenderData.Address,
Phone: parseInfo.RenderData.Phone,
})
if err != nil {
logx.Error("合成刀版图失败:", err)
return nil
}
combineImage := "" //刀版图
if res != nil && res.ResourceUrl != nil {
combineImage = *res.ResourceUrl
} else {
logx.Error("合成刀版图失败,合成的刀版图是空指针:", err)
return nil
}
logx.Info("合成刀版图成功:", *res.ResourceUrl)
//获取渲染设置信息
element, err := svcCtx.AllModels.FsProductTemplateElement.FindOneByModelId(ctx, *productTemplate.ModelId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("element info is not found,model_id = ?", *productTemplate.ModelId)
return nil //不返回错误就删除消息
}
logx.Error("failed to get element list,", err)
return nil //不返回错误就删除消息
}
//组装数据
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 nil //不返回错误就删除消息
}
}
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": parseInfo.RenderData.ProductId,
"tid": *element.Title,
"rotation": *element.Rotation,
"filePath": "", //todo 文件路径,针对千人千面
"data": tempData,
},
}
sendData := map[string]interface{}{
"id": parseInfo.TaskId,
"order_id": 0,
"user_id": parseInfo.RenderData.UserId,
"guest_id": parseInfo.RenderData.GuestId,
"sku_ids": []int64{parseInfo.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成功")
return nil
}

View File

@ -12,11 +12,6 @@ import (
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/api/render/render_notify",
Handler: RenderNotifyHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/render/get_face_slice",

View File

@ -5,19 +5,6 @@ import (
"fusenapi/utils/basic"
)
type RequestToUnity struct {
}
type RequestReadImages struct {
}
type RenderNotifyReq struct {
TaskId string `json:"task_id"` //任务id
UserId int64 `json:"user_id"`
GuestId int64 `json:"guest_id"`
Image string `json:"image"`
}
type Request struct {
}

View File

@ -1,11 +1,8 @@
package main
import (
"context"
"flag"
"fmt"
"fusenapi/constants"
"fusenapi/server/render/consumer"
"net/http"
"fusenapi/utils/auth"
@ -30,12 +27,6 @@ func main() {
defer server.Stop()
ctx := svc.NewServiceContext(c)
//消费渲染前组装数据队列
ctx1 := context.Background()
ctx2, cancel := context.WithCancel(ctx1)
ctx2 = context.WithValue(ctx2, "svcctx", ctx)
defer cancel()
go ctx.RabbitMq.Consume(ctx2, constants.RABBIT_MQ_ASSEMBLE_RENDER_DATA, &consumer.MqConsumerRenderAssemble{})
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()

View File

@ -65,7 +65,8 @@ func (l *LogoCombineLogic) LogoCombine(req *types.LogoCombineReq, userinfo *auth
Slogan: req.Slogan,
Phone: req.Phone,
Address: req.Address,
Qrcode: req.Qrcode,
Qrcode: req.Qrcode,
})
if err != nil {

View File

@ -4,9 +4,6 @@ import (
"testing"
)
// var configFile = flag.String("f", "etc/home-user-auth.yaml", "the config file")
func TestMain(t *testing.T) {
// log.Println(model.RawFieldNames[FsCanteenType]())
main()
}

View File

@ -83,8 +83,10 @@ func (l *UploadCallbackLogic) UploadCallback(req *types.UploadCallbackReq, useri
fsResource.ResourceUrl = &req.ResourceUrl
fsResource.Metadata = &req.Metadata
fsResource.ApiType = &req.ApiType
fsResource.Source = &req.Source
fsResource.BucketName = bucketName
fsResource.Version = &version
if resourceInfo.ResourceId == "" {
_, err = resourceModelTS.BuilderCreate(ctx, transBuilder, fsResource)
} else {

View File

@ -90,6 +90,7 @@ func (l *UploadFileBackendLogic) UploadFileBackend(req *types.UploadFileBackendR
ApiType: req.ApiType,
UserId: userId,
GuestId: guestId,
Source: req.Source,
})
if err != nil {

View File

@ -77,6 +77,7 @@ func (l *UploadFileBaseLogic) UploadFileBase(req *types.UploadFileBaseReq, useri
ApiType: req.ApiType,
UserId: userId,
GuestId: guestId,
Source: req.Source,
})
if err != nil {

View File

@ -123,6 +123,7 @@ func (l *UploadFilesBackendLogic) UploadFilesBackend(req *types.UploadFilesReq,
ApiType: req.ApiType,
Bucket: bucketName,
HashKey: hashKey,
Source: req.Source,
}
}
}, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) {
@ -148,6 +149,7 @@ func (l *UploadFilesBackendLogic) UploadFilesBackend(req *types.UploadFilesReq,
ApiType: req.ApiType,
UserId: userId,
GuestId: guestId,
Source: uploadDataInfo.Source,
})
if err == nil {
uploadUrl.Status = 1
@ -201,6 +203,7 @@ type UploadData struct {
Bucket *string `json:"bucket"`
HashKey string `json:"hash_key"`
FileData []byte `fsfile:"data"`
Source string `json:"source"`
}
type UploadUrl struct {

View File

@ -88,6 +88,7 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us
imageTypes["image/tiff"] = struct{}{}
imageTypes["image/webp"] = struct{}{}
imageTypes["image/svg+xml"] = struct{}{}
// 判断文件类型是否为图片
_, ok := imageTypes[fileType]
if !ok {
@ -115,6 +116,7 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us
ApiType: 2,
UserId: userId,
GuestId: guestId,
Source: "upload-logo",
})
if err != nil {

View File

@ -13,6 +13,7 @@ type UploadFileBaseReq struct {
UserId int64 `form:"user_id,optional"` // 上传文件额外信息
GuestId int64 `form:"guest_id,optional"` // 上传文件额外信息
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
Source string `form:"source"` // 上传来源
}
type UploadLogoReq struct {
@ -28,12 +29,14 @@ type UploadFileBackendReq struct {
FileKey string `form:"file_key"` // 上传唯一标识信息
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息
Metadata string `form:"meta_data,optional"` // 上传文件额外信息
Source string `form:"source"` // 上传来源
}
type UploadFilesReq struct {
ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型1=对外2=对内
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
UploadInfo string `form:"upload_info"` // 上传信息 json
Source string `form:"source"` // 上传来源
}
type UploadCallbackReq struct {
@ -43,6 +46,7 @@ type UploadCallbackReq struct {
ResourceUrl string `form:"resource_url"` // 资源URL
Metadata string `form:"metadata,optional"` // 元数据,json格式,存储图像分率
ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型1=对外2=对内
Source string `form:"source"` // 上传来源
}
type RequestUpFile struct {

View File

@ -8,4 +8,17 @@ Auth:
AccessSecret: fusen2023
AccessExpire: 2592000
RefreshAfter: 1592000
SourceRabbitMq: amqp://rabbit001:rabbit001129@110.41.19.98:5672
SourceRabbitMq: amqp://rabbit001:rabbit001129@110.41.19.98:5672
AWS:
S3:
Credentials:
AccessKeyID: AKIAZB2JKUXDPNRP4YT2
Secret: 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
Token:
BLMService:
Url: "http://18.119.109.254:8999"
LogoCombine:
#Url: "http://192.168.1.7:8999/LogoCombine"
Url: "http://18.119.109.254:8999/LogoCombine"
Unity:
Host: http://api.fusen.3718.cn:4050

View File

@ -12,4 +12,22 @@ type Config struct {
Auth types.Auth
ReplicaId uint64
SourceRabbitMq string
AWS struct {
S3 struct {
Credentials struct {
AccessKeyID string
Secret string
Token string
}
}
}
BLMService struct {
Url string
LogoCombine struct {
Url string
}
}
Unity struct {
Host string
}
}

View File

@ -10,6 +10,6 @@ func DataTransferHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 创建一个业务逻辑层实例
l := logic.NewDataTransferLogic(r.Context(), svcCtx)
l.DataTransfer(svcCtx, w, r)
l.DataTransfer(w, r)
}
}

View File

@ -6,9 +6,9 @@ import (
"fusenapi/utils/basic"
"fusenapi/server/render/internal/logic"
"fusenapi/server/render/internal/svc"
"fusenapi/server/render/internal/types"
"fusenapi/server/websocket/internal/logic"
"fusenapi/server/websocket/internal/svc"
"fusenapi/server/websocket/internal/types"
)
func RenderNotifyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {

View File

@ -17,6 +17,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/websocket/data_transfer",
Handler: DataTransferHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/websocket/render_notify",
Handler: RenderNotifyHandler(serverCtx),
},
},
)
}

View File

@ -5,8 +5,6 @@ import (
"encoding/json"
"fmt"
"fusenapi/constants"
"fusenapi/initalize"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/id_generator"
"fusenapi/utils/websocket_data"
@ -70,22 +68,20 @@ var (
// 每个连接的连接基本属性
type wsConnectItem struct {
conn *websocket.Conn //websocket的连接
ctx context.Context
rabbitMq *initalize.RabbitMqHandle
allModels *gmodel.AllModelsGen
closeChan chan struct{} //ws连接关闭chan
isClose bool //是否已经关闭
uniqueId string //ws连接唯一标识
inChan chan []byte //接受消息缓冲通道
outChan chan []byte //发送回客户端的消息
mutex sync.Mutex //互斥锁
userId int64 //用户id
guestId int64 //游客id
renderProperty renderProperty //扩展云渲染属性
conn *websocket.Conn //websocket的连接
logic *DataTransferLogic //logic
closeChan chan struct{} //ws连接关闭chan
isClose bool //是否已经关闭
uniqueId string //ws连接唯一标识
inChan chan []byte //接受消息缓冲通道
outChan chan []byte //发送回客户端的消息
mutex sync.Mutex //互斥锁
userId int64 //用户id
guestId int64 //游客id
renderProperty renderProperty //扩展云渲染属性
}
func (l *DataTransferLogic) DataTransfer(svcCtx *svc.ServiceContext, w http.ResponseWriter, r *http.Request) {
func (l *DataTransferLogic) DataTransfer(w http.ResponseWriter, r *http.Request) {
//升级websocket
conn, err := upgrade.Upgrade(w, r, nil)
if err != nil {
@ -98,7 +94,7 @@ func (l *DataTransferLogic) DataTransfer(svcCtx *svc.ServiceContext, w http.Resp
userInfo *auth.UserInfo
isAuth bool
)
isAuth, userInfo = l.checkAuth(svcCtx, r)
isAuth, userInfo = l.checkAuth(r)
if !isAuth {
time.Sleep(time.Second * 1) //兼容下火狐
rsp := websocket_data.DataTransferData{
@ -126,6 +122,8 @@ func (l *DataTransferLogic) DataTransfer(svcCtx *svc.ServiceContext, w http.Resp
go ws.sendLoop()
//操作连接中渲染任务的增加/删除
go ws.operationRenderTask()
//消费渲染缓冲队列
go ws.renderImage()
//心跳
ws.heartbeat()
}
@ -138,18 +136,17 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo auth.User
uniqueId := l.getUniqueId(userInfo)
ws := wsConnectItem{
conn: conn,
ctx: l.ctx,
rabbitMq: l.svcCtx.RabbitMq,
allModels: l.svcCtx.AllModels,
logic: l,
uniqueId: uniqueId,
closeChan: make(chan struct{}, 1),
inChan: make(chan []byte, 1000),
outChan: make(chan []byte, 1000),
inChan: make(chan []byte, 100),
outChan: make(chan []byte, 100),
userId: userInfo.UserId,
guestId: userInfo.GuestId,
renderProperty: renderProperty{
renderImageTask: make(map[string]string),
renderImageTaskCtlChan: make(chan renderImageControlChanItem, 100),
renderChan: make(chan []byte, 100),
},
}
//保存连接
@ -178,9 +175,9 @@ func getUserPart(userId, guestId int64) string {
}
// 鉴权
func (l *DataTransferLogic) checkAuth(svcCtx *svc.ServiceContext, r *http.Request) (isAuth bool, userInfo *auth.UserInfo) {
func (l *DataTransferLogic) checkAuth(r *http.Request) (isAuth bool, userInfo *auth.UserInfo) {
// 解析JWT token,并对空用户进行判断
claims, err := svcCtx.ParseJwtToken(r)
claims, err := l.svcCtx.ParseJwtToken(r)
// 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息
if err != nil {
return false, nil
@ -321,7 +318,7 @@ func (w *wsConnectItem) dealwithReciveData(data []byte) {
switch parseInfo.T {
//图片渲染
case constants.WEBSOCKET_RENDER_IMAGE:
w.renderImage(d)
w.sendToRenderChan(d)
//刷新重连请求恢复上次连接的标识
case constants.WEBSOCKET_REQUEST_REUSE_LAST_CONNECT:
w.reuseLastConnect(d)

View File

@ -1,59 +0,0 @@
package logic
import (
"context"
"encoding/json"
"fusenapi/constants"
"fusenapi/utils/websocket_data"
"github.com/zeromicro/go-zero/core/logx"
)
// 消费渲染结果数据
type MqConsumerRenderResult struct {
}
func (m *MqConsumerRenderResult) Run(ctx context.Context, data []byte) error {
defer func() {
if err := recover(); err != nil {
logx.Error("MqConsumerRenderResult panic:", err)
}
}()
logx.Info("接收到MqConsumerRenderResult数据:", string(data))
var parseInfo websocket_data.RenderImageNotify
if err := json.Unmarshal(data, &parseInfo); err != nil {
logx.Error("MqConsumerRenderResult data format err:", err)
return nil //不返回错误则就删掉该消息
}
//遍历websocket链接把数据传进去
mapConnPool.Range(func(key, value any) bool {
//断言连接
ws, ok := value.(wsConnectItem)
if !ok {
return true
}
//关闭标识
if ws.isClose {
return true
}
//查询有无该渲染任务
renderId, ok := ws.renderProperty.renderImageTask[parseInfo.TaskId]
if !ok {
return true
}
b := ws.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
RenderId: renderId,
Image: parseInfo.Image,
})
//删除对应的需要渲染的图片map
ws.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{
Option: 0, //0删除 1添加
TaskId: parseInfo.TaskId,
RenderId: renderId,
}
//发送数据到out chan
ws.sendToOutChan(b)
return true
})
return nil
}

View File

@ -1,16 +1,17 @@
package logic
import (
"context"
"encoding/json"
"fusenapi/constants"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/file"
"fusenapi/utils/websocket_data"
"time"
"fusenapi/server/render/internal/svc"
"fusenapi/server/render/internal/types"
"context"
"fusenapi/server/websocket/internal/svc"
"fusenapi/server/websocket/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
@ -55,26 +56,56 @@ func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq, userinfo *a
AwsSession: l.svcCtx.AwsSession,
}
uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{
Source: "unity cloud render",
FileHash: req.TaskId,
FileData: req.Image,
Metadata: "",
UploadBucket: 1,
ApiType: 2,
UserId: req.UserId,
GuestId: req.GuestId,
FileByte: nil,
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeFileUploadErr, "failed to upload render resource image")
}
//发送消息到对应的rabbitmq
data := websocket_data.RenderImageNotify{
TaskId: req.TaskId,
Image: uploadRes.ResourceUrl,
}
d, _ := json.Marshal(data)
if err = l.svcCtx.RabbitMq.SendMsg(constants.RABBIT_MQ_RENDER_RESULT_DATA, d); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to send data")
}
//遍历websocket链接把数据传进去
mapConnPool.Range(func(key, value any) bool {
//断言连接
ws, ok := value.(wsConnectItem)
if !ok {
return true
}
//关闭标识
if ws.isClose {
return true
}
//查询有无该渲染任务
renderId, ok := ws.renderProperty.renderImageTask[req.TaskId]
if !ok {
return true
}
b := ws.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
RenderId: renderId,
Image: uploadRes.ResourceUrl,
})
deleteTask := renderImageControlChanItem{
Option: 0, //0删除 1添加
TaskId: req.TaskId,
RenderId: renderId,
}
select {
case <-ws.closeChan: //关闭了
return true
case ws.renderProperty.renderImageTaskCtlChan <- deleteTask: //删除对应的需要渲染的图片map
//发送数据到out chan
ws.sendToOutChan(b)
case <-time.After(time.Second * 3): //超时丢弃
return true
}
return true
})
logx.Info("渲染回调成功######################")
return resp.SetStatusWithMessage(basic.CodeOK, "success")
}

View File

@ -1,20 +1,26 @@
package logic
import (
"bytes"
"encoding/json"
"errors"
"fusenapi/constants"
"fusenapi/service/repositories"
"fusenapi/utils/curl"
"fusenapi/utils/hash"
"fusenapi/utils/websocket_data"
"github.com/zeromicro/go-zero/core/logx"
"gorm.io/gorm"
"strconv"
"time"
)
// 云渲染属性
type renderProperty struct {
renderImageTask map[string]string //需要渲染的图片任务 key是taskId val 是renderId
renderImageTaskCtlChan chan renderImageControlChanItem //渲染任务新增移除的控制通道
renderChan chan []byte //渲染的缓冲队列
}
// 渲染任务新增移除的控制通道的数据
@ -24,8 +30,39 @@ type renderImageControlChanItem struct {
RenderId string // map的val
}
// 发送到渲染缓冲池
func (w *wsConnectItem) sendToRenderChan(data []byte) {
select {
case <-w.closeChan: //已经关闭
return
case w.renderProperty.renderChan <- data:
return
case <-time.After(time.Second * 3):
return
}
}
// 渲染发送到组装数据组装数据
func (w *wsConnectItem) renderImage(data []byte) {
func (w *wsConnectItem) renderImage() {
defer func() {
if err := recover(); err != nil {
logx.Error("renderImage panic:", err)
}
}()
for {
select {
case <-w.closeChan: //已关闭
return
case data := <-w.renderProperty.renderChan:
w.consumeRenderCache(data)
}
}
}
// 消费渲染缓冲数据
func (w *wsConnectItem) consumeRenderCache(data []byte) {
logx.Info("消费渲染数据:", string(data))
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)))
@ -49,7 +86,7 @@ func (w *wsConnectItem) renderImage(data []byte) {
return
}
//获取上传最近的logo
userMaterial, err := w.allModels.FsUserMaterial.FindLatestOne(w.ctx, w.userId, w.guestId)
userMaterial, err := w.logic.svcCtx.AllModels.FsUserMaterial.FindLatestOne(w.logic.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"))
@ -57,7 +94,7 @@ func (w *wsConnectItem) renderImage(data []byte) {
return
}
//使用默认logo(id=0)
userMaterialDefault, err := w.allModels.FsUserMaterial.FindOneById(w.ctx, 0)
userMaterialDefault, err := w.logic.svcCtx.AllModels.FsUserMaterial.FindOneById(w.logic.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"))
@ -75,10 +112,13 @@ func (w *wsConnectItem) renderImage(data []byte) {
renderImageData.RenderData.UserId = w.userId
renderImageData.RenderData.GuestId = w.guestId
//生成任务id
taskId := hash.JsonHashKey(renderImageData.RenderData)
//生成任务id(需要把user_id,guest_id设为0)
hashVal := renderImageData.RenderData
hashVal.UserId = 0
hashVal.GuestId = 0
taskId := hash.JsonHashKey(hashVal)
//查询有没有缓存的资源,有就返回######################
resource, err := w.allModels.FsResource.FindOneById(w.ctx, taskId)
resource, err := w.logic.svcCtx.AllModels.FsResource.FindOneById(w.logic.ctx, taskId)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("failed to find render resource:", err)
@ -101,18 +141,156 @@ func (w *wsConnectItem) renderImage(data []byte) {
TaskId: taskId,
RenderId: renderImageData.RenderId,
}
tmpData := websocket_data.AssembleRenderData{
TaskId: taskId,
RenderId: renderImageData.RenderId,
RenderData: renderImageData.RenderData,
}
d, _ := json.Marshal(tmpData)
//发送给对应的流水线组装数据
if err = w.rabbitMq.SendMsg(constants.RABBIT_MQ_ASSEMBLE_RENDER_DATA, d); err != nil {
logx.Error("发送渲染任务数据到MQ失败:", string(d), "err:", err)
//组装数据
if err = w.assembleRenderData(taskId, renderImageData); err != nil {
logx.Error("组装数据失败:", err)
return
}
logx.Info("发送渲染数据到rabbitmq成功:", string(d))
}
// 组装数据发送给unity
func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.RenderImageReqMsg) error {
defer func() {
if err := recover(); err != nil {
logx.Error("assembleRenderData panic:", err)
}
}()
//获取模板
productTemplate, err := w.logic.svcCtx.AllModels.FsProductTemplateV2.FindOneByProductIdTagIdWithSizeTable(w.logic.ctx, info.RenderData.ProductId, info.RenderData.TemplateTag)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
logx.Error("template info is not found")
return err
}
logx.Error("failed to get template info:", err)
return err
}
//获取刀版图
res, err := w.logic.svcCtx.Repositories.ImageHandle.LogoCombine(w.logic.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 err
}
combineImage := "" //刀版图
if res != nil && res.ResourceUrl != nil {
combineImage = *res.ResourceUrl
} else {
logx.Error("合成刀版图失败,合成的刀版图是空指针:", err)
return err
}
logx.Info("合成刀版图成功:", *res.ResourceUrl)
//获取渲染设置信息
element, err := w.logic.svcCtx.AllModels.FsProductTemplateElement.FindOneByModelId(w.logic.ctx, *productTemplate.ModelId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
// todo 没有图就给他返回一张默认(后面要删除)
defaultImg := w.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
RenderId: info.RenderId,
Image: "https://s3.us-west-1.amazonaws.com/storage.fusenpack.com/695463af6e9b93c003db39ddf728241f9523efc55b20dc37f30fe5d96ed54fb5",
})
w.sendToOutChan(defaultImg)
logx.Error("element info is not found,model_id = ", *productTemplate.ModelId)
return err
}
logx.Error("failed to get element list,", err)
return err
}
//组装数据
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 err
}
}
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 千人千面需要使用
}
//请求unity接口
url := "http://api.fusen.3718.cn:4050/api/render/queue/push"
header := make(map[string]string)
header["content-type"] = "application/json"
t := time.Now().UTC()
postData := map[string]interface{}{
"group": "unity3d",
"source": "home page",
"priority": 1,
"create_at": t,
"render_data": sendData,
}
p, _ := json.Marshal(postData)
_, err = curl.ApiCall(url, "POST", header, bytes.NewReader(p), time.Second*10)
if err != nil {
logx.Error("failed to send data to unity")
return err
}
logx.Info("发送到unity成功################")
return nil
}
// 操作连接中渲染任务的增加/删除

View File

@ -7,6 +7,10 @@ import (
"fusenapi/shared"
"net/http"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"fusenapi/initalize"
"fusenapi/model/gmodel"
@ -18,21 +22,29 @@ type ServiceContext struct {
Config config.Config
SharedState *shared.SharedState
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
RabbitMq *initalize.RabbitMqHandle
MysqlConn *gorm.DB
AllModels *gmodel.AllModelsGen
RabbitMq *initalize.RabbitMqHandle
AwsSession *session.Session
Repositories *initalize.Repositories
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := initalize.InitMysql(c.SourceMysql)
// StateServer := shared.StartNode(c.ReplicaId, autoconfig.AutoGetAllServerConfig(), conn)
config := aws.Config{
Credentials: credentials.NewStaticCredentials(c.AWS.S3.Credentials.AccessKeyID, c.AWS.S3.Credentials.Secret, c.AWS.S3.Credentials.Token),
}
return &ServiceContext{
Config: c,
SharedState: nil,
MysqlConn: conn,
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
Config: c,
MysqlConn: conn,
AllModels: gmodel.NewAllModels(conn),
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
AwsSession: session.Must(session.NewSession(&config)),
Repositories: initalize.NewAllRepositories(&initalize.NewAllRepositorieData{
GormDB: conn,
BLMServiceUrl: &c.BLMService.Url,
AwsSession: session.Must(session.NewSession(&config)),
}),
}
}

View File

@ -5,21 +5,11 @@ import (
"fusenapi/utils/basic"
)
type RequestToUnity struct {
}
type RequestReadImages struct {
}
type RenderNotifyReq struct {
Sign string `json:"sign"`
Time int64 `json:"time"`
Info NotifyInfo `json:"info"`
}
type NotifyInfo struct {
TaskId string `json:"task_id"` //任务id
Image string `json:"image"`
TaskId string `json:"task_id"` //任务id
UserId int64 `json:"user_id"`
GuestId int64 `json:"guest_id"`
Image string `json:"image"`
}
type Request struct {

View File

@ -1,11 +1,8 @@
package main
import (
"context"
"flag"
"fmt"
"fusenapi/constants"
"fusenapi/server/websocket/internal/logic"
"net/http"
"fusenapi/utils/auth"
@ -30,12 +27,6 @@ func main() {
defer server.Stop()
ctx := svc.NewServiceContext(c)
//消费渲染结果队列
ctx1 := context.Background()
ctx2, cancel := context.WithCancel(ctx1)
ctx2 = context.WithValue(ctx2, "allmodels", ctx.AllModels)
defer cancel()
go ctx.RabbitMq.Consume(ctx2, constants.RABBIT_MQ_RENDER_RESULT_DATA, &logic.MqConsumerRenderResult{})
handler.RegisterHandlers(server, ctx)
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
server.Start()

View File

@ -8,26 +8,8 @@ info (
)
import "basic.api"
type RequestToUnity {
}
type RequestReadImages {
}
service render {
//云渲染完了通知接口
@handler RenderNotifyHandler
post /api/render/render_notify(RenderNotifyReq) returns (response);
//获取面片信息
@handler GetFaceSliceHandler
post /api/render/get_face_slice(request) returns (response);
}
//渲染完了通知接口
type RenderNotifyReq {
TaskId string `json:"task_id"` //任务id
UserId int64 `json:"user_id"`
GuestId int64 `json:"guest_id"`
Image string `json:"image"`
}

View File

@ -53,6 +53,7 @@ type (
UserId int64 `form:"user_id,optional"` // 上传文件额外信息
GuestId int64 `form:"guest_id,optional"` // 上传文件额外信息
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
Source string `form:"source"` // 上传来源
}
)
@ -72,12 +73,14 @@ type (
FileKey string `form:"file_key"` // 上传唯一标识信息
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息
Metadata string `form:"meta_data,optional"` // 上传文件额外信息
Source string `form:"source"` // 上传来源
}
UploadFilesReq {
ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型1=对外2=对内
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
UploadInfo string `form:"upload_info"` // 上传信息 json
Source string `form:"source"` // 上传来源
}
UploadCallbackReq {
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
@ -86,6 +89,7 @@ type (
ResourceUrl string `form:"resource_url"` // 资源URL
Metadata string `form:"metadata,optional"` // 元数据,json格式,存储图像分率
ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型1=对外2=对内
Source string `form:"source"` // 上传来源
}
)

View File

@ -12,4 +12,15 @@ service websocket {
//websocket数据交互
@handler DataTransferHandler
get /api/websocket/data_transfer(request) returns (response);
//云渲染完了通知接口
@handler RenderNotifyHandler
post /api/websocket/render_notify(RenderNotifyReq) returns (response);
}
//渲染完了通知接口
type RenderNotifyReq {
TaskId string `json:"task_id"` //任务id
UserId int64 `json:"user_id"`
GuestId int64 `json:"guest_id"`
Image string `json:"image"`
}

View File

@ -46,7 +46,7 @@ type (
UserId int64 `json:"user_id"`
GuestId int64 `json:"guest_id"`
TemplateId int64 `json:"template_id"`
TemplateTag string `json:"resource_key"`
TemplateTag string `json:"template_tag"`
Website string `json:"website"` // 合图参数
Slogan string `json:"slogan"` // 合图参数
Address string `json:"address"` // 合图参数
@ -62,7 +62,10 @@ type (
func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq) (*LogoCombineRes, error) {
// 根据hash 查询数据资源
var resourceId string = hash.JsonHashKey(in)
var hashKeyData = *in
hashKeyData.GuestId = 0
hashKeyData.UserId = 0
var resourceId string = hash.JsonHashKey(hashKeyData)
resourceModel := gmodel.NewFsResourceModel(l.MysqlConn)
resourceInfo, err := resourceModel.FindOneById(ctx, resourceId)
@ -89,15 +92,6 @@ func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq
return nil, err
}
var groupOptions map[string]interface{}
if productTemplateV2Info.GroupOptions != nil {
err = json.Unmarshal([]byte(*productTemplateV2Info.GroupOptions), &groupOptions)
if err != nil {
logx.Error(err)
return nil, err
}
}
var materialList []interface{}
if productTemplateV2Info.TemplateInfo != nil {
var templateInfo map[string]interface{}
@ -108,6 +102,7 @@ func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq
return nil, err
}
materialList = templateInfo["materialList"].([]interface{})
groupOptions = templateInfo["groupOptions"].(map[string]interface{})
}
var moduleDataMap = make(map[string]interface{}, 4)
@ -211,6 +206,7 @@ func (l *defaultImageHandle) LogoCombine(ctx context.Context, in *LogoCombineReq
AwsSession: l.AwsSession,
}
uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{
Source: "combine-image",
FileHash: resourceId,
FileData: fileBase.(string),
UploadBucket: 1,

View File

@ -22,6 +22,7 @@ type Upload struct {
}
type UploadBaseReq struct {
Source string
FileHash string
FileData string
Metadata string
@ -119,6 +120,7 @@ func (upload *Upload) UploadFileByBase64(req *UploadBaseReq) (*UploadBaseRes, er
Metadata: &req.Metadata,
ApiType: &apiType,
BucketName: bucketName,
Source: &req.Source,
}).Error
if err != nil {
logx.Errorf("err:%+vdesc:%+v", err, "fail.upload.resourceInfoAdd.mysql")
@ -212,6 +214,7 @@ func (upload *Upload) UploadFileByByte(req *UploadBaseReq) (*UploadBaseRes, erro
Metadata: &req.Metadata,
ApiType: &apiType,
BucketName: bucketName,
Source: &req.Source,
}).Error
if err != nil {
logx.Errorf("err:%+vdesc:%+v", err, "fail.upload.resourceInfoAdd.mysql")

View File

@ -28,20 +28,7 @@ type RenderImageRspMsg struct {
RenderId string `json:"render_id"` //渲染id
Image string `json:"image"` //渲染结果图片
}
// 渲染服务器回调数据
type RenderImageNotify struct {
TaskId string `json:"task_id"`
Image string `json:"image"`
}
type ThirdPartyLoginRspMsg struct {
//websocket三方登录的通知数据
Token string `json:"token"`
}
// 发送到渲染组装的mq数据
type AssembleRenderData struct {
TaskId string `json:"task_id"`
RenderId string `json:"render_id"`
RenderData RenderData `json:"render_data"`
}