Merge branch 'develop' into feature/auth
This commit is contained in:
@@ -73,7 +73,7 @@ func (l *GetFittingByPidLogic) GetFittingByPid(req *types.GetFittingByPidReq, us
|
||||
partIds = append(partIds, *v.PartId)
|
||||
}
|
||||
//获取配件数据
|
||||
fittingList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIds(l.ctx, partIds, "is_popular DESC,price ASC")
|
||||
fittingList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIds(l.ctx, partIds, "is_hot DESC,price ASC")
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get part list")
|
||||
@@ -110,7 +110,7 @@ func (l *GetFittingByPidLogic) GetFittingByPid(req *types.GetFittingByPidReq, us
|
||||
Title: *fitting.Title,
|
||||
Price: *fitting.Price,
|
||||
ModelInfo: modelInfo,
|
||||
IsPopular: *fitting.IsPopular > 0,
|
||||
IsPopular: *fitting.IsHot > 0,
|
||||
})
|
||||
}
|
||||
return resp.SetStatusWithMessage(basic.CodeOK, "success", listRsp)
|
||||
|
||||
@@ -99,7 +99,7 @@ func (l *GetProductListLogic) GetProductList(req *types.GetProductListReq, useri
|
||||
}
|
||||
//获取模板
|
||||
productTemplateModel := gmodel.NewFsProductTemplateV2Model(l.svcCtx.MysqlConn)
|
||||
productTemplatesV2, err := productTemplateModel.FindAllByProductIds(l.ctx, productIds)
|
||||
productTemplatesV2, err := productTemplateModel.FindAllByProductIds(l.ctx, productIds, "")
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeServiceErr, "get product template_v2 err")
|
||||
|
||||
@@ -48,7 +48,7 @@ func (l *GetSizeByPidLogic) GetSizeByPid(req *types.GetSizeByPidReq, userinfo *a
|
||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product info")
|
||||
}
|
||||
//获取产品尺寸列表(需要正序排序)
|
||||
sizeList, err := l.svcCtx.AllModels.FsProductSize.GetAllByProductIds(l.ctx, []int64{productInfo.Id}, "is_popular DESC,sort ASC")
|
||||
sizeList, err := l.svcCtx.AllModels.FsProductSize.GetAllByProductIds(l.ctx, []int64{productInfo.Id}, "is_hot DESC,sort ASC")
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get size list")
|
||||
@@ -118,7 +118,7 @@ func (l *GetSizeByPidLogic) GetSizeByPid(req *types.GetSizeByPidReq, userinfo *a
|
||||
Cover: *sizeInfo.Cover,
|
||||
PartsCanDeleted: *sizeInfo.PartsCanDeleted > 0,
|
||||
ModelId: modelList[modelIndex].Id,
|
||||
IsPopular: *sizeInfo.IsPopular > 0,
|
||||
IsPopular: *sizeInfo.IsHot > 0,
|
||||
MinPrice: float64(minPrice) / 100,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get tag info")
|
||||
}
|
||||
//前台用的分类是1
|
||||
if *tagData.Category != 1 {
|
||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "invalid tag")
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
|
||||
productTemplatesV2 []gmodel.FsProductTemplateV2 //产品模板列表(select 字段需要看查询的地方)
|
||||
productSizeCountList []gmodel.CountProductSizeByStatusRsp //产品尺寸数量列表(select 字段需要看查询的地方)
|
||||
mapProductSizeCount = make(map[int64]int64) //产品尺寸数量map
|
||||
mapProductTemplate = make(map[int64]struct{}) //产品模板map
|
||||
mapProductTemplate = make(map[int64]int64) //产品模板map
|
||||
)
|
||||
//携带产品
|
||||
if req.WithProduct {
|
||||
@@ -169,14 +170,22 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
|
||||
mapProductMinPrice[v.ProductId] = int64(priceSlice[0])
|
||||
}
|
||||
}
|
||||
//获取模板(只是获取产品product_id)
|
||||
productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIds(l.ctx, productIds, "product_id")
|
||||
//获取模板(只是获取产品product_id,id)
|
||||
if req.TemplateTag != "" { //指定模板tag
|
||||
productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIdsTemplateTag(l.ctx, productIds, req.TemplateTag, "sort ASC", "product_id,id")
|
||||
} else { //没指定模板tag
|
||||
productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIds(l.ctx, productIds, "sort ASC", "product_id,id")
|
||||
}
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeServiceErr, "get product template_v2 err")
|
||||
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product templates")
|
||||
}
|
||||
//只存第一个
|
||||
for _, v := range productTemplatesV2 {
|
||||
mapProductTemplate[*v.ProductId] = struct{}{}
|
||||
if _, ok := mapProductTemplate[*v.ProductId]; ok {
|
||||
continue
|
||||
}
|
||||
mapProductTemplate[*v.ProductId] = v.Id
|
||||
}
|
||||
//获取产品尺寸数量
|
||||
productSizeCountList, err = l.svcCtx.AllModels.FsProductSize.GetGroupProductSizeByStatus(l.ctx, productIds, 1)
|
||||
@@ -209,9 +218,11 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
|
||||
logx.Error(err)
|
||||
return resp.SetStatusAddMessage(basic.CodeServiceErr, "failed to deal with tag data")
|
||||
}
|
||||
//组装等级从属关系
|
||||
rspTagList, TotalCategoryProduct := l.organizationLevelRelation(minLevel, mapTagLevel)
|
||||
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetTagProductListRsp{
|
||||
TotalCategoryProduct: len(productList),
|
||||
TagList: l.organizationLevelRelation(minLevel, mapTagLevel), //组装等级从属关系
|
||||
TotalCategoryProduct: TotalCategoryProduct,
|
||||
TagList: rspTagList,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -223,7 +234,7 @@ type dealWithTagMenuDataReq struct {
|
||||
MapTagProp map[int64][]types.CoverDefaultItem
|
||||
ProductTagPropList []gmodel.FsProductTagProp
|
||||
MapProductMinPrice map[int64]int64
|
||||
MapProductTemplate map[int64]struct{}
|
||||
MapProductTemplate map[int64]int64
|
||||
MapProductSizeCount map[int64]int64
|
||||
MapTagLevel map[string]*types.TagItem
|
||||
MapProductHaveOptionFitting map[int64]struct{}
|
||||
@@ -274,7 +285,7 @@ func (l *GetTagProductListLogic) dealWithTagMenuData(req dealWithTagMenuDataReq)
|
||||
}
|
||||
|
||||
// 组织等级从属关系
|
||||
func (l *GetTagProductListLogic) organizationLevelRelation(minLevel int, mapTagLevel map[string]*types.TagItem) []types.TagItem {
|
||||
func (l *GetTagProductListLogic) organizationLevelRelation(minLevel int, mapTagLevel map[string]*types.TagItem) (rspTagList []types.TagItem, productCount int) {
|
||||
mapTop := make(map[string]struct{})
|
||||
//设置归属关系
|
||||
for prefix, tagItem := range mapTagLevel {
|
||||
@@ -316,22 +327,23 @@ func (l *GetTagProductListLogic) organizationLevelRelation(minLevel int, mapTagL
|
||||
if len(mapTagLevel[prefix].TagProductList) == 0 {
|
||||
continue
|
||||
}
|
||||
productCount += len(mapTagLevel[prefix].TagProductList)
|
||||
rspList = append(rspList, *mapTagLevel[prefix])
|
||||
}
|
||||
//排序
|
||||
sort.SliceStable(rspList, func(i, j int) bool {
|
||||
return rspList[i].Sort < rspList[j].Sort
|
||||
})
|
||||
return rspList
|
||||
return rspList, productCount
|
||||
}
|
||||
|
||||
// 获取对应tag的产品列表
|
||||
// 获取某个tag的直属产品
|
||||
type getTagProductsReq struct {
|
||||
TagId int64
|
||||
ProductList []gmodel.FsProduct
|
||||
MapTagProp map[int64][]types.CoverDefaultItem
|
||||
MapProductMinPrice map[int64]int64
|
||||
MapProductTemplate map[int64]struct{}
|
||||
MapProductTemplate map[int64]int64
|
||||
MapProductSizeCount map[int64]int64
|
||||
MapProductHaveOptionFitting map[int64]struct{}
|
||||
Size uint32
|
||||
@@ -347,7 +359,7 @@ func (l *GetTagProductListLogic) getTagProducts(req getTagProductsReq) (productL
|
||||
continue
|
||||
}
|
||||
minPrice, ok := req.MapProductMinPrice[productInfo.Id]
|
||||
_, tmpOk := req.MapProductTemplate[productInfo.Id]
|
||||
templateId, tmpOk := req.MapProductTemplate[productInfo.Id]
|
||||
//无最小价格则不显示 || 没有模板也不显示
|
||||
if !ok || !tmpOk {
|
||||
continue
|
||||
@@ -367,6 +379,7 @@ func (l *GetTagProductListLogic) getTagProducts(req getTagProductsReq) (productL
|
||||
Title: *productInfo.Title,
|
||||
SizeNum: uint32(sizeNum),
|
||||
CoverDefault: []types.CoverDefaultItem{},
|
||||
DefaultTemplateId: templateId,
|
||||
MinPrice: minPrice,
|
||||
HaveOptionalFitting: haveOptionalFitting,
|
||||
Recommended: *productInfo.IsRecommend > 0,
|
||||
|
||||
@@ -37,8 +37,8 @@ func (l *GetTemplateByPidLogic) GetTemplateByPid(req *types.GetTemplateByPidReq,
|
||||
if req.Pid == "" {
|
||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:pid is empty")
|
||||
}
|
||||
if req.ProductTemplateTagId <= 0 {
|
||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:product_template_tag_id")
|
||||
if req.TemplateTag == "" {
|
||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:template_tag")
|
||||
}
|
||||
//获取产品信息(只获取id)
|
||||
productInfo, err := l.svcCtx.AllModels.FsProduct.FindOneBySn(l.ctx, req.Pid, "id")
|
||||
@@ -67,15 +67,6 @@ 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 {
|
||||
@@ -92,7 +83,7 @@ func (l *GetTemplateByPidLogic) GetTemplateByPid(req *types.GetTemplateByPidReq,
|
||||
mapModel[v.Id] = k
|
||||
}
|
||||
//查询模型ids下对应tag标签的模板
|
||||
templateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByModelIdsTemplateTag(l.ctx, modelIds, *templateTagInfo.TemplateTag, "")
|
||||
templateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByModelIdsTemplateTag(l.ctx, modelIds, req.TemplateTag, "")
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get template list")
|
||||
@@ -113,17 +104,42 @@ func (l *GetTemplateByPidLogic) GetTemplateByPid(req *types.GetTemplateByPidReq,
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeJsonErr, fmt.Sprintf("failed to parse json product template info(may be old data):%d", templateInfo.Id))
|
||||
}
|
||||
//后台隐藏/显示信息
|
||||
var switchInfo interface{}
|
||||
//后台隐藏/显示信息(现在下面是写死了)
|
||||
/*var switchInfo interface{}
|
||||
if templateInfo.SwitchInfo != nil && *templateInfo.SwitchInfo != "" {
|
||||
_ = json.Unmarshal([]byte(*templateInfo.SwitchInfo), &switchInfo)
|
||||
}
|
||||
}*/
|
||||
modelInfo := modelList[modelIndex]
|
||||
mapKey := fmt.Sprintf("_%d", *modelInfo.SizeId)
|
||||
rsp[mapKey] = map[string]interface{}{
|
||||
"id": templateInfo.Id,
|
||||
"material": *templateInfo.MaterialImg,
|
||||
"material_data": switchInfo,
|
||||
"id": templateInfo.Id,
|
||||
"material": *templateInfo.MaterialImg,
|
||||
//写死的数据
|
||||
"material_data": map[string]interface{}{
|
||||
"QRcode": map[string]interface{}{
|
||||
"if_show": true,
|
||||
"text": "1111",
|
||||
"default_value": "11111",
|
||||
},
|
||||
"Website": map[string]interface{}{
|
||||
"if_show": true,
|
||||
"text": "2222",
|
||||
"default_value": "2222",
|
||||
},
|
||||
"Address": map[string]interface{}{
|
||||
"if_show": true,
|
||||
"text": "address",
|
||||
"default_value": "address",
|
||||
},
|
||||
"Phone": map[string]interface{}{
|
||||
"if_show": true,
|
||||
"text": "phone",
|
||||
"default_value": "默认phone",
|
||||
},
|
||||
"Logo": map[string]interface{}{
|
||||
"material": "/image/logo/aHnT1_rzubdwax_scale.png",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return resp.SetStatusWithMessage(basic.CodeOK, "success", rsp)
|
||||
|
||||
@@ -130,7 +130,7 @@ func (l *HomePageRecommendProductListLogic) HomePageRecommendProductList(req *ty
|
||||
}
|
||||
}
|
||||
//获取模板(只是获取产品product_id)
|
||||
productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIds(l.ctx, productIds, "product_id")
|
||||
productTemplatesV2, err = l.svcCtx.AllModels.FsProductTemplateV2.FindAllByProductIds(l.ctx, productIds, "", "product_id")
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatusWithMessage(basic.CodeServiceErr, "get product template_v2 err")
|
||||
|
||||
@@ -249,6 +249,7 @@ type GetRecommandProductListRsp struct {
|
||||
type GetTagProductListReq struct {
|
||||
Cid int64 `form:"cid,optional"` //分类id
|
||||
Size uint32 `form:"size,optional"` //尺寸
|
||||
TemplateTag string `form:"template_tag,optional"` //模板标签
|
||||
WithProduct bool `form:"with_product,optional"` //是否携带分类下的产品
|
||||
}
|
||||
|
||||
@@ -275,6 +276,7 @@ type TagProduct struct {
|
||||
SizeNum uint32 `json:"size_num"`
|
||||
MinPrice int64 `json:"min_price"`
|
||||
CoverDefault []CoverDefaultItem `json:"cover_default"`
|
||||
DefaultTemplateId int64 `json:"default_template_id"`
|
||||
HaveOptionalFitting bool `json:"have_optional_fitting"`
|
||||
Recommended bool `json:"recommended"`
|
||||
}
|
||||
@@ -340,9 +342,9 @@ type GetSizeByPidRsp struct {
|
||||
}
|
||||
|
||||
type GetTemplateByPidReq struct {
|
||||
Pid string `form:"pid"`
|
||||
ProductSizeId int64 `form:"product_size_id,optional"`
|
||||
ProductTemplateTagId int64 `form:"product_template_tag_id"`
|
||||
Pid string `form:"pid"`
|
||||
ProductSizeId int64 `form:"product_size_id,optional"`
|
||||
TemplateTag string `form:"template_tag"`
|
||||
}
|
||||
|
||||
type GetFittingByPidReq struct {
|
||||
|
||||
@@ -2,7 +2,7 @@ Name: resource
|
||||
Host: 0.0.0.0
|
||||
Port: 9916
|
||||
ReplicaId: 60
|
||||
Timeout: 15000 #服务超时时间(毫秒)
|
||||
Timeout: 150000 #服务超时时间(毫秒)
|
||||
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
||||
Auth:
|
||||
AccessSecret: fusen2023
|
||||
|
||||
35
server/resource/internal/handler/logoremovebghandler.go
Normal file
35
server/resource/internal/handler/logoremovebghandler.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"fusenapi/utils/basic"
|
||||
|
||||
"fusenapi/server/resource/internal/logic"
|
||||
"fusenapi/server/resource/internal/svc"
|
||||
"fusenapi/server/resource/internal/types"
|
||||
)
|
||||
|
||||
func LogoRemovebgHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var req types.LogoRemovebgReq
|
||||
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建一个业务逻辑层实例
|
||||
l := logic.NewLogoRemovebgLogic(r.Context(), svcCtx)
|
||||
|
||||
rl := reflect.ValueOf(l)
|
||||
basic.BeforeLogic(w, r, rl)
|
||||
|
||||
resp := l.LogoRemovebg(&req, userinfo)
|
||||
|
||||
if !basic.AfterLogic(w, r, rl, resp) {
|
||||
basic.NormalAfterLogic(w, r, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/api/resource/logo-combine",
|
||||
Handler: LogoCombineHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/api/resource/logo-removebg",
|
||||
Handler: LogoRemovebgHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/api/resource/info",
|
||||
|
||||
61
server/resource/internal/logic/logoremovebglogic.go
Normal file
61
server/resource/internal/logic/logoremovebglogic.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fusenapi/service/repositories"
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/basic"
|
||||
|
||||
"context"
|
||||
|
||||
"fusenapi/server/resource/internal/svc"
|
||||
"fusenapi/server/resource/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type LogoRemovebgLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewLogoRemovebgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LogoRemovebgLogic {
|
||||
return &LogoRemovebgLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// 处理进入前逻辑w,r
|
||||
// func (l *LogoRemovebgLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||
// }
|
||||
|
||||
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||
// func (l *LogoRemovebgLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
// }
|
||||
|
||||
func (l *LogoRemovebgLogic) LogoRemovebg(req *types.LogoRemovebgReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||
// userinfo 传入值时, 一定不为null
|
||||
res, err := l.svcCtx.Repositories.ImageHandle.LogoStandard(l.ctx, &repositories.LogoStandardReq{
|
||||
IsRemoveBg: req.IsRemoveBg,
|
||||
LogoFile: req.LogoFile,
|
||||
Width: req.Width,
|
||||
Height: req.Height,
|
||||
Proportion: req.Proportion,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return resp.SetStatus(basic.CodeServiceErr)
|
||||
}
|
||||
|
||||
// 返回成功的响应和上传URL
|
||||
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
|
||||
"resource_id": res.ResourceId,
|
||||
"resource_url": res.ResourceUrl,
|
||||
"ismax_proportion": res.IsmaxProportion,
|
||||
"img_color": res.ImgColor,
|
||||
})
|
||||
}
|
||||
@@ -5,6 +5,14 @@ import (
|
||||
"fusenapi/utils/basic"
|
||||
)
|
||||
|
||||
type LogoRemovebgReq struct {
|
||||
IsRemoveBg string `form:"is_remove_bg"`
|
||||
LogoFile string `form:"logo_file"`
|
||||
Width string `form:"width"`
|
||||
Height string `form:"height"`
|
||||
Proportion int64 `form:"proportion"`
|
||||
}
|
||||
|
||||
type ResourceInfoReq struct {
|
||||
ResourceId string `form:"resource_id,optional"` // 资源ID
|
||||
ResourceKey string `form:"resource_key,optional"` // 资源唯一标识
|
||||
|
||||
@@ -2,7 +2,8 @@ Name: upload
|
||||
Host: localhost
|
||||
Port: 9912
|
||||
ReplicaId: 70
|
||||
Timeout: 15000 #服务超时时间
|
||||
Timeout: 150000 #服务超时时间
|
||||
MaxBytes: 104857600 #传输字节大小
|
||||
SourceMysql: "fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest"
|
||||
Env: "test"
|
||||
Auth:
|
||||
|
||||
@@ -57,6 +57,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/api/upload/upload-file-base",
|
||||
Handler: UploadFileBaseHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/api/upload/up-standard-logo",
|
||||
Handler: UploadLogoStandardHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
35
server/upload/internal/handler/uploadlogostandardhandler.go
Normal file
35
server/upload/internal/handler/uploadlogostandardhandler.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"fusenapi/utils/basic"
|
||||
|
||||
"fusenapi/server/upload/internal/logic"
|
||||
"fusenapi/server/upload/internal/svc"
|
||||
"fusenapi/server/upload/internal/types"
|
||||
)
|
||||
|
||||
func UploadLogoStandardHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var req types.UploadLogoStandardReq
|
||||
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建一个业务逻辑层实例
|
||||
l := logic.NewUploadLogoStandardLogic(r.Context(), svcCtx)
|
||||
|
||||
rl := reflect.ValueOf(l)
|
||||
basic.BeforeLogic(w, r, rl)
|
||||
|
||||
resp := l.UploadLogoStandard(&req, userinfo)
|
||||
|
||||
if !basic.AfterLogic(w, r, rl, resp) {
|
||||
basic.NormalAfterLogic(w, r, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package logic
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"fusenapi/model/gmodel"
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/basic"
|
||||
@@ -95,6 +96,12 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us
|
||||
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,file is not image")
|
||||
}
|
||||
|
||||
// 限制上传文件大小 50k
|
||||
// maxSize := 100 * 1024
|
||||
// if fileHeader.Size > int64(maxSize) {
|
||||
// return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,The file size exceeds the maximum limit of 100k")
|
||||
// }
|
||||
|
||||
// 读取数据流
|
||||
ioData, err := io.ReadAll(fileObject)
|
||||
if err != nil {
|
||||
@@ -124,6 +131,8 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us
|
||||
return resp.SetStatus(basic.CodeFileUploadErr, "upload file failed")
|
||||
}
|
||||
|
||||
logx.Infof("上传logo请求算法--开始时间:%v", time.Now())
|
||||
|
||||
var logoWidth int64
|
||||
var logoHeight int64
|
||||
// 查看sku是否存在
|
||||
@@ -146,35 +155,39 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us
|
||||
}
|
||||
var resultStr string
|
||||
|
||||
var postMap = make(map[string]interface{}, 1)
|
||||
var postMap = make(map[string]string, 1)
|
||||
postMap["logo_url"] = uploadRes.ResourceUrl
|
||||
postMapB, _ := json.Marshal(postMap)
|
||||
fmt.Println(string(postMapB))
|
||||
|
||||
var headerData = make(map[string]string, 1)
|
||||
headerData["Content-Type"] = "application/json"
|
||||
result, err := curl.ApiCall(l.svcCtx.Config.BLMService.ImageProcess.Url, "POST", headerData, strings.NewReader(string(postMapB)), time.Second*20)
|
||||
result, err := curl.ApiCall(l.svcCtx.Config.BLMService.ImageProcess.Url, "POST", headerData, strings.NewReader(string(postMapB)), time.Minute*5)
|
||||
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail 01")
|
||||
}
|
||||
defer result.Body.Close()
|
||||
b, err := io.ReadAll(result.Body)
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail 02")
|
||||
}
|
||||
|
||||
logx.Infof("上传logo请求算法--结束时间:%v", time.Now())
|
||||
logx.Infof("上传logo请求算法--返回结果:%v", string(b))
|
||||
|
||||
if string(b) == "Internal Server Error" {
|
||||
err = errors.New("BLMService fail Internal Server Error")
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail 03")
|
||||
} else {
|
||||
var resData map[string]interface{}
|
||||
err = json.Unmarshal(b, &resData)
|
||||
if err != nil || resData == nil {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail 04")
|
||||
}
|
||||
|
||||
if resData != nil {
|
||||
@@ -182,11 +195,11 @@ func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.Us
|
||||
resultStr = resData["data"].(string)
|
||||
} else {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErrType, "service fail")
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErrType, "service fail 05")
|
||||
}
|
||||
} else {
|
||||
logx.Error(err)
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail 06")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
43
server/upload/internal/logic/uploadlogostandardlogic.go
Normal file
43
server/upload/internal/logic/uploadlogostandardlogic.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/basic"
|
||||
|
||||
"context"
|
||||
|
||||
"fusenapi/server/upload/internal/svc"
|
||||
"fusenapi/server/upload/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UploadLogoStandardLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewUploadLogoStandardLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadLogoStandardLogic {
|
||||
return &UploadLogoStandardLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// 处理进入前逻辑w,r
|
||||
// func (l *UploadLogoStandardLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||
// }
|
||||
|
||||
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||
// func (l *UploadLogoStandardLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
// }
|
||||
|
||||
func (l *UploadLogoStandardLogic) UploadLogoStandard(req *types.UploadLogoStandardReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||
// userinfo 传入值时, 一定不为null
|
||||
|
||||
return resp.SetStatus(basic.CodeOK)
|
||||
}
|
||||
@@ -5,6 +5,14 @@ import (
|
||||
"fusenapi/utils/basic"
|
||||
)
|
||||
|
||||
type UploadLogoStandardReq struct {
|
||||
IsRemoveBg string `form:"is_remove_bg"`
|
||||
LogoFile string `form:"logo_file"`
|
||||
Width string `form:"width"`
|
||||
Height string `form:"height"`
|
||||
Proportion int64 `form:"proportion"`
|
||||
}
|
||||
|
||||
type UploadFileBaseReq struct {
|
||||
ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型:1=对外,2=对内
|
||||
FileKey string `form:"file_key"` // 上传唯一标识信息
|
||||
|
||||
@@ -3,7 +3,6 @@ package logic
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"fusenapi/constants"
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/id_generator"
|
||||
@@ -81,7 +80,13 @@ type wsConnectItem struct {
|
||||
renderProperty renderProperty //扩展云渲染属性
|
||||
}
|
||||
|
||||
// 请求建立连接,升级websocket协议
|
||||
func (l *DataTransferLogic) DataTransfer(w http.ResponseWriter, r *http.Request) {
|
||||
//把子协议携带的token设置到标准token头信息中
|
||||
token := r.Header.Get("Sec-Websocket-Protocol")
|
||||
r.Header.Set("Authorization", "Bearer "+token)
|
||||
//设置Sec-Websocket-Protocol
|
||||
upgrade.Subprotocols = []string{token}
|
||||
//升级websocket
|
||||
conn, err := upgrade.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
@@ -90,29 +95,18 @@ func (l *DataTransferLogic) DataTransfer(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
defer conn.Close()
|
||||
//鉴权不成功后断开
|
||||
/*var (
|
||||
var (
|
||||
userInfo *auth.UserInfo
|
||||
isAuth bool
|
||||
)
|
||||
isAuth, userInfo = l.checkAuth(r)
|
||||
if !isAuth {
|
||||
time.Sleep(time.Second * 1) //兼容下火狐
|
||||
rsp := websocket_data.DataTransferData{
|
||||
T: constants.WEBSOCKET_UNAUTH,
|
||||
D: nil,
|
||||
}
|
||||
b, _ := json.Marshal(rsp)
|
||||
//先发一条正常信息
|
||||
_ = conn.WriteMessage(websocket.TextMessage, b)
|
||||
//发送关闭信息
|
||||
_ = conn.WriteMessage(websocket.CloseMessage, nil)
|
||||
//未授权响应消息
|
||||
l.unAuthResponse(conn)
|
||||
return
|
||||
}*/
|
||||
//测试的目前写死 39
|
||||
var userInfo auth.UserInfo
|
||||
userInfo.UserId = 39
|
||||
}
|
||||
//设置连接
|
||||
ws := l.setConnPool(conn, userInfo)
|
||||
ws := l.setConnPool(conn, *userInfo)
|
||||
defer ws.close()
|
||||
//循环读客户端信息
|
||||
go ws.readLoop()
|
||||
@@ -144,7 +138,7 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo auth.User
|
||||
userId: userInfo.UserId,
|
||||
guestId: userInfo.GuestId,
|
||||
renderProperty: renderProperty{
|
||||
renderImageTask: make(map[string]string),
|
||||
renderImageTask: make(map[string]*renderTask),
|
||||
renderImageTaskCtlChan: make(chan renderImageControlChanItem, 100),
|
||||
renderChan: make(chan []byte, 100),
|
||||
},
|
||||
@@ -153,7 +147,7 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo auth.User
|
||||
mapConnPool.Store(uniqueId, ws)
|
||||
go func() {
|
||||
//把连接成功消息发回去
|
||||
time.Sleep(time.Second * 1) //兼容下火狐
|
||||
time.Sleep(time.Second * 1) //兼容下火狐(直接发回去收不到第一条消息:有待研究)
|
||||
ws.sendToOutChan(ws.respondDataFormat(constants.WEBSOCKET_CONNECT_SUCCESS, uniqueId))
|
||||
}()
|
||||
return ws
|
||||
@@ -162,24 +156,20 @@ func (l *DataTransferLogic) setConnPool(conn *websocket.Conn, userInfo auth.User
|
||||
// 获取唯一id
|
||||
func (l *DataTransferLogic) getUniqueId(userInfo auth.UserInfo) string {
|
||||
//后面拼接上用户id
|
||||
uniqueId := uuid.New().String() + getUserPart(userInfo.UserId, userInfo.GuestId)
|
||||
uniqueId := uuid.New().String() + getUserJoinPart(userInfo.UserId, userInfo.GuestId)
|
||||
if _, ok := mapConnPool.Load(uniqueId); ok {
|
||||
uniqueId = l.getUniqueId(userInfo)
|
||||
}
|
||||
return uniqueId
|
||||
}
|
||||
|
||||
// 获取用户拼接部分
|
||||
func getUserPart(userId, guestId int64) string {
|
||||
return fmt.Sprintf("_%d_%d", userId, guestId)
|
||||
}
|
||||
|
||||
// 鉴权
|
||||
func (l *DataTransferLogic) checkAuth(r *http.Request) (isAuth bool, userInfo *auth.UserInfo) {
|
||||
// 解析JWT token,并对空用户进行判断
|
||||
claims, err := l.svcCtx.ParseJwtToken(r)
|
||||
// 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return false, nil
|
||||
}
|
||||
if claims != nil {
|
||||
@@ -187,6 +177,7 @@ func (l *DataTransferLogic) checkAuth(r *http.Request) (isAuth bool, userInfo *a
|
||||
userInfo, err = auth.GetUserInfoFormMapClaims(claims)
|
||||
// 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
return false, nil
|
||||
}
|
||||
//不是登录用户也不是游客
|
||||
@@ -198,6 +189,22 @@ func (l *DataTransferLogic) checkAuth(r *http.Request) (isAuth bool, userInfo *a
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// 鉴权失败通知
|
||||
func (l *DataTransferLogic) unAuthResponse(conn *websocket.Conn) {
|
||||
time.Sleep(time.Second * 1) //兼容下火狐(直接发回去收不到第一条消息:有待研究)
|
||||
rsp := websocket_data.DataTransferData{
|
||||
T: constants.WEBSOCKET_UNAUTH,
|
||||
D: nil,
|
||||
}
|
||||
b, _ := json.Marshal(rsp)
|
||||
//先发一条正常信息
|
||||
_ = conn.WriteMessage(websocket.TextMessage, b)
|
||||
//发送关闭信息
|
||||
_ = conn.WriteMessage(websocket.CloseMessage, nil)
|
||||
//关闭连接
|
||||
conn.Close()
|
||||
}
|
||||
|
||||
// 心跳
|
||||
func (w *wsConnectItem) heartbeat() {
|
||||
tick := time.Tick(time.Second * 5)
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fusenapi/constants"
|
||||
"context"
|
||||
"fusenapi/server/websocket/internal/svc"
|
||||
"fusenapi/server/websocket/internal/types"
|
||||
"fusenapi/utils/auth"
|
||||
"fusenapi/utils/basic"
|
||||
"fusenapi/utils/file"
|
||||
"fusenapi/utils/websocket_data"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
|
||||
"fusenapi/server/websocket/internal/svc"
|
||||
"fusenapi/server/websocket/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
@@ -41,14 +37,17 @@ func NewRenderNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Rend
|
||||
|
||||
func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||
if req.TaskId == "" {
|
||||
logx.Error("渲染回调参数错误:invalid param task_id")
|
||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param task_id")
|
||||
}
|
||||
if req.Image == "" {
|
||||
logx.Error("渲染回调参数错误:invalid param image")
|
||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param image")
|
||||
}
|
||||
if req.UserId == 0 && req.GuestId == 0 {
|
||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid user_id or guest_id")
|
||||
}
|
||||
//存base64打印测试
|
||||
/* f, _ := os.Create("b.txt")
|
||||
defer f.Close()
|
||||
f.WriteString(req.Image)*/
|
||||
// 上传文件
|
||||
var upload = file.Upload{
|
||||
Ctx: l.ctx,
|
||||
@@ -67,7 +66,7 @@ func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq, userinfo *a
|
||||
FileByte: nil,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Error(err)
|
||||
logx.Error("渲染回调上传文件失败:", err)
|
||||
return resp.SetStatusWithMessage(basic.CodeFileUploadErr, "failed to upload render resource image")
|
||||
}
|
||||
//遍历websocket链接把数据传进去
|
||||
@@ -75,37 +74,24 @@ func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq, userinfo *a
|
||||
//断言连接
|
||||
ws, ok := value.(wsConnectItem)
|
||||
if !ok {
|
||||
logx.Error("渲染回调断言websocket连接失败")
|
||||
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,
|
||||
//记录收到unity渲染结果时间
|
||||
ws.modifyRenderTaskTimeConsuming(renderImageControlChanItem{
|
||||
Option: 2,
|
||||
TaskProperty: renderTask{
|
||||
UnityRenderEndTime: time.Now().UTC().Unix(),
|
||||
},
|
||||
})
|
||||
//发送处理并删除任务
|
||||
ws.deleteRenderTask(renderImageControlChanItem{
|
||||
Option: 0, //0删除 1添加
|
||||
TaskId: req.TaskId,
|
||||
RenderNotifyImageUrl: 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("渲染回调成功######################")
|
||||
logx.Info("渲染回调成功,渲染结果图片为:", uploadRes.ResourceUrl)
|
||||
return resp.SetStatusWithMessage(basic.CodeOK, "success")
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"fusenapi/constants"
|
||||
"fusenapi/service/repositories"
|
||||
"fusenapi/utils/curl"
|
||||
@@ -18,16 +19,25 @@ import (
|
||||
|
||||
// 云渲染属性
|
||||
type renderProperty struct {
|
||||
renderImageTask map[string]string //需要渲染的图片任务 key是taskId val 是renderId
|
||||
renderImageTask map[string]*renderTask //需要渲染的图片任务 key是taskId val 是renderId
|
||||
renderImageTaskCtlChan chan renderImageControlChanItem //渲染任务新增移除的控制通道
|
||||
renderChan chan []byte //渲染的缓冲队列
|
||||
}
|
||||
type renderTask struct {
|
||||
RenderId string //渲染id(前端传的)
|
||||
CombineBeginTime int64 //合图开始时间
|
||||
CombineEndTime int64 //合图结束时间
|
||||
UnityRenderBeginTime int64 //发送给unity时间
|
||||
UnityRenderEndTime int64 //unity回调结果时间
|
||||
}
|
||||
|
||||
// 渲染任务新增移除的控制通道的数据
|
||||
type renderImageControlChanItem struct {
|
||||
Option int // 0删除 1添加
|
||||
TaskId string //map的key
|
||||
RenderId string // map的val
|
||||
Option int // 0删除 1添加
|
||||
TaskId string //map的key
|
||||
RenderId string // map的val(增加任务时候传)
|
||||
RenderNotifyImageUrl string //渲染回调数据(删除任务时候传)
|
||||
TaskProperty renderTask //渲染任务的属性
|
||||
}
|
||||
|
||||
// 发送到渲染缓冲池
|
||||
@@ -35,14 +45,14 @@ func (w *wsConnectItem) sendToRenderChan(data []byte) {
|
||||
select {
|
||||
case <-w.closeChan: //已经关闭
|
||||
return
|
||||
case w.renderProperty.renderChan <- data:
|
||||
case w.renderProperty.renderChan <- data: //发入到缓冲池
|
||||
return
|
||||
case <-time.After(time.Second * 3):
|
||||
case <-time.After(time.Second * 3): //三秒没进入缓冲池就丢弃
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染发送到组装数据组装数据
|
||||
// 渲染发送到组装数据组装数据(缓冲池)
|
||||
func (w *wsConnectItem) renderImage() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@@ -69,7 +79,6 @@ func (w *wsConnectItem) consumeRenderCache(data []byte) {
|
||||
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")
|
||||
@@ -116,7 +125,10 @@ func (w *wsConnectItem) consumeRenderCache(data []byte) {
|
||||
hashVal := renderImageData.RenderData
|
||||
hashVal.UserId = 0
|
||||
hashVal.GuestId = 0
|
||||
taskId := hash.JsonHashKey(hashVal)
|
||||
hashByte, _ := json.Marshal(hashVal)
|
||||
var hashData map[string]interface{}
|
||||
_ = json.Unmarshal(hashByte, &hashData)
|
||||
taskId := hash.JsonHashKey(hashData)
|
||||
//查询有没有缓存的资源,有就返回######################
|
||||
resource, err := w.logic.svcCtx.AllModels.FsResource.FindOneById(w.logic.ctx, taskId)
|
||||
if err != nil {
|
||||
@@ -127,8 +139,10 @@ func (w *wsConnectItem) consumeRenderCache(data []byte) {
|
||||
} else {
|
||||
//返回给客户端
|
||||
b := w.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
|
||||
RenderId: renderImageData.RenderId,
|
||||
Image: *resource.ResourceUrl,
|
||||
RenderId: renderImageData.RenderId,
|
||||
Image: *resource.ResourceUrl,
|
||||
CombineTakesTime: "耗时0秒(缓存)",
|
||||
UnityRenderTakesTime: "耗时0秒(缓存)",
|
||||
})
|
||||
//发送数据到out chan
|
||||
w.sendToOutChan(b)
|
||||
@@ -136,11 +150,11 @@ func (w *wsConnectItem) consumeRenderCache(data []byte) {
|
||||
}
|
||||
//###########################################
|
||||
//把需要渲染的图片任务加进去
|
||||
w.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{
|
||||
w.createRenderTask(renderImageControlChanItem{
|
||||
Option: 1, //0删除 1添加
|
||||
TaskId: taskId,
|
||||
RenderId: renderImageData.RenderId,
|
||||
}
|
||||
})
|
||||
//组装数据
|
||||
if err = w.assembleRenderData(taskId, renderImageData); err != nil {
|
||||
logx.Error("组装数据失败:", err)
|
||||
@@ -165,8 +179,15 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re
|
||||
logx.Error("failed to get template info:", err)
|
||||
return err
|
||||
}
|
||||
//记录刀版图合成开始时间
|
||||
w.modifyRenderTaskTimeConsuming(renderImageControlChanItem{
|
||||
Option: 2,
|
||||
TaskProperty: renderTask{
|
||||
CombineBeginTime: time.Now().UTC().Unix(),
|
||||
},
|
||||
})
|
||||
//获取刀版图
|
||||
res, err := w.logic.svcCtx.Repositories.ImageHandle.LogoCombine(w.logic.ctx, &repositories.LogoCombineReq{
|
||||
combineReq := repositories.LogoCombineReq{
|
||||
UserId: info.RenderData.UserId,
|
||||
GuestId: info.RenderData.GuestId,
|
||||
TemplateId: productTemplate.Id,
|
||||
@@ -175,9 +196,10 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re
|
||||
Slogan: info.RenderData.Slogan,
|
||||
Address: info.RenderData.Address,
|
||||
Phone: info.RenderData.Phone,
|
||||
})
|
||||
}
|
||||
res, err := w.logic.svcCtx.Repositories.ImageHandle.LogoCombine(w.logic.ctx, &combineReq)
|
||||
if err != nil {
|
||||
logx.Error("合成刀版图失败:", err)
|
||||
logx.Error("合成刀版图失败,合成请求数据:", combineReq, "错误信息:", err)
|
||||
return err
|
||||
}
|
||||
combineImage := "" //刀版图
|
||||
@@ -187,17 +209,18 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re
|
||||
logx.Error("合成刀版图失败,合成的刀版图是空指针:", err)
|
||||
return err
|
||||
}
|
||||
logx.Info("合成刀版图成功:", *res.ResourceUrl)
|
||||
//记录刀版图合成结束时间
|
||||
w.modifyRenderTaskTimeConsuming(renderImageControlChanItem{
|
||||
Option: 2,
|
||||
TaskProperty: renderTask{
|
||||
CombineEndTime: time.Now().UTC().Unix(),
|
||||
},
|
||||
})
|
||||
logx.Info("合成刀版图成功,合成刀版图数据:", combineReq, ",logo图片:", info.RenderData.Logo, " 刀版图:", *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
|
||||
}
|
||||
@@ -208,6 +231,9 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re
|
||||
refletion := -1
|
||||
if element.Refletion != nil && *element.Refletion != "" {
|
||||
refletion, err = strconv.Atoi(*element.Refletion)
|
||||
if err != nil {
|
||||
logx.Error("err refletion:set default -1")
|
||||
}
|
||||
}
|
||||
//组装data数据
|
||||
var mode map[string]interface{}
|
||||
@@ -272,7 +298,7 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re
|
||||
"folder": "", //todo 千人千面需要使用
|
||||
}
|
||||
//请求unity接口
|
||||
url := "http://api.fusen.3718.cn:4050/api/render/queue/push"
|
||||
url := w.logic.svcCtx.Config.Unity.Host + "/api/render/queue/push"
|
||||
header := make(map[string]string)
|
||||
header["content-type"] = "application/json"
|
||||
t := time.Now().UTC()
|
||||
@@ -283,17 +309,66 @@ func (w *wsConnectItem) assembleRenderData(taskId string, info websocket_data.Re
|
||||
"create_at": t,
|
||||
"render_data": sendData,
|
||||
}
|
||||
p, _ := json.Marshal(postData)
|
||||
_, err = curl.ApiCall(url, "POST", header, bytes.NewReader(p), time.Second*10)
|
||||
postDataBytes, _ := json.Marshal(postData)
|
||||
_, err = curl.ApiCall(url, "POST", header, bytes.NewReader(postDataBytes), time.Second*10)
|
||||
if err != nil {
|
||||
logx.Error("failed to send data to unity")
|
||||
return err
|
||||
}
|
||||
logx.Info("发送到unity成功################")
|
||||
//记录发送到unity时间
|
||||
w.modifyRenderTaskTimeConsuming(renderImageControlChanItem{
|
||||
Option: 2,
|
||||
TaskProperty: renderTask{
|
||||
UnityRenderBeginTime: time.Now().UTC().Unix(),
|
||||
},
|
||||
})
|
||||
logx.Info("发送到unity成功,刀版图:", combineImage, " 请求unity的数据:", string(postDataBytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 操作连接中渲染任务的增加/删除
|
||||
// 增加渲染任务
|
||||
func (w *wsConnectItem) createRenderTask(data renderImageControlChanItem) {
|
||||
//强制设为增加
|
||||
data.Option = 1
|
||||
select {
|
||||
case <-w.closeChan: //关闭
|
||||
return
|
||||
case w.renderProperty.renderImageTaskCtlChan <- data:
|
||||
return
|
||||
case <-time.After(time.Second * 3):
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染回调处理并删除渲染任务
|
||||
func (w *wsConnectItem) deleteRenderTask(data renderImageControlChanItem) {
|
||||
//强制设为删除
|
||||
data.Option = 0
|
||||
select {
|
||||
case <-w.closeChan: //关闭
|
||||
return
|
||||
case w.renderProperty.renderImageTaskCtlChan <- data:
|
||||
return
|
||||
case <-time.After(time.Second * 3):
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 修改耗时属性(只有耗时属性可以更新)
|
||||
func (w *wsConnectItem) modifyRenderTaskTimeConsuming(data renderImageControlChanItem) {
|
||||
//强制设为修改耗时属性
|
||||
data.Option = 2
|
||||
select {
|
||||
case <-w.closeChan: //关闭
|
||||
return
|
||||
case w.renderProperty.renderImageTaskCtlChan <- data:
|
||||
return
|
||||
case <-time.After(time.Second * 3):
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 操作连接中渲染任务的增加/删除(任务map不能读写并发,所以放在chan里面串行执行)
|
||||
func (w *wsConnectItem) operationRenderTask() {
|
||||
for {
|
||||
select {
|
||||
@@ -301,10 +376,46 @@ func (w *wsConnectItem) operationRenderTask() {
|
||||
return
|
||||
case data := <-w.renderProperty.renderImageTaskCtlChan:
|
||||
switch data.Option {
|
||||
case 0: //删除任务
|
||||
case 0: //渲染结果回调,删除任务
|
||||
//存在任务,则发送渲染结果给前端
|
||||
if taskData, ok := w.renderProperty.renderImageTask[data.TaskId]; ok {
|
||||
CombineTakesTime := ""
|
||||
UnityRenderTakesTime := ""
|
||||
if taskData.CombineBeginTime > 0 && taskData.CombineEndTime > 0 {
|
||||
CombineTakesTime = fmt.Sprintf("耗时%d秒", taskData.CombineEndTime-taskData.CombineBeginTime)
|
||||
}
|
||||
if taskData.UnityRenderBeginTime > 0 && taskData.UnityRenderEndTime > 0 {
|
||||
UnityRenderTakesTime = fmt.Sprintf("耗时%d秒", taskData.UnityRenderEndTime-taskData.UnityRenderBeginTime)
|
||||
}
|
||||
//发送到出口
|
||||
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, websocket_data.RenderImageRspMsg{
|
||||
RenderId: taskData.RenderId,
|
||||
Image: data.RenderNotifyImageUrl,
|
||||
CombineTakesTime: CombineTakesTime,
|
||||
UnityRenderTakesTime: UnityRenderTakesTime,
|
||||
}))
|
||||
}
|
||||
delete(w.renderProperty.renderImageTask, data.TaskId)
|
||||
case 1: //新增任务
|
||||
w.renderProperty.renderImageTask[data.TaskId] = data.RenderId
|
||||
w.renderProperty.renderImageTask[data.TaskId] = &renderTask{
|
||||
RenderId: data.RenderId,
|
||||
}
|
||||
case 2: //修改(耗时)属性
|
||||
if taskData, ok := w.renderProperty.renderImageTask[data.TaskId]; ok {
|
||||
if data.TaskProperty.CombineBeginTime != 0 {
|
||||
taskData.CombineBeginTime = data.TaskProperty.CombineBeginTime
|
||||
}
|
||||
if data.TaskProperty.CombineEndTime != 0 {
|
||||
taskData.CombineEndTime = data.TaskProperty.CombineEndTime
|
||||
}
|
||||
if data.TaskProperty.UnityRenderBeginTime != 0 {
|
||||
taskData.UnityRenderBeginTime = data.TaskProperty.UnityRenderBeginTime
|
||||
}
|
||||
if data.TaskProperty.UnityRenderEndTime != 0 {
|
||||
taskData.UnityRenderEndTime = data.TaskProperty.UnityRenderEndTime
|
||||
}
|
||||
logx.Info("**********:", taskData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package logic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"fusenapi/constants"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
@@ -22,7 +23,7 @@ func (w *wsConnectItem) reuseLastConnect(data []byte) {
|
||||
return
|
||||
}
|
||||
//合成client后缀,不是同个后缀的不能复用
|
||||
userPart := getUserPart(w.userId, w.guestId)
|
||||
userPart := getUserJoinPart(w.userId, w.guestId)
|
||||
lenUserPart := len(userPart)
|
||||
if lenClientId <= lenUserPart {
|
||||
w.sendToOutChan(w.respondDataFormat(constants.WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR, "length of client id is to short"))
|
||||
@@ -36,10 +37,23 @@ func (w *wsConnectItem) reuseLastConnect(data []byte) {
|
||||
publicMutex.Lock()
|
||||
defer publicMutex.Unlock()
|
||||
//存在是不能给他申请重新绑定
|
||||
if _, ok := mapConnPool.Load(clientId); ok {
|
||||
rsp := w.respondDataFormat(constants.WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR, "id has bound by other connect ")
|
||||
w.sendToOutChan(rsp)
|
||||
return
|
||||
if v, ok := mapConnPool.Load(clientId); ok {
|
||||
obj, ok := v.(wsConnectItem)
|
||||
if !ok {
|
||||
logx.Error("连接断言失败")
|
||||
}
|
||||
//是当前自己占用
|
||||
if obj.uniqueId == w.uniqueId {
|
||||
//重新绑定
|
||||
w.uniqueId = clientId
|
||||
rsp := w.respondDataFormat(constants.WEBSOCKET_CONNECT_SUCCESS, clientId)
|
||||
w.sendToOutChan(rsp)
|
||||
return
|
||||
} else {
|
||||
rsp := w.respondDataFormat(constants.WEBSOCKET_REQUEST_RESUME_LAST_CONNECT_ERR, "id has bound by other connect ")
|
||||
w.sendToOutChan(rsp)
|
||||
return
|
||||
}
|
||||
}
|
||||
//重新绑定
|
||||
w.uniqueId = clientId
|
||||
@@ -47,3 +61,8 @@ func (w *wsConnectItem) reuseLastConnect(data []byte) {
|
||||
w.sendToOutChan(rsp)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户拼接部分(复用标识用到)
|
||||
func getUserJoinPart(userId, guestId int64) string {
|
||||
return fmt.Sprintf("_%d_%d", userId, guestId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user