Merge branch 'develop' into feature/auth

This commit is contained in:
eson
2023-08-22 10:34:21 +08:00
79 changed files with 1360 additions and 495 deletions

View File

@@ -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)

View File

@@ -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")

View File

@@ -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,
})
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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")

View File

@@ -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 {

View File

@@ -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

View 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)
}
}
}

View File

@@ -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",

View 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,
})
}

View File

@@ -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"` // 资源唯一标识

View File

@@ -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:

View File

@@ -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),
},
},
)
}

View 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)
}
}
}

View File

@@ -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")
}
}

View 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)
}

View File

@@ -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"` // 上传唯一标识信息

View File

@@ -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)

View File

@@ -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")
}

View File

@@ -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)
}
}
}
}

View File

@@ -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)
}