Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into feature/auth
This commit is contained in:
commit
8bea89754b
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,7 +4,7 @@
|
|||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
bin/
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
@ -127,6 +127,7 @@ type Day int64
|
|||||||
// 订单取消时间
|
// 订单取消时间
|
||||||
const (
|
const (
|
||||||
CANCLE_ORDER_EXPIRE Day = 48 * 3600
|
CANCLE_ORDER_EXPIRE Day = 48 * 3600
|
||||||
|
CANCLE_ORDER_EXPIRE_DAY Day = 2 // 2天
|
||||||
)
|
)
|
||||||
|
|
||||||
// 订单时间配置
|
// 订单时间配置
|
||||||
|
@ -9,9 +9,3 @@ const (
|
|||||||
//渲染结果数据队列
|
//渲染结果数据队列
|
||||||
RABBIT_MQ_RENDER_RESULT_DATA RABBIT_MQ = "RABBIT_MQ_RENDER_RESULT_DATA"
|
RABBIT_MQ_RENDER_RESULT_DATA RABBIT_MQ = "RABBIT_MQ_RENDER_RESULT_DATA"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 队列列表
|
|
||||||
var MQ_QUEUE_ARR = []RABBIT_MQ{
|
|
||||||
RABBIT_MQ_ASSEMBLE_RENDER_DATA,
|
|
||||||
RABBIT_MQ_RENDER_RESULT_DATA,
|
|
||||||
}
|
|
||||||
|
203
constants/render.go
Normal file
203
constants/render.go
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
// 渲染要用到的面片模板
|
||||||
|
const RENDER_FACE_SLICE_TEMPLATE_JSON = `[
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"tag": "MainColor",
|
||||||
|
"title": "",
|
||||||
|
"type": "color",
|
||||||
|
"text": "",
|
||||||
|
"fill": "{{MainColorFill}}",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": "Aqum2SmallCaps3",
|
||||||
|
"ifBr": false,
|
||||||
|
"ifShow": true,
|
||||||
|
"ifGroup": false,
|
||||||
|
"maxNum": 50,
|
||||||
|
"rotation": 0,
|
||||||
|
"lineHeight": 1,
|
||||||
|
"align": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"material": "",
|
||||||
|
"materialTime": "",
|
||||||
|
"materialName": "",
|
||||||
|
"QRcodeType": "",
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"proportion": 60,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"opacity": 1,
|
||||||
|
"optionalColor": [
|
||||||
|
{
|
||||||
|
"color": "#000000",
|
||||||
|
"name": "Black",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"zIndex": 1,
|
||||||
|
"svgPath": "",
|
||||||
|
"follow": {
|
||||||
|
"fill": "",
|
||||||
|
"ifShow": "",
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"group": [],
|
||||||
|
"cameraStand": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"tag": "SecondaryColor",
|
||||||
|
"title": "贴图3",
|
||||||
|
"type": "color",
|
||||||
|
"text": "",
|
||||||
|
"fill": "{{SecondaryColorFill}}",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": "Aqum2SmallCaps3",
|
||||||
|
"ifBr": false,
|
||||||
|
"ifShow": true,
|
||||||
|
"ifGroup": false,
|
||||||
|
"maxNum": 50,
|
||||||
|
"rotation": 0,
|
||||||
|
"lineHeight": 1,
|
||||||
|
"align": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"material": "",
|
||||||
|
"materialTime": "",
|
||||||
|
"materialName": "",
|
||||||
|
"QRcodeType": "",
|
||||||
|
"width": 1024,
|
||||||
|
"height": 1024,
|
||||||
|
"proportion": 60,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"opacity": 1,
|
||||||
|
"optionalColor": [
|
||||||
|
{
|
||||||
|
"color": "#000000",
|
||||||
|
"name": "Black",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"zIndex": 2,
|
||||||
|
"svgPath": "",
|
||||||
|
"follow": {
|
||||||
|
"fill": "",
|
||||||
|
"ifShow": "",
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"group": [],
|
||||||
|
"cameraStand": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "569d7981-25c3-3c03-0e7e-800c14800362",
|
||||||
|
"tag": "Slogan",
|
||||||
|
"title": "贴图4",
|
||||||
|
"type": "text",
|
||||||
|
"text": "",
|
||||||
|
"fill": "",
|
||||||
|
"fontSize": 13,
|
||||||
|
"fontFamily": "MontserratBold3",
|
||||||
|
"ifBr": false,
|
||||||
|
"ifShow": true,
|
||||||
|
"ifGroup": false,
|
||||||
|
"maxNum": 50,
|
||||||
|
"rotation": 0,
|
||||||
|
"lineHeight": 1,
|
||||||
|
"align": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"material": "",
|
||||||
|
"materialTime": "",
|
||||||
|
"materialName": "",
|
||||||
|
"QRcodeType": "",
|
||||||
|
"width": 309.9999999999993,
|
||||||
|
"height": 11.999265664648076,
|
||||||
|
"proportion": 60,
|
||||||
|
"x": 97.0015259021898,
|
||||||
|
"y": 575.300725990631,
|
||||||
|
"opacity": 1,
|
||||||
|
"optionalColor": [
|
||||||
|
{
|
||||||
|
"color": "#000000",
|
||||||
|
"name": "Black",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"zIndex": 3,
|
||||||
|
"svgPath": "",
|
||||||
|
"follow": {
|
||||||
|
"fill": "38c09538-937d-510c-bf32-bfb1ce90cafa",
|
||||||
|
"ifShow": "",
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"group": [],
|
||||||
|
"cameraStand": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 45
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c466e27c-d48f-db86-b85f-3c4c51114046",
|
||||||
|
"tag": "Logo",
|
||||||
|
"title": "贴图8",
|
||||||
|
"type": "image",
|
||||||
|
"text": "",
|
||||||
|
"fill": "#0082ca",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": "Aqum2SmallCaps3",
|
||||||
|
"ifBr": false,
|
||||||
|
"ifShow": true,
|
||||||
|
"ifGroup": false,
|
||||||
|
"maxNum": 50,
|
||||||
|
"rotation": 0,
|
||||||
|
"lineHeight": 1,
|
||||||
|
"align": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"material": "{{LogoMaterial}}",
|
||||||
|
"materialTime": "",
|
||||||
|
"materialName": "",
|
||||||
|
"QRcodeType": "",
|
||||||
|
"width": 282.9999999999999,
|
||||||
|
"height": 95.99999999999933,
|
||||||
|
"proportion": 60,
|
||||||
|
"x": 110.99999999999982,
|
||||||
|
"y": 438.7192999999991,
|
||||||
|
"opacity": 1,
|
||||||
|
"optionalColor": [
|
||||||
|
{
|
||||||
|
"color": "#000000",
|
||||||
|
"name": "Black",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MainColor",
|
||||||
|
"color": "#0082ca",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"zIndex": 7,
|
||||||
|
"svgPath": "",
|
||||||
|
"follow": {
|
||||||
|
"fill": "",
|
||||||
|
"ifShow": "",
|
||||||
|
"content": ""
|
||||||
|
},
|
||||||
|
"group": [],
|
||||||
|
"cameraStand": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`
|
@ -8,6 +8,8 @@ const (
|
|||||||
WEBSOCKET_UNAUTH = "WEBSOCKET_UNAUTH"
|
WEBSOCKET_UNAUTH = "WEBSOCKET_UNAUTH"
|
||||||
//ws连接成功
|
//ws连接成功
|
||||||
WEBSOCKET_CONNECT_SUCCESS = "WEBSOCKET_CONNECT_SUCCESS"
|
WEBSOCKET_CONNECT_SUCCESS = "WEBSOCKET_CONNECT_SUCCESS"
|
||||||
|
//渲染前数据组装
|
||||||
|
WEBSOCKET_RENDER_IMAGE_ASSEMBLE = "WEBSOCKET_RENDER_IMAGE_ASSEMBLE"
|
||||||
//图片渲染
|
//图片渲染
|
||||||
WEBSOCKET_RENDER_IMAGE = "WEBSOCKET_RENDER_IMAGE"
|
WEBSOCKET_RENDER_IMAGE = "WEBSOCKET_RENDER_IMAGE"
|
||||||
//数据格式错误
|
//数据格式错误
|
||||||
|
15
fs_package_docker_image.sh
Executable file
15
fs_package_docker_image.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
name=${1%%\\*}
|
||||||
|
#进入对应服务目录
|
||||||
|
cd server/$name
|
||||||
|
#构建二进制文件
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./bin/api-$name-srv ./$name.go
|
||||||
|
#删除之前旧的镜像
|
||||||
|
docker rmi -f api-$name-srv:latest
|
||||||
|
docker rmi -f registry.cn-hangzhou.aliyuncs.com/fusen-test/fusen_docker_hub:latest
|
||||||
|
#打包docker镜像
|
||||||
|
docker build -t api-$name-srv:latest .
|
||||||
|
#打tag(测试环境,正式把命名空间fusentest改成fusen)
|
||||||
|
docker tag api-$name-srv:latest registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest
|
||||||
|
#推送到阿里云镜像库(测试环境,正式把命名空间fusentest改成fusen)
|
||||||
|
docker push registry.cn-hangzhou.aliyuncs.com/fusen-test/$name:latest
|
@ -1,6 +1,7 @@
|
|||||||
Name: {{.serviceName}}
|
Name: {{.serviceName}}
|
||||||
Host: {{.host}}
|
Host: {{.host}}
|
||||||
Port: {{.port}}
|
Port: {{.port}}
|
||||||
|
Timeout: 15000 #服务超时时间(毫秒)
|
||||||
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
||||||
SourceRabbitMq: amqp://rabbit001:rabbit001129@110.41.19.98:5672
|
SourceRabbitMq: amqp://rabbit001:rabbit001129@110.41.19.98:5672
|
||||||
Auth:
|
Auth:
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package initalize
|
package initalize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fusenapi/constants"
|
"fusenapi/constants"
|
||||||
|
"fusenapi/utils/mq_consumer_factory"
|
||||||
"github.com/streadway/amqp"
|
"github.com/streadway/amqp"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
"log"
|
"log"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RabbitMqHandle struct {
|
type RabbitMqHandle struct {
|
||||||
@ -18,6 +21,12 @@ type queueItem struct {
|
|||||||
queue amqp.Queue
|
queue amqp.Queue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 队列列表
|
||||||
|
var mqQueueArr = []constants.RABBIT_MQ{
|
||||||
|
constants.RABBIT_MQ_ASSEMBLE_RENDER_DATA,
|
||||||
|
constants.RABBIT_MQ_RENDER_RESULT_DATA,
|
||||||
|
}
|
||||||
|
|
||||||
// 存储连接
|
// 存储连接
|
||||||
var mapMq = make(map[constants.RABBIT_MQ]queueItem)
|
var mapMq = make(map[constants.RABBIT_MQ]queueItem)
|
||||||
|
|
||||||
@ -35,7 +44,7 @@ func InitRabbitMq(url string, config *tls.Config) *RabbitMqHandle {
|
|||||||
log.Fatalf("Failed to open a channel: %v", err)
|
log.Fatalf("Failed to open a channel: %v", err)
|
||||||
}
|
}
|
||||||
//声明队列
|
//声明队列
|
||||||
for _, queueName := range constants.MQ_QUEUE_ARR {
|
for _, queueName := range mqQueueArr {
|
||||||
q, err := ch.QueueDeclare(
|
q, err := ch.QueueDeclare(
|
||||||
string(queueName), // 队列名
|
string(queueName), // 队列名
|
||||||
true, // 是否持久化
|
true, // 是否持久化
|
||||||
@ -75,11 +84,17 @@ func (h *RabbitMqHandle) SendMsg(queueName constants.RABBIT_MQ, message []byte)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 消费消息
|
// 消费消息
|
||||||
func (h *RabbitMqHandle) Consume(queueName constants.RABBIT_MQ, handleFunc func(data []byte) error) error {
|
func (h *RabbitMqHandle) Consume(ctx context.Context, queueName constants.RABBIT_MQ, handle mq_consumer_factory.MqHandle) {
|
||||||
object, ok := mapMq[queueName]
|
object, ok := mapMq[queueName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("unknown queue")
|
panic("unknown queue")
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
panic("err ctx deadline")
|
||||||
|
}
|
||||||
|
}()
|
||||||
msgs, err := object.ch.Consume(
|
msgs, err := object.ch.Consume(
|
||||||
object.queue.Name, // 队列名
|
object.queue.Name, // 队列名
|
||||||
object.queue.Name, // 消费者名,如果为空,则是随机生成一个
|
object.queue.Name, // 消费者名,如果为空,则是随机生成一个
|
||||||
@ -94,18 +109,21 @@ func (h *RabbitMqHandle) Consume(queueName constants.RABBIT_MQ, handleFunc func(
|
|||||||
}
|
}
|
||||||
//允许20的并发
|
//允许20的并发
|
||||||
limit := make(chan struct{}, 20)
|
limit := make(chan struct{}, 20)
|
||||||
|
wait := sync.WaitGroup{}
|
||||||
defer close(limit)
|
defer close(limit)
|
||||||
// 消费消息
|
// 消费消息
|
||||||
for msg := range msgs {
|
for msg := range msgs {
|
||||||
limit <- struct{}{}
|
limit <- struct{}{}
|
||||||
|
wait.Add(1)
|
||||||
go func(m amqp.Delivery) {
|
go func(m amqp.Delivery) {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
logx.Error(err)
|
logx.Error(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
<-limit
|
<-limit
|
||||||
|
wait.Done()
|
||||||
}()
|
}()
|
||||||
if err = handleFunc(m.Body); err != nil {
|
if err = handle.Run(ctx, m.Body); err != nil {
|
||||||
logx.Error("failed to deal with MQ message:", string(m.Body))
|
logx.Error("failed to deal with MQ message:", string(m.Body))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -116,5 +134,5 @@ func (h *RabbitMqHandle) Consume(queueName constants.RABBIT_MQ, handleFunc func(
|
|||||||
}
|
}
|
||||||
}(msg)
|
}(msg)
|
||||||
}
|
}
|
||||||
return nil
|
wait.Wait()
|
||||||
}
|
}
|
||||||
|
@ -92,5 +92,5 @@ func (c *FsCartModel) DeleteCartsByIds(ctx context.Context, ids []int64) ( err e
|
|||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return c.db.WithContext(ctx).Model(&FsCart{}).Where("`id` in (?)", ids).Delete(&FsCart{}).Error
|
return c.db.Table(c.name).WithContext(ctx).Model(&FsCart{}).Where("`id` in (?)", ids).Update("status", 0).Error
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
package gmodel
|
package gmodel
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
// TODO: 使用model的属性做你想做的
|
// TODO: 使用model的属性做你想做的
|
||||||
|
|
||||||
|
func (r *FsCloudRenderLogModel) Create(ctx context.Context, data *FsCloudRenderLog) error {
|
||||||
|
return r.db.WithContext(ctx).Model(&FsCloudRenderLog{}).Create(data).Error
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"fusenapi/utils/handler"
|
"fusenapi/utils/handlers"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -60,7 +60,7 @@ func (o *FsOrderModel) FindPageListByPage(ctx context.Context, rowBuilder *gorm.
|
|||||||
var resp []*FsOrderRel
|
var resp []*FsOrderRel
|
||||||
// 过滤
|
// 过滤
|
||||||
if filterMap != nil {
|
if filterMap != nil {
|
||||||
rowBuilder = rowBuilder.Scopes(handler.FilterData(filterMap))
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 排序
|
// 排序
|
||||||
@ -70,11 +70,11 @@ func (o *FsOrderModel) FindPageListByPage(ctx context.Context, rowBuilder *gorm.
|
|||||||
for i := 0; i < s.NumField(); i++ {
|
for i := 0; i < s.NumField(); i++ {
|
||||||
fieldsMap[s.Field(i).Tag.Get("json")] = struct{}{}
|
fieldsMap[s.Field(i).Tag.Get("json")] = struct{}{}
|
||||||
}
|
}
|
||||||
rowBuilder = rowBuilder.Scopes(handler.OrderCheck(orderBy, fieldsMap))
|
rowBuilder = rowBuilder.Scopes(handlers.OrderCheck(orderBy, fieldsMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页
|
// 分页
|
||||||
rowBuilder = rowBuilder.Scopes(handler.Paginate(page, pageSize))
|
rowBuilder = rowBuilder.Scopes(handlers.Paginate(page, pageSize))
|
||||||
|
|
||||||
// 结果
|
// 结果
|
||||||
result := rowBuilder.Debug().WithContext(ctx).Find(&resp)
|
result := rowBuilder.Debug().WithContext(ctx).Find(&resp)
|
||||||
@ -125,7 +125,7 @@ func (m *FsOrderModel) FindCount(ctx context.Context, countBuilder *gorm.DB, fil
|
|||||||
|
|
||||||
// 过滤
|
// 过滤
|
||||||
if filterMap != nil {
|
if filterMap != nil {
|
||||||
countBuilder = countBuilder.Scopes(handler.FilterData(filterMap))
|
countBuilder = countBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := countBuilder.WithContext(ctx).Limit(1).Count(&count)
|
result := countBuilder.WithContext(ctx).Limit(1).Count(&count)
|
||||||
@ -140,7 +140,7 @@ func (m *FsOrderModel) FindOneByQuery(ctx context.Context, rowBuilder *gorm.DB,
|
|||||||
var resp FsOrderRel
|
var resp FsOrderRel
|
||||||
|
|
||||||
if filterMap != nil {
|
if filterMap != nil {
|
||||||
rowBuilder = rowBuilder.Scopes(handler.FilterData(filterMap))
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp)
|
result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp)
|
||||||
|
@ -1,2 +1,15 @@
|
|||||||
package gmodel
|
package gmodel
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
// TODO: 使用model的属性做你想做的
|
// TODO: 使用model的属性做你想做的
|
||||||
|
|
||||||
|
func (p *FsPayEventModel) CreateOrUpdate(ctx context.Context, req *FsPayEvent) (resp *FsPayEvent, err error) {
|
||||||
|
rowBuilder := p.db.Table(p.name).WithContext(ctx)
|
||||||
|
if req.Id > 0 {
|
||||||
|
err = rowBuilder.Save(req).Error
|
||||||
|
} else {
|
||||||
|
err = rowBuilder.Create(req).Error
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
@ -2,7 +2,8 @@ package gmodel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fusenapi/utils/handler"
|
"fusenapi/utils/handlers"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -54,7 +55,7 @@ func (m *FsPayModel) FindCount(ctx context.Context, countBuilder *gorm.DB, filte
|
|||||||
|
|
||||||
// 过滤
|
// 过滤
|
||||||
if filterMap != nil {
|
if filterMap != nil {
|
||||||
countBuilder = countBuilder.Scopes(handler.FilterData(filterMap))
|
countBuilder = countBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := countBuilder.WithContext(ctx).Limit(1).Count(&count)
|
result := countBuilder.WithContext(ctx).Limit(1).Count(&count)
|
||||||
@ -69,7 +70,7 @@ func (m *FsPayModel) FindOneByQuery(ctx context.Context, rowBuilder *gorm.DB, fi
|
|||||||
var resp FsPay
|
var resp FsPay
|
||||||
|
|
||||||
if filterMap != nil {
|
if filterMap != nil {
|
||||||
rowBuilder = rowBuilder.Scopes(handler.FilterData(filterMap))
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp)
|
result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp)
|
||||||
@ -80,6 +81,31 @@ func (m *FsPayModel) FindOneByQuery(ctx context.Context, rowBuilder *gorm.DB, fi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *FsPayModel) FindAll(ctx context.Context, rowBuilder *gorm.DB, filterMap map[string]string, orderBy string) ([]*FsPay, error) {
|
||||||
|
var resp []*FsPay
|
||||||
|
// 过滤
|
||||||
|
if filterMap != nil {
|
||||||
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
if orderBy != "" {
|
||||||
|
var fieldsMap = make(map[string]struct{})
|
||||||
|
s := reflect.TypeOf(&FsOrder{}).Elem() //通过反射获取type定义
|
||||||
|
for i := 0; i < s.NumField(); i++ {
|
||||||
|
fieldsMap[s.Field(i).Tag.Get("json")] = struct{}{}
|
||||||
|
}
|
||||||
|
rowBuilder = rowBuilder.Scopes(handlers.OrderCheck(orderBy, fieldsMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := rowBuilder.WithContext(ctx).Find(&resp)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
} else {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 事务
|
// 事务
|
||||||
func (m *FsPayModel) Trans(ctx context.Context, fn func(ctx context.Context, connGorm *gorm.DB) error) error {
|
func (m *FsPayModel) Trans(ctx context.Context, fn func(ctx context.Context, connGorm *gorm.DB) error) error {
|
||||||
tx := m.db.Table(m.name).WithContext(ctx).Begin()
|
tx := m.db.Table(m.name).WithContext(ctx).Begin()
|
||||||
|
@ -93,3 +93,11 @@ func (d *FsProductModel3dModel) GetGroupPartListByProductIds(ctx context.Context
|
|||||||
Group("product_id").Find(&resp).Error
|
Group("product_id").Find(&resp).Error
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
func (d *FsProductModel3dModel) FindOneJoinSize(ctx context.Context, productId int64) (resp FsProductModel3d, err error) {
|
||||||
|
err = d.db.WithContext(ctx).Table(d.name+"as m").Joins("left join fs_product_size as s on m.size_id = s.id").
|
||||||
|
Select("m.*").
|
||||||
|
Where("m.product_id = ?", productId).
|
||||||
|
Where("(s.status= ? and m.tag = ?)", 1, 1).
|
||||||
|
Order("s.sort ASC").Take(&resp).Error
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
@ -22,6 +22,8 @@ type FsProductTemplateV2 struct {
|
|||||||
Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间
|
Ctime *int64 `gorm:"default:0;" json:"ctime"` // 添加时间
|
||||||
Tag *string `gorm:"default:'';" json:"tag"` // 标签(用户自填)
|
Tag *string `gorm:"default:'';" json:"tag"` // 标签(用户自填)
|
||||||
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除
|
IsDel *int64 `gorm:"default:0;" json:"is_del"` // 是否删除 1删除
|
||||||
|
GroupOptions *string `gorm:"default:'';" json:"group_options"` // 颜色分组
|
||||||
|
Version *int64 `gorm:"default:0;" json:"version"` //
|
||||||
}
|
}
|
||||||
type FsProductTemplateV2Model struct {
|
type FsProductTemplateV2Model struct {
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
|
@ -106,3 +106,16 @@ func (t *FsProductTemplateV2Model) GetProductTemplateListByParams(ctx context.Co
|
|||||||
err = db.Find(&resp).Error
|
err = db.Find(&resp).Error
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取第一个尺寸下的模板
|
||||||
|
func (t *FsProductTemplateV2Model) FindOneByProductIdTagIdWithSizeTable(ctx context.Context, productId int64, tagId 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").
|
||||||
|
Select("t.*").
|
||||||
|
Where("t.product_id = ? and t.tag = ? ", productId, tagId).
|
||||||
|
Where("t.status = ? and t.is_del = ?", 1, 0).
|
||||||
|
Where("s.status = ?", 1).
|
||||||
|
Order("s.sort ASC").
|
||||||
|
Take(&resp).Error
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package gmodel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fusenapi/utils/handlers"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@ -24,3 +25,43 @@ func (m *FsRefundReasonModel) Update(ctx context.Context, obj *FsRefundReason) e
|
|||||||
func (m *FsRefundReasonModel) UpdateByRefundReasonId(ctx context.Context, obj *FsRefundReason) error {
|
func (m *FsRefundReasonModel) UpdateByRefundReasonId(ctx context.Context, obj *FsRefundReason) error {
|
||||||
return m.db.WithContext(ctx).Model(obj).Where("`refund_reason_id` = ?", obj.RefundReasonId).Updates(obj).Error
|
return m.db.WithContext(ctx).Model(obj).Where("`refund_reason_id` = ?", obj.RefundReasonId).Updates(obj).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *FsRefundReasonModel) CreateOrUpdate(ctx context.Context, req *FsRefundReason) (resp *FsRefundReason, err error) {
|
||||||
|
rowBuilder := m.db.Table(m.name).WithContext(ctx)
|
||||||
|
if req.Id > 0 {
|
||||||
|
err = rowBuilder.Save(req).Error
|
||||||
|
} else {
|
||||||
|
err = rowBuilder.Create(req).Error
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsRefundReasonModel) FindOneByQuery(ctx context.Context, rowBuilder *gorm.DB, filterMap map[string]string) (*FsRefundReason, error) {
|
||||||
|
var resp FsRefundReason
|
||||||
|
|
||||||
|
if filterMap != nil {
|
||||||
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
} else {
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsRefundReasonModel) RowSelectBuilder(selectData []string) *gorm.DB {
|
||||||
|
var rowBuilder = m.db.Table(m.name)
|
||||||
|
|
||||||
|
if selectData != nil {
|
||||||
|
rowBuilder = rowBuilder.Select(selectData)
|
||||||
|
} else {
|
||||||
|
rowBuilder = rowBuilder.Select("*")
|
||||||
|
}
|
||||||
|
return rowBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsRefundReasonModel) TableName() string {
|
||||||
|
return m.name
|
||||||
|
}
|
||||||
|
@ -16,6 +16,8 @@ type FsResource struct {
|
|||||||
UploadedAt *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"uploaded_at"` // 上传时间
|
UploadedAt *time.Time `gorm:"index;default:'0000-00-00 00:00:00';" json:"uploaded_at"` // 上传时间
|
||||||
Metadata *string `gorm:"default:'';" json:"metadata"` // 元数据,json格式,存储图像分率
|
Metadata *string `gorm:"default:'';" json:"metadata"` // 元数据,json格式,存储图像分率
|
||||||
MetaKey1 *string `gorm:"index;default:'';" json:"meta_key1"` // 需要关键信息查询的自定义属性1,可以动态增加
|
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"` // 存储桶名
|
||||||
}
|
}
|
||||||
type FsResourceModel struct {
|
type FsResourceModel struct {
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
|
@ -1 +1,84 @@
|
|||||||
package gmodel
|
package gmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fusenapi/utils/handlers"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: 使用model的属性做你想做的
|
||||||
|
|
||||||
|
func (p *FsResourceModel) FindOneById(ctx context.Context, resourceId string) (*FsResource, error) {
|
||||||
|
var resp FsResource
|
||||||
|
result := p.db.Table(p.name).WithContext(ctx).Where("resource_id =?", resourceId).Take(&resp)
|
||||||
|
if result.Error != nil {
|
||||||
|
// 检查 ErrRecordNotFound 错误
|
||||||
|
if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *FsResourceModel) Create(ctx context.Context, req *FsResource) (resp *FsResource, err error) {
|
||||||
|
err = p.db.Table(p.name).WithContext(ctx).Create(req).Error
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *FsResourceModel) Update(ctx context.Context, req *FsResource) (resp *FsResource, err error) {
|
||||||
|
err = p.db.Table(p.name).WithContext(ctx).Where("resource_id =?", req.ResourceId).Save(req).Error
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsResourceModel) FindOneByQuery(ctx context.Context, rowBuilder *gorm.DB, filterMap map[string]string) (*FsResource, error) {
|
||||||
|
var resp FsResource
|
||||||
|
|
||||||
|
if filterMap != nil {
|
||||||
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := rowBuilder.WithContext(ctx).Limit(1).Find(&resp)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
} else {
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsResourceModel) RowSelectBuilder(selectData []string) *gorm.DB {
|
||||||
|
var rowBuilder = m.db.Table(m.name)
|
||||||
|
|
||||||
|
if selectData != nil {
|
||||||
|
rowBuilder = rowBuilder.Select(selectData)
|
||||||
|
} else {
|
||||||
|
rowBuilder = rowBuilder.Select("*")
|
||||||
|
}
|
||||||
|
return rowBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// 事务
|
||||||
|
func (m *FsResourceModel) Trans(ctx context.Context, fn func(ctx context.Context, connGorm *gorm.DB) error) error {
|
||||||
|
tx := m.db.Table(m.name).WithContext(ctx).Begin()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := tx.Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fn(ctx, tx); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Commit().Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsResourceModel) TableName() string {
|
||||||
|
return m.name
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ type FsTags struct {
|
|||||||
Description *string `gorm:"default:'';" json:"description"` // 介绍 Seo
|
Description *string `gorm:"default:'';" json:"description"` // 介绍 Seo
|
||||||
RecommendProduct *string `gorm:"default:'';" json:"recommend_product"` //
|
RecommendProduct *string `gorm:"default:'';" json:"recommend_product"` //
|
||||||
RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` //
|
RecommendProductSort *string `gorm:"default:'';" json:"recommend_product_sort"` //
|
||||||
|
Category *int64 `gorm:"default:1;" json:"category"` // 分类:1前台用的 2后台用的
|
||||||
}
|
}
|
||||||
type FsTagsModel struct {
|
type FsTagsModel struct {
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
|
@ -36,6 +36,7 @@ type GetAllTagByParamsReq struct {
|
|||||||
OrderBy string
|
OrderBy string
|
||||||
LevelPrefixLeftLike string //右模糊
|
LevelPrefixLeftLike string //右模糊
|
||||||
WithChild bool //是否包含子层级
|
WithChild bool //是否包含子层级
|
||||||
|
Category int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *FsTagsModel) GetAllTagByParams(ctx context.Context, req GetAllTagByParamsReq) (resp []FsTags, err error) {
|
func (t *FsTagsModel) GetAllTagByParams(ctx context.Context, req GetAllTagByParamsReq) (resp []FsTags, err error) {
|
||||||
@ -46,6 +47,9 @@ func (t *FsTagsModel) GetAllTagByParams(ctx context.Context, req GetAllTagByPara
|
|||||||
if req.Status != nil {
|
if req.Status != nil {
|
||||||
db = db.Where("`status` = ?", *req.Status)
|
db = db.Where("`status` = ?", *req.Status)
|
||||||
}
|
}
|
||||||
|
if req.Category != 0 {
|
||||||
|
db = db.Where("`category` = ?", req.Category)
|
||||||
|
}
|
||||||
if req.LevelPrefixLeftLike != "" {
|
if req.LevelPrefixLeftLike != "" {
|
||||||
//查询子集
|
//查询子集
|
||||||
if req.WithChild {
|
if req.WithChild {
|
||||||
|
25
model/gmodel/fs_user_material_gen.go
Normal file
25
model/gmodel/fs_user_material_gen.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package gmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// fs_user_material 用户素材表
|
||||||
|
type FsUserMaterial struct {
|
||||||
|
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` // 用户 ID
|
||||||
|
Module *string `gorm:"default:'';" json:"module"` // 所属模块:logo
|
||||||
|
UserId *int64 `gorm:"index;default:0;" json:"user_id"` // 用户 ID
|
||||||
|
GuestId *int64 `gorm:"index;default:0;" json:"guest_id"` // 游客 ID
|
||||||
|
ResourceId *string `gorm:"default:'';" json:"resource_id"` // 资源ID
|
||||||
|
ResourceUrl *string `gorm:"default:'';" json:"resource_url"` // 资源 URL
|
||||||
|
Metadata *string `gorm:"default:'';" json:"metadata"` // 元数据,json格式,存储图像分率
|
||||||
|
CreateAt *int64 `gorm:"default:0;" json:"create_at"` // 上传时间
|
||||||
|
}
|
||||||
|
type FsUserMaterialModel struct {
|
||||||
|
db *gorm.DB
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFsUserMaterialModel(db *gorm.DB) *FsUserMaterialModel {
|
||||||
|
return &FsUserMaterialModel{db: db, name: "fs_user_material"}
|
||||||
|
}
|
72
model/gmodel/fs_user_material_logic.go
Normal file
72
model/gmodel/fs_user_material_logic.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package gmodel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fusenapi/utils/handlers"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: 使用model的属性做你想做的
|
||||||
|
|
||||||
|
func (p *FsUserMaterialModel) CreateOrUpdate(ctx context.Context, req *FsUserMaterial) (resp *FsUserMaterial, err error) {
|
||||||
|
rowBuilder := p.db.Table(p.name).WithContext(ctx)
|
||||||
|
if req.Id > 0 {
|
||||||
|
err = rowBuilder.Save(req).Error
|
||||||
|
} else {
|
||||||
|
err = rowBuilder.Create(req).Error
|
||||||
|
}
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsUserMaterialModel) FindAll(ctx context.Context, rowBuilder *gorm.DB, filterMap map[string]string, orderBy string) ([]*FsUserMaterial, error) {
|
||||||
|
var resp []*FsUserMaterial
|
||||||
|
// 过滤
|
||||||
|
if filterMap != nil {
|
||||||
|
rowBuilder = rowBuilder.Scopes(handlers.FilterData(filterMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
if orderBy != "" {
|
||||||
|
var fieldsMap = make(map[string]struct{})
|
||||||
|
s := reflect.TypeOf(&FsUserMaterial{}).Elem() //通过反射获取type定义
|
||||||
|
for i := 0; i < s.NumField(); i++ {
|
||||||
|
fieldsMap[s.Field(i).Tag.Get("json")] = struct{}{}
|
||||||
|
}
|
||||||
|
rowBuilder = rowBuilder.Scopes(handlers.OrderCheck(orderBy, fieldsMap))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := rowBuilder.WithContext(ctx).Find(&resp)
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
} else {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *FsUserMaterialModel) RowSelectBuilder(selectData []string) *gorm.DB {
|
||||||
|
var rowBuilder = m.db.Table(m.name)
|
||||||
|
|
||||||
|
if selectData != nil {
|
||||||
|
rowBuilder = rowBuilder.Select(selectData)
|
||||||
|
} else {
|
||||||
|
rowBuilder = rowBuilder.Select("*")
|
||||||
|
}
|
||||||
|
return rowBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最新记录
|
||||||
|
func (m *FsUserMaterialModel) FindLatestOne(ctx context.Context, userId int64, guestId int64) (resp FsUserMaterial, err error) {
|
||||||
|
if userId == 0 && guestId == 0 {
|
||||||
|
return FsUserMaterial{}, nil
|
||||||
|
}
|
||||||
|
db := m.db.WithContext(ctx).Model(&FsUserMaterial{}).Order("id DESC")
|
||||||
|
if userId != 0 {
|
||||||
|
db = db.Where("`user_id` = ?", userId)
|
||||||
|
} else {
|
||||||
|
db = db.Where("`guest_id` = ?", guestId)
|
||||||
|
}
|
||||||
|
err = db.Take(&resp).Error
|
||||||
|
return resp, err
|
||||||
|
}
|
@ -89,6 +89,7 @@ type AllModelsGen struct {
|
|||||||
FsTrade *FsTradeModel // fs_trade
|
FsTrade *FsTradeModel // fs_trade
|
||||||
FsUser *FsUserModel // fs_user 用户表
|
FsUser *FsUserModel // fs_user 用户表
|
||||||
FsUserDesign *FsUserDesignModel // fs_user_design 废弃表
|
FsUserDesign *FsUserDesignModel // fs_user_design 废弃表
|
||||||
|
FsUserMaterial *FsUserMaterialModel // fs_user_material 用户素材表
|
||||||
FsUserStock *FsUserStockModel // fs_user_stock 用户云仓库存
|
FsUserStock *FsUserStockModel // fs_user_stock 用户云仓库存
|
||||||
FsWebSet *FsWebSetModel // fs_web_set 网站配置表
|
FsWebSet *FsWebSetModel // fs_web_set 网站配置表
|
||||||
|
|
||||||
@ -181,6 +182,7 @@ func NewAllModels(gdb *gorm.DB) *AllModelsGen {
|
|||||||
FsTrade: NewFsTradeModel(gdb),
|
FsTrade: NewFsTradeModel(gdb),
|
||||||
FsUser: NewFsUserModel(gdb),
|
FsUser: NewFsUserModel(gdb),
|
||||||
FsUserDesign: NewFsUserDesignModel(gdb),
|
FsUserDesign: NewFsUserDesignModel(gdb),
|
||||||
|
FsUserMaterial: NewFsUserMaterialModel(gdb),
|
||||||
FsUserStock: NewFsUserStockModel(gdb),
|
FsUserStock: NewFsUserStockModel(gdb),
|
||||||
FsWebSet: NewFsWebSetModel(gdb),
|
FsWebSet: NewFsWebSetModel(gdb),
|
||||||
}
|
}
|
||||||
|
6
server/auth/Dockerfile
Executable file
6
server/auth/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-assistant-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-assistant-srv"]
|
6
server/backend/Dockerfile
Executable file
6
server/backend/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-backend-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-backend-srv"]
|
6
server/canteen/Dockerfile
Executable file
6
server/canteen/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-canteen-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-canteen-srv"]
|
6
server/data-transfer/Dockerfile
Executable file
6
server/data-transfer/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-data-transfer-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-data-transfer-srv"]
|
6
server/home-user-auth/Dockerfile
Executable file
6
server/home-user-auth/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-home-user-auth-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-home-user-auth-srv"]
|
@ -12,3 +12,10 @@ Auth:
|
|||||||
|
|
||||||
Stripe:
|
Stripe:
|
||||||
SK: "sk_test_51IisojHygnIJZeghPVSBhkwySfcyDV4SoAduIxu3J7bvSJ9cZMD96LY1LO6SpdbYquLJX5oKvgEBB67KT9pecfCy00iEC4pp9y"
|
SK: "sk_test_51IisojHygnIJZeghPVSBhkwySfcyDV4SoAduIxu3J7bvSJ9cZMD96LY1LO6SpdbYquLJX5oKvgEBB67KT9pecfCy00iEC4pp9y"
|
||||||
|
|
||||||
|
PayConfig:
|
||||||
|
Stripe:
|
||||||
|
Key: "sk_test_51IisojHygnIJZeghPVSBhkwySfcyDV4SoAduIxu3J7bvSJ9cZMD96LY1LO6SpdbYquLJX5oKvgEBB67KT9pecfCy00iEC4pp9y"
|
||||||
|
EndpointSecret: "whsec_f5f9a121d43af3789db7459352f08cf523eb9e0fbf3381f91ba6c97c324c174d"
|
||||||
|
SuccessURL: "http://www.baidu.com"
|
||||||
|
CancelURL: "http://www.baidu.com"
|
||||||
|
@ -17,4 +17,13 @@ type Config struct {
|
|||||||
Stripe struct {
|
Stripe struct {
|
||||||
SK string
|
SK string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PayConfig struct {
|
||||||
|
Stripe struct {
|
||||||
|
EndpointSecret string
|
||||||
|
Key string
|
||||||
|
CancelURL string
|
||||||
|
SuccessURL string
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
Path: "/api/user/order-cancel",
|
Path: "/api/user/order-cancel",
|
||||||
Handler: UserOrderCancelHandler(serverCtx),
|
Handler: UserOrderCancelHandler(serverCtx),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/api/user/logo-list",
|
||||||
|
Handler: UserLogoListHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/api/user/one-more-order",
|
||||||
|
Handler: UserAgainOrderHandler(serverCtx),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,27 +6,27 @@ import (
|
|||||||
|
|
||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
|
|
||||||
"fusenapi/server/websocket/internal/logic"
|
"fusenapi/server/home-user-auth/internal/logic"
|
||||||
"fusenapi/server/websocket/internal/svc"
|
"fusenapi/server/home-user-auth/internal/svc"
|
||||||
"fusenapi/server/websocket/internal/types"
|
"fusenapi/server/home-user-auth/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ThirdPartyLoginNotifyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func UserAgainOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var req types.ThirdPartyLoginNotifyReq
|
var req types.UserAgainOrderReq
|
||||||
userinfo, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
userinfo, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个业务逻辑层实例
|
// 创建一个业务逻辑层实例
|
||||||
l := logic.NewThirdPartyLoginNotifyLogic(r.Context(), svcCtx)
|
l := logic.NewUserAgainOrderLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
rl := reflect.ValueOf(l)
|
rl := reflect.ValueOf(l)
|
||||||
basic.BeforeLogic(w, r, rl)
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
resp := l.ThirdPartyLoginNotify(&req, userinfo)
|
resp := l.UserAgainOrder(&req, userinfo)
|
||||||
|
|
||||||
if !basic.AfterLogic(w, r, rl, resp) {
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
basic.NormalAfterLogic(w, r, resp)
|
basic.NormalAfterLogic(w, r, resp)
|
@ -0,0 +1,35 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
|
||||||
|
"fusenapi/server/home-user-auth/internal/logic"
|
||||||
|
"fusenapi/server/home-user-auth/internal/svc"
|
||||||
|
"fusenapi/server/home-user-auth/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UserLogoListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.UserLogoListReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewUserLogoListLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.UserLogoList(&req, userinfo)
|
||||||
|
|
||||||
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
|
basic.NormalAfterLogic(w, r, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
server/home-user-auth/internal/logic/useragainorderlogic.go
Normal file
144
server/home-user-auth/internal/logic/useragainorderlogic.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/home-user-auth/internal/svc"
|
||||||
|
"fusenapi/server/home-user-auth/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserAgainOrderLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserAgainOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserAgainOrderLogic {
|
||||||
|
return &UserAgainOrderLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UserAgainOrderLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UserAgainOrderLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UserAgainOrderLogic) UserAgainOrder(req *types.UserAgainOrderReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
if userinfo == nil || userinfo.UserId == 0 {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询订单数据
|
||||||
|
orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
|
||||||
|
orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn)
|
||||||
|
fsOrderDetailModel := gmodel.NewFsOrderDetailModel(l.svcCtx.MysqlConn)
|
||||||
|
fsProductDesignModel := gmodel.NewFsProductDesignModel(l.svcCtx.MysqlConn)
|
||||||
|
|
||||||
|
rsbOrder := orderModel.RowSelectBuilder(nil)
|
||||||
|
rsbOrder = rsbOrder.Where("sn =?", req.Sn).Preload("FsOrderDetails")
|
||||||
|
rsbOrder = rsbOrder.Preload("FsOrderDetails", func(dbPreload *gorm.DB) *gorm.DB {
|
||||||
|
return dbPreload.Table(fsOrderDetailModel.TableName()).Preload("FsOrderDetailTemplateInfo", func(dbPreload *gorm.DB) *gorm.DB {
|
||||||
|
return dbPreload.Table(orderDetailTemplateModel.TableName()).Preload("FsProductDesignInfo", func(dbPreload *gorm.DB) *gorm.DB {
|
||||||
|
return dbPreload.Table(fsProductDesignModel.TableName())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
fsOrderRelInfo, err := orderModel.FindOneByQuery(l.ctx, rsbOrder, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order not found")
|
||||||
|
}
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order info")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fsOrderRelInfo.FsOrderDetails) > 0 {
|
||||||
|
for _, fsOrderDetail := range fsOrderRelInfo.FsOrderDetails {
|
||||||
|
var isCheck int64 = 1
|
||||||
|
productDesignInfo := fsOrderDetail.FsOrderDetailTemplateInfo.FsProductDesignInfo
|
||||||
|
if productDesignInfo.Id != 0 {
|
||||||
|
|
||||||
|
// 查找是否有此材质、产品、大小id的阶梯价格
|
||||||
|
productPriceModel := gmodel.NewFsProductPriceModel(l.svcCtx.MysqlConn)
|
||||||
|
priceStatus := int64(1)
|
||||||
|
priceReq := gmodel.FindOneProductPriceByParamsReq{
|
||||||
|
ProductId: productDesignInfo.ProductId,
|
||||||
|
MaterialId: productDesignInfo.MaterialId,
|
||||||
|
SizeId: productDesignInfo.SizeId,
|
||||||
|
Status: &priceStatus,
|
||||||
|
}
|
||||||
|
productPriceInfo, err := productPriceModel.FindOneProductPriceByParams(l.ctx, priceReq)
|
||||||
|
if err == nil && productPriceInfo.Id != 0 && *productPriceInfo.EachBoxNum > 0 {
|
||||||
|
|
||||||
|
// 买的数量和每箱数量取余为0 且 份数大于等于最小购买数量才算满足条件
|
||||||
|
if *fsOrderDetail.BuyNum%*productPriceInfo.EachBoxNum == 0 && int64(float64(*fsOrderDetail.BuyNum)/float64(*productPriceInfo.EachBoxNum)) >= *productPriceInfo.MinBuyNum {
|
||||||
|
|
||||||
|
// 查询购物车
|
||||||
|
cartModel := gmodel.NewFsCartModel(l.svcCtx.MysqlConn)
|
||||||
|
cartStatus := int64(1)
|
||||||
|
cartReq := gmodel.FindOneCartByParamsReq{
|
||||||
|
UserId: &userinfo.UserId,
|
||||||
|
ProductId: productDesignInfo.ProductId,
|
||||||
|
TemplateId: productDesignInfo.TemplateId,
|
||||||
|
PriceId: &productPriceInfo.Id,
|
||||||
|
DesignId: &productDesignInfo.Id,
|
||||||
|
MaterialId: productDesignInfo.MaterialId,
|
||||||
|
Status: &cartStatus,
|
||||||
|
}
|
||||||
|
cartInfo, err := cartModel.FindOneCartByParams(l.ctx, cartReq)
|
||||||
|
if err == nil && (err != nil && errors.Is(err, gorm.ErrRecordNotFound)) {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
nowTime := time.Now()
|
||||||
|
data := gmodel.FsCart{
|
||||||
|
UserId: &userinfo.UserId,
|
||||||
|
ProductId: productPriceInfo.ProductId,
|
||||||
|
TemplateId: productDesignInfo.TemplateId,
|
||||||
|
PriceId: &productPriceInfo.Id,
|
||||||
|
MaterialId: productDesignInfo.MaterialId,
|
||||||
|
SizeId: productDesignInfo.SizeId,
|
||||||
|
BuyNum: fsOrderDetail.BuyNum,
|
||||||
|
Cover: productDesignInfo.Cover,
|
||||||
|
DesignId: &productDesignInfo.Id,
|
||||||
|
Ctime: &now,
|
||||||
|
Status: &cartStatus,
|
||||||
|
OptionalId: productDesignInfo.OptionalId,
|
||||||
|
IsCheck: &isCheck,
|
||||||
|
TsTime: &nowTime,
|
||||||
|
}
|
||||||
|
if cartInfo == nil {
|
||||||
|
err = cartModel.Create(l.ctx, data)
|
||||||
|
} else {
|
||||||
|
err = cartModel.Update(l.ctx, cartInfo.Id, data)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to add to cart")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp.SetStatus(basic.CodeOK)
|
||||||
|
}
|
71
server/home-user-auth/internal/logic/userlogolistlogic.go
Normal file
71
server/home-user-auth/internal/logic/userlogolistlogic.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/home-user-auth/internal/svc"
|
||||||
|
"fusenapi/server/home-user-auth/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserLogoListLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUserLogoListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLogoListLogic {
|
||||||
|
return &UserLogoListLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UserLogoListLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UserLogoListLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UserLogoListLogic) UserLogoList(req *types.UserLogoListReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
// 定义用户ID
|
||||||
|
var userId int64
|
||||||
|
var guestId int64
|
||||||
|
|
||||||
|
// 检查用户是否是游客
|
||||||
|
if userinfo.IsGuest() {
|
||||||
|
// 如果是,使用游客ID和游客键名格式
|
||||||
|
guestId = userinfo.GuestId
|
||||||
|
} else {
|
||||||
|
// 否则,使用用户ID和用户键名格式
|
||||||
|
userId = userinfo.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
userMaterialModel := gmodel.NewFsUserMaterialModel(l.svcCtx.MysqlConn)
|
||||||
|
userMaterialRSB := userMaterialModel.RowSelectBuilder(nil).
|
||||||
|
Where("module = ?", "logo").Where("user_id = ?", userId).Where("guest_id = ?", guestId).Order("id desc")
|
||||||
|
list, err := userMaterialModel.FindAll(l.ctx, userMaterialRSB, nil, "")
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "data not found")
|
||||||
|
}
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get data list")
|
||||||
|
}
|
||||||
|
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
|
||||||
|
"list": list,
|
||||||
|
})
|
||||||
|
}
|
@ -6,6 +6,8 @@ import (
|
|||||||
"fusenapi/model/gmodel"
|
"fusenapi/model/gmodel"
|
||||||
"fusenapi/utils/auth"
|
"fusenapi/utils/auth"
|
||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
|
"fusenapi/utils/handlers"
|
||||||
|
"time"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
@ -50,11 +52,76 @@ func (l *UserOrderCancelLogic) UserOrderCancel(req *types.UserOrderCancelReq, us
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断订单状态
|
// 判断订单状态
|
||||||
if *orderInfo.Status == int64(constants.STATUS_NEW_NOT_PAY) {
|
var notCancelStatusMap = make(map[int64]struct{}, 3)
|
||||||
|
notCancelStatusMap[int64(constants.STATUS_NEW_NOT_PAY)] = struct{}{}
|
||||||
} else {
|
notCancelStatusMap[int64(constants.STATUS_NEW_PART_PAY)] = struct{}{}
|
||||||
|
notCancelStatusMap[int64(constants.STATUS_NEW_PAY_COMPLETED)] = struct{}{}
|
||||||
|
_, ok := notCancelStatusMap[int64(*orderInfo.Status)]
|
||||||
|
if !ok {
|
||||||
return resp.SetStatusWithMessage(basic.CodeOrderNotCancelledErr, "the order status not cancle")
|
return resp.SetStatusWithMessage(basic.CodeOrderNotCancelledErr, "the order status not cancle")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cancelTime int64 = time.Now().Unix() - (*orderInfo.Ctime + int64(constants.CANCLE_ORDER_EXPIRE))
|
||||||
|
// 第一次支付成功后48小时后不能进行取消操作
|
||||||
|
if *orderInfo.IsPayCompleted == 1 && cancelTime > 0 {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeOrderNotCancelledErr, "The current order cannot be cancelled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改订单--取消状态和取消原因
|
||||||
|
*orderInfo.Status = int64(constants.STATUS_NEW_CANCEL)
|
||||||
|
*orderInfo.IsCancel = 1
|
||||||
|
orderInfo.RefundReasonId = &req.RefundReasonId
|
||||||
|
orderInfo.RefundReason = &req.RefundReason
|
||||||
|
|
||||||
|
var nowTime = time.Now().Unix()
|
||||||
|
var payList []handlers.PayInfo
|
||||||
|
// 事务处理
|
||||||
|
err = orderModel.Trans(l.ctx, func(ctx context.Context, connGorm *gorm.DB) (err error) {
|
||||||
|
// 修改订单信息
|
||||||
|
orderModelTS := gmodel.NewFsOrderModel(connGorm)
|
||||||
|
err = orderModelTS.Update(ctx, orderInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 新增退款记录
|
||||||
|
var isRefund int64 = 0
|
||||||
|
refundReasonModelTS := gmodel.NewFsRefundReasonModel(connGorm)
|
||||||
|
refundReasonModelTS.CreateOrUpdate(ctx, &gmodel.FsRefundReason{
|
||||||
|
IsRefund: &isRefund,
|
||||||
|
RefundReasonId: &req.RefundReasonId,
|
||||||
|
RefundReason: &req.RefundReason,
|
||||||
|
OrderId: &orderInfo.Id,
|
||||||
|
CreatedAt: &nowTime,
|
||||||
|
})
|
||||||
|
// 退款申请
|
||||||
|
// 退款申请--查询支付信息
|
||||||
|
fsPayModelTS := gmodel.NewFsPayModel(connGorm)
|
||||||
|
rbFsPay := fsPayModelTS.RowSelectBuilder(nil).Where("order_number = ?", orderInfo.Sn).Where("pay_status =?", constants.PAYSTATUS_SUCCESS).Where("is_refund =?", 0)
|
||||||
|
payInfoList, err := fsPayModelTS.FindAll(ctx, rbFsPay, nil, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, payInfo := range payInfoList {
|
||||||
|
var key string
|
||||||
|
if *payInfo.PaymentMethod == int64(constants.PAYMETHOD_STRIPE) {
|
||||||
|
key = l.svcCtx.Config.PayConfig.Stripe.Key
|
||||||
|
}
|
||||||
|
payList = append(payList, handlers.PayInfo{
|
||||||
|
TradeNo: *payInfo.TradeNo,
|
||||||
|
PaymentMethod: *payInfo.PaymentMethod,
|
||||||
|
Key: key,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
// 退款申请--调取第三方接口发起退款
|
||||||
|
handlers.PayRefundHandler(&handlers.PayRefundHandlerReq{
|
||||||
|
PayInfoList: payList,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeOrderCancelledNotOk, "the order cancle failed")
|
||||||
|
}
|
||||||
|
|
||||||
return resp.SetStatus(basic.CodeOK)
|
return resp.SetStatus(basic.CodeOK)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,19 @@ import (
|
|||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UserAgainOrderReq struct {
|
||||||
|
Sn string `form:"sn"` // 订单编号
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAgainOrderRes struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserLogoListReq struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserLogoListRes struct {
|
||||||
|
}
|
||||||
|
|
||||||
type UserOrderDeleteReq struct {
|
type UserOrderDeleteReq struct {
|
||||||
ID int64 `form:"id"` //订单id
|
ID int64 `form:"id"` //订单id
|
||||||
}
|
}
|
||||||
|
6
server/inventory/Dockerfile
Executable file
6
server/inventory/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-inventory-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-inventory-srv"]
|
@ -1,7 +1,6 @@
|
|||||||
Name: inventory
|
Name: inventory
|
||||||
Host: localhost
|
Host: localhost
|
||||||
Port: 9905
|
Port: 9905
|
||||||
ReplicaId: 30
|
|
||||||
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
||||||
Auth:
|
Auth:
|
||||||
AccessSecret: fusen2023
|
AccessSecret: fusen2023
|
||||||
|
@ -18,7 +18,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
Handler: TakeHandler(serverCtx),
|
Handler: TakeHandler(serverCtx),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodPost,
|
||||||
Path: "/api/inventory/list",
|
Path: "/api/inventory/list",
|
||||||
Handler: GetCloudListHandler(serverCtx),
|
Handler: GetCloudListHandler(serverCtx),
|
||||||
},
|
},
|
||||||
|
@ -16,9 +16,9 @@ type TakeForm struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetCloudListReq struct {
|
type GetCloudListReq struct {
|
||||||
Page int `form:"page"`
|
Page int `json:"page"`
|
||||||
PageSize int `form:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
Size int64 `form:"size"`
|
Size int64 `json:"size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetCloudListRsp struct {
|
type GetCloudListRsp struct {
|
||||||
|
12
server/inventory/inventory_test.go
Normal file
12
server/inventory/inventory_test.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
6
server/map-library/Dockerfile
Executable file
6
server/map-library/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-map-library-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-map-library-srv"]
|
6
server/orders/Dockerfile
Executable file
6
server/orders/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-order-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-order-srv"]
|
6
server/pay/Dockerfile
Executable file
6
server/pay/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-pay-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-pay-srv"]
|
@ -1,8 +1,6 @@
|
|||||||
Name: pay
|
Name: pay
|
||||||
Host: 0.0.0.0
|
Host: 0.0.0.0
|
||||||
Port: 9915
|
Port: 9915
|
||||||
ReplicaId: 45
|
|
||||||
Timeout: 15000
|
|
||||||
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
||||||
Auth:
|
Auth:
|
||||||
AccessSecret: fusen2023
|
AccessSecret: fusen2023
|
||||||
|
35
server/pay/internal/handler/orderrefundhandler.go
Normal file
35
server/pay/internal/handler/orderrefundhandler.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
|
||||||
|
"fusenapi/server/pay/internal/logic"
|
||||||
|
"fusenapi/server/pay/internal/svc"
|
||||||
|
"fusenapi/server/pay/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OrderRefundHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.OrderRefundReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewOrderRefundLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.OrderRefund(&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/pay/payment-intent",
|
Path: "/api/pay/payment-intent",
|
||||||
Handler: OrderPaymentIntentHandler(serverCtx),
|
Handler: OrderPaymentIntentHandler(serverCtx),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/api/pay/refund",
|
||||||
|
Handler: OrderRefundHandler(serverCtx),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Path: "/api/pay/stripe-webhook",
|
Path: "/api/pay/stripe-webhook",
|
||||||
|
@ -30,6 +30,15 @@ func StripeWebhookHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
IPAddress := r.Header.Get("X-Real-Ip")
|
||||||
|
if IPAddress == "" {
|
||||||
|
IPAddress = r.Header.Get("X-Forwarded-For")
|
||||||
|
}
|
||||||
|
if IPAddress == "" {
|
||||||
|
IPAddress = r.RemoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
req.RemoteAddr = IPAddress
|
||||||
req.Payload = payload
|
req.Payload = payload
|
||||||
req.StripeSignature = r.Header.Get("Stripe-Signature")
|
req.StripeSignature = r.Header.Get("Stripe-Signature")
|
||||||
|
|
||||||
|
43
server/pay/internal/logic/orderrefundlogic.go
Normal file
43
server/pay/internal/logic/orderrefundlogic.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/pay/internal/svc"
|
||||||
|
"fusenapi/server/pay/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderRefundLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOrderRefundLogic(ctx context.Context, svcCtx *svc.ServiceContext) *OrderRefundLogic {
|
||||||
|
return &OrderRefundLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *OrderRefundLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *OrderRefundLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *OrderRefundLogic) OrderRefund(req *types.OrderRefundReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
|
||||||
|
return resp.SetStatus(basic.CodeOK)
|
||||||
|
}
|
@ -64,6 +64,21 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
|
|||||||
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed")
|
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "Webhook signature verification failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增支付回调事件日志
|
||||||
|
var payMethod = int64(constants.PAYMETHOD_STRIPE)
|
||||||
|
var nowTime = time.Now().Unix()
|
||||||
|
var eventData = string(event.Data.Raw)
|
||||||
|
var fsPayEvent = &gmodel.FsPayEvent{
|
||||||
|
PayMethod: &payMethod,
|
||||||
|
EventId: &event.ID,
|
||||||
|
EventType: &event.Type,
|
||||||
|
EventData: &eventData,
|
||||||
|
EventCreated: &event.Created,
|
||||||
|
Ip: &req.RemoteAddr,
|
||||||
|
CreatedAt: &nowTime,
|
||||||
|
}
|
||||||
|
l.HandlePayEventCreate(fsPayEvent)
|
||||||
|
|
||||||
// Unmarshal the event data into an appropriate struct depending on its Type
|
// Unmarshal the event data into an appropriate struct depending on its Type
|
||||||
switch event.Type {
|
switch event.Type {
|
||||||
case "charge.succeeded":
|
case "charge.succeeded":
|
||||||
@ -91,12 +106,13 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
|
|||||||
var paymentIntent stripe.PaymentIntent
|
var paymentIntent stripe.PaymentIntent
|
||||||
err := json.Unmarshal(event.Data.Raw, &paymentIntent)
|
err := json.Unmarshal(event.Data.Raw, &paymentIntent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logx.Error(err)
|
logx.Errorf("err:%+v,desc:%s", err, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
|
||||||
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
|
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_intent.succeeded")
|
||||||
}
|
}
|
||||||
err = l.handlePaymentIntentSucceeded(&paymentIntent)
|
err = l.HandlePaymentIntentSucceeded(&paymentIntent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type Unhandled")
|
logx.Errorf("err:%+v,desc:%s", err, "pay notify handle payment_intent.succeeded")
|
||||||
|
return resp.SetStatusWithMessage(basic.CodePaybackNotOk, "pay notify handle payment_intent.succeeded")
|
||||||
}
|
}
|
||||||
case "payment_method.attached":
|
case "payment_method.attached":
|
||||||
var paymentMethod stripe.PaymentMethod
|
var paymentMethod stripe.PaymentMethod
|
||||||
@ -105,6 +121,19 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
|
|||||||
logx.Error(err)
|
logx.Error(err)
|
||||||
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached")
|
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type payment_method.attached")
|
||||||
}
|
}
|
||||||
|
case "charge.refunded":
|
||||||
|
var chargeRefunded stripe.Charge
|
||||||
|
err := json.Unmarshal(event.Data.Raw, &chargeRefunded)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("err:%+v,desc:%s", err, "pay notify Unmarshal fail event.Type charge.refunded")
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify Unmarshal fail event.Type charge.refunded")
|
||||||
|
}
|
||||||
|
err = l.HandleChargeRefunded(&chargeRefunded)
|
||||||
|
if err != nil {
|
||||||
|
logx.Errorf("err:%+v,desc:%s", err, "pay notify handle charge.refunded")
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeAesCbcDecryptionErr, "pay notify handle charge.refunded")
|
||||||
|
}
|
||||||
|
|
||||||
// ... handle other event types
|
// ... handle other event types
|
||||||
default:
|
default:
|
||||||
logx.Error("Unhandled event")
|
logx.Error("Unhandled event")
|
||||||
@ -114,6 +143,72 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
|
|||||||
return resp.SetStatus(basic.CodeOK)
|
return resp.SetStatus(basic.CodeOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 回调事件日志
|
||||||
|
func (l *StripeWebhookLogic) HandlePayEventCreate(fsPayEvent *gmodel.FsPayEvent) error {
|
||||||
|
_, err := gmodel.NewFsPayEventModel(l.svcCtx.MysqlConn).CreateOrUpdate(l.ctx, fsPayEvent)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退款成功
|
||||||
|
func (l *StripeWebhookLogic) HandleChargeRefunded(chargeRefunded *stripe.Charge) (err error) {
|
||||||
|
// 退款成功
|
||||||
|
if chargeRefunded.Status == "succeeded" {
|
||||||
|
orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
|
||||||
|
err = orderModel.Trans(l.ctx, func(ctx context.Context, connGorm *gorm.DB) (err error) {
|
||||||
|
// 查询支付记录
|
||||||
|
payModelT := gmodel.NewFsPayModel(connGorm)
|
||||||
|
payModelTRSB := payModelT.RowSelectBuilder(nil)
|
||||||
|
payModelTRSB1 := payModelTRSB.Where("trade_no = ?", chargeRefunded.PaymentIntent.ID).Where("pay_status = ?", constants.PAYSTATUS_SUCCESS).Where("is_refund = ?", 0)
|
||||||
|
payInfo, err := payModelT.FindOneByQuery(l.ctx, payModelTRSB1, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 更新支付记录
|
||||||
|
*payInfo.IsRefund = 1
|
||||||
|
_, err = payModelT.CreateOrUpdate(ctx, payInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// 获取是否还有未退款的数据
|
||||||
|
payModelTRSB2 := payModelTRSB.Where("order_number = ?", payInfo.OrderNumber).Where("pay_status = ?", constants.PAYSTATUS_SUCCESS).Where("is_refund = ?", 0)
|
||||||
|
count, err := payModelT.FindCount(l.ctx, payModelTRSB2, nil)
|
||||||
|
if count == 0 {
|
||||||
|
// 退款完成更新订单状态
|
||||||
|
orderModelT := gmodel.NewFsOrderModel(connGorm)
|
||||||
|
orderModelTRSB := orderModelT.RowSelectBuilder(nil).Where("sn =?", payInfo.OrderNumber)
|
||||||
|
orderInfoRel, err := orderModelT.FindOneByQuery(ctx, orderModelTRSB, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var isRefunded int64 = 1
|
||||||
|
var isRefunding int64 = 1
|
||||||
|
var orderStatus int64 = int64(constants.STATUS_NEW_REFUNDED)
|
||||||
|
var orderInfo = &gmodel.FsOrder{}
|
||||||
|
orderInfo.Id = orderInfoRel.Id
|
||||||
|
orderInfo.IsRefunded = &isRefunded
|
||||||
|
orderInfo.IsRefunding = &isRefunding
|
||||||
|
orderInfo.Status = &orderStatus
|
||||||
|
orderModelT.Update(ctx, orderInfo)
|
||||||
|
|
||||||
|
// 记录退款原因
|
||||||
|
refundReasonModelT := gmodel.NewFsRefundReasonModel(connGorm)
|
||||||
|
refundReasonModelTRSB := refundReasonModelT.RowSelectBuilder(nil).Where("order_id =?", orderInfoRel.Id)
|
||||||
|
refundReasonInfo, err := refundReasonModelT.FindOneByQuery(ctx, refundReasonModelTRSB, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*refundReasonInfo.IsRefund = 1
|
||||||
|
_, err = refundReasonModelT.CreateOrUpdate(ctx, refundReasonInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// session完成
|
// session完成
|
||||||
// func (l *StripeWebhookLogic) handlePaymentSessionCompleted(sessionId string, tradeNo string) (err error) {
|
// func (l *StripeWebhookLogic) handlePaymentSessionCompleted(sessionId string, tradeNo string) (err error) {
|
||||||
// // 查询支付记录
|
// // 查询支付记录
|
||||||
@ -136,8 +231,8 @@ func (l *StripeWebhookLogic) StripeWebhook(req *types.StripeWebhookReq, userinfo
|
|||||||
// return err
|
// return err
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 成功的付款
|
// 付款成功
|
||||||
func (l *StripeWebhookLogic) handlePaymentIntentSucceeded(paymentIntent *stripe.PaymentIntent) error {
|
func (l *StripeWebhookLogic) HandlePaymentIntentSucceeded(paymentIntent *stripe.PaymentIntent) error {
|
||||||
orderSn, ok := paymentIntent.Metadata["order_sn"]
|
orderSn, ok := paymentIntent.Metadata["order_sn"]
|
||||||
if !ok || orderSn == "" {
|
if !ok || orderSn == "" {
|
||||||
return errors.New("order_sn not found")
|
return errors.New("order_sn not found")
|
||||||
@ -146,14 +241,12 @@ func (l *StripeWebhookLogic) handlePaymentIntentSucceeded(paymentIntent *stripe.
|
|||||||
// 查询支付记录
|
// 查询支付记录
|
||||||
payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn)
|
payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn)
|
||||||
rsbPay := payModel.RowSelectBuilder(nil)
|
rsbPay := payModel.RowSelectBuilder(nil)
|
||||||
rsbPay = rsbPay.Where("order_number = ?", orderSn)
|
rsbPay = rsbPay.Where("order_number = ?", orderSn).Where("pay_status = ?", constants.PAYSTATUS_UNSUCCESS)
|
||||||
payInfo, err := payModel.FindOneByQuery(l.ctx, rsbPay, nil)
|
payInfo, err := payModel.FindOneByQuery(l.ctx, rsbPay, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if *payInfo.PayStatus == 1 {
|
|
||||||
return errors.New("pay status 1")
|
|
||||||
}
|
|
||||||
//订单信息
|
//订单信息
|
||||||
orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn)
|
orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn)
|
||||||
orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
|
orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
|
||||||
@ -209,6 +302,7 @@ func (l *StripeWebhookLogic) handlePaymentIntentSucceeded(paymentIntent *stripe.
|
|||||||
*payInfo.PayTime = nowTime
|
*payInfo.PayTime = nowTime
|
||||||
*payInfo.CardNo = card
|
*payInfo.CardNo = card
|
||||||
*payInfo.Brand = brand
|
*payInfo.Brand = brand
|
||||||
|
*payInfo.TradeNo = paymentIntent.ID
|
||||||
_, err = payModelT.CreateOrUpdate(ctx, payInfo)
|
_, err = payModelT.CreateOrUpdate(ctx, payInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -244,12 +338,12 @@ func (l *StripeWebhookLogic) handlePaymentIntentSucceeded(paymentIntent *stripe.
|
|||||||
|
|
||||||
// 支付记录是尾款
|
// 支付记录是尾款
|
||||||
if *payInfo.PayStage == int64(constants.PAYSTAGE_REMAINING) {
|
if *payInfo.PayStage == int64(constants.PAYSTAGE_REMAINING) {
|
||||||
if *orderInfo.Status < int64(constants.STATUS_NEW_PAY_COMPLETED) {
|
if *fsOrderRelInfo.Status < int64(constants.STATUS_NEW_PAY_COMPLETED) {
|
||||||
orderStatus = int64(constants.STATUS_NEW_PAY_COMPLETED)
|
orderStatus = int64(constants.STATUS_NEW_PAY_COMPLETED)
|
||||||
}
|
}
|
||||||
orderIsPayCompleted = 1
|
orderIsPayCompleted = 1
|
||||||
orderInfo.IsPayCompleted = &orderIsPayCompleted
|
orderInfo.IsPayCompleted = &orderIsPayCompleted
|
||||||
orderPayedAmount = *orderInfo.PayedAmount + paymentIntent.Amount
|
orderPayedAmount = *fsOrderRelInfo.PayedAmount + paymentIntent.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新订单信息
|
// 更新订单信息
|
||||||
|
@ -5,6 +5,12 @@ import (
|
|||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type OrderRefundReq struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderRefundRes struct {
|
||||||
|
}
|
||||||
|
|
||||||
type OrderPaymentIntentReq struct {
|
type OrderPaymentIntentReq struct {
|
||||||
Sn string `form:"sn"` //订单编号
|
Sn string `form:"sn"` //订单编号
|
||||||
DeliveryMethod int64 `form:"delivery_method"` //发货方式
|
DeliveryMethod int64 `form:"delivery_method"` //发货方式
|
||||||
@ -20,6 +26,7 @@ type OrderPaymentIntentRes struct {
|
|||||||
type StripeWebhookReq struct {
|
type StripeWebhookReq struct {
|
||||||
Payload []byte `json:"base_byte_slice,optional"`
|
Payload []byte `json:"base_byte_slice,optional"`
|
||||||
StripeSignature string `json:"Stripe-Signature"`
|
StripeSignature string `json:"Stripe-Signature"`
|
||||||
|
RemoteAddr string `json:"remote_addr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
6
server/product-model/Dockerfile
Executable file
6
server/product-model/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-product-model-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-product-model-srv"]
|
6
server/product-template-tag/Dockerfile
Executable file
6
server/product-template-tag/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-product-template-tag-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-product-template-tag-srv"]
|
6
server/product-template/Dockerfile
Executable file
6
server/product-template/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-product-template-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-product-template-srv"]
|
6
server/product/Dockerfile
Executable file
6
server/product/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-product-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-product-srv"]
|
@ -50,6 +50,7 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
|
|||||||
Status: &tStatus,
|
Status: &tStatus,
|
||||||
OrderBy: "`sort` DESC",
|
OrderBy: "`sort` DESC",
|
||||||
WithChild: true, //需要子集
|
WithChild: true, //需要子集
|
||||||
|
Category: 1, //前台网站用的
|
||||||
}
|
}
|
||||||
//传入分类id
|
//传入分类id
|
||||||
if req.Cid > 0 {
|
if req.Cid > 0 {
|
||||||
@ -62,6 +63,9 @@ func (l *GetTagProductListLogic) GetTagProductList(req *types.GetTagProductListR
|
|||||||
logx.Error(err)
|
logx.Error(err)
|
||||||
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get tag info")
|
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get tag info")
|
||||||
}
|
}
|
||||||
|
if *tagData.Category != 1 {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "invalid tag")
|
||||||
|
}
|
||||||
tReq.LevelPrefixLeftLike = *tagData.LevelPrefix
|
tReq.LevelPrefixLeftLike = *tagData.LevelPrefix
|
||||||
}
|
}
|
||||||
tagList, err := l.svcCtx.AllModels.FsTags.GetAllTagByParams(l.ctx, tReq)
|
tagList, err := l.svcCtx.AllModels.FsTags.GetAllTagByParams(l.ctx, tReq)
|
||||||
@ -220,7 +224,7 @@ func (l *GetTagProductListLogic) dealWithTagMenuData(req dealWithTagMenuDataReq)
|
|||||||
*req.MinLevel = lenLevel
|
*req.MinLevel = lenLevel
|
||||||
}
|
}
|
||||||
tagTem := types.TagItem{
|
tagTem := types.TagItem{
|
||||||
TagProductList: nil,
|
TagProductList: []interface{}{},
|
||||||
TypeName: *tagInfo.Title,
|
TypeName: *tagInfo.Title,
|
||||||
TypeId: tagInfo.Id,
|
TypeId: tagInfo.Id,
|
||||||
Icon: *tagInfo.Icon,
|
Icon: *tagInfo.Icon,
|
||||||
|
6
server/render/Dockerfile
Executable file
6
server/render/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-render-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-render-srv"]
|
238
server/render/consumer/assemble_render_data.go
Normal file
238
server/render/consumer/assemble_render_data.go
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
package consumer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/websocket_data"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 这里请求的py接口返回数据
|
||||||
|
type pythonApiRsp struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data []struct {
|
||||||
|
Tid int64 `json:"tid"`
|
||||||
|
Imgurl string `json:"imgurl"`
|
||||||
|
Costtime int64 `json:"costtime"`
|
||||||
|
} `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消费渲染需要组装的数据
|
||||||
|
type MqConsumerRenderAssemble struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MqConsumerRenderAssemble) Run(ctx context.Context, data []byte) error {
|
||||||
|
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("allmodels")
|
||||||
|
if val == nil {
|
||||||
|
return errors.New("allmodels is nil")
|
||||||
|
}
|
||||||
|
allmodels, ok := val.(*gmodel.AllModelsGen)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("allmodels is nil!!")
|
||||||
|
}
|
||||||
|
timeSearchBegin := time.Now().UnixMilli()
|
||||||
|
//获取模板
|
||||||
|
templateInfo, err := allmodels.FsProductTemplateV2.FindOneByProductIdTagIdWithSizeTable(ctx, parseInfo.RenderData.ProductId, fmt.Sprintf("%d", parseInfo.RenderData.TemplateTagId))
|
||||||
|
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 err
|
||||||
|
}
|
||||||
|
renderLogTime := time.Now().UnixMilli() - timeSearchBegin
|
||||||
|
now := time.Now().Unix()
|
||||||
|
title := "1-组装模板数据"
|
||||||
|
//云渲染日志
|
||||||
|
err = allmodels.FsCloudRenderLog.Create(ctx, &gmodel.FsCloudRenderLog{
|
||||||
|
UserId: &parseInfo.RenderData.UserId,
|
||||||
|
Title: &title,
|
||||||
|
Time: &renderLogTime,
|
||||||
|
Tag: &parseInfo.RenderId,
|
||||||
|
Ctime: &now,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
pyapiBeginTime := time.Now().UnixMilli()
|
||||||
|
//这里curl post请求数据。获取处理好的贴图数据,用于贴model的贴图
|
||||||
|
pythonPostData := map[string]interface{}{
|
||||||
|
"tids": templateInfo.Id,
|
||||||
|
"data": parseInfo.RenderData.Data,
|
||||||
|
}
|
||||||
|
pyPostBytes, _ := json.Marshal(pythonPostData)
|
||||||
|
url := "http://110.41.19.98:8867/imgRender"
|
||||||
|
pyRsp, err := http.Post(url, "application/json;charset=UTF-8", bytes.NewReader(pyPostBytes))
|
||||||
|
if err != nil {
|
||||||
|
logx.Error("request python render api err:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer pyRsp.Body.Close()
|
||||||
|
pyRspBytes, err := ioutil.ReadAll(pyRsp.Body)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error("failed to read python api rsp body,err=", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var rspInfo pythonApiRsp
|
||||||
|
if err = json.Unmarshal(pyRspBytes, &rspInfo); err != nil {
|
||||||
|
logx.Error("failed to unmarshal python api rsp:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rspInfo.Code != 200 {
|
||||||
|
logx.Error("python api 接口请求错误:", rspInfo.Msg)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(rspInfo.Data) == 0 {
|
||||||
|
logx.Error("python api 接口没有数据:")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//云渲染日志
|
||||||
|
title = "2-请求->接收python合成刀版图接口"
|
||||||
|
now = time.Now().Unix()
|
||||||
|
pyRequestTime := time.Now().UnixMilli() - pyapiBeginTime
|
||||||
|
err = allmodels.FsCloudRenderLog.Create(ctx, &gmodel.FsCloudRenderLog{
|
||||||
|
UserId: &parseInfo.RenderData.UserId,
|
||||||
|
Title: &title,
|
||||||
|
Time: &pyRequestTime,
|
||||||
|
Tag: &parseInfo.RenderId,
|
||||||
|
Ctime: &now,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
incTime := int64(0)
|
||||||
|
mapCurlData := make(map[int64]int)
|
||||||
|
for k, v := range rspInfo.Data {
|
||||||
|
mapCurlData[v.Tid] = k
|
||||||
|
incTime += v.Costtime
|
||||||
|
}
|
||||||
|
//云渲染日志
|
||||||
|
title = "3-python合成刀版图"
|
||||||
|
now = time.Now().Unix()
|
||||||
|
postData := string(pyPostBytes)
|
||||||
|
pyRspStr := string(pyRspBytes)
|
||||||
|
err = allmodels.FsCloudRenderLog.Create(ctx, &gmodel.FsCloudRenderLog{
|
||||||
|
UserId: &parseInfo.RenderData.UserId,
|
||||||
|
PostUrl: &url,
|
||||||
|
PostData: &postData,
|
||||||
|
Result: &pyRspStr,
|
||||||
|
Title: &title,
|
||||||
|
Time: &incTime,
|
||||||
|
Tag: &parseInfo.RenderId,
|
||||||
|
Ctime: &now,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
//获取渲染设置信息
|
||||||
|
//element, err := allmodels.FsProductTemplateElement
|
||||||
|
/*
|
||||||
|
|
||||||
|
$element = ProductTemplateElement::find()
|
||||||
|
->andFilterWhere(['in', 'product_template_id', $mids])
|
||||||
|
->asArray()
|
||||||
|
->all();
|
||||||
|
|
||||||
|
$element = array_column($element, null, 'product_template_id');
|
||||||
|
$elementTitles = array_column($element, 'title');
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
$time_pinjie_begin = $render->getMillisecond();
|
||||||
|
foreach ($templates as $key => $val) {
|
||||||
|
if(!isset($element[$val['model_id']]) || !isset($imageData[$val['id']])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//数据拼装
|
||||||
|
$item = [];
|
||||||
|
|
||||||
|
$item['light'] = $element[$val['model_id']]['light'];
|
||||||
|
$item['refletion'] = $element[$val['model_id']]['refletion'] == '' ? -1 : (int)$element[$val['model_id']]['refletion'];
|
||||||
|
$item['scale'] = $element[$val['model_id']]['scale'];
|
||||||
|
$item['sku_id'] = $val['product_id'];
|
||||||
|
$item['tid'] = $element[$val['model_id']]['title'];
|
||||||
|
$item['rotation'] = $element[$val['model_id']]['rotation'];
|
||||||
|
$item['filePath'] = '';//todo 文件路径,针对千人千面
|
||||||
|
|
||||||
|
//组装data数据
|
||||||
|
$tempData = [];
|
||||||
|
//获取材质模式对应关系
|
||||||
|
$mode = $element[$val['model_id']]['mode'] ? json_decode($element[$val['model_id']]['mode'], true) : [];
|
||||||
|
// $base_img = (new ImageService())->base64EncodeImageNoHeader(\Yii::$app->params['baseurl'].$imageData[$val['id']]['imgurl']);
|
||||||
|
$base_img = \Yii::$app->params['h5Url'].'/storage'.$imageData[$val['id']]['imgurl'];
|
||||||
|
//判断是否包含base数据 即对应建模那边的model
|
||||||
|
if($element[$val['model_id']]['base']){
|
||||||
|
$tempData[] = [
|
||||||
|
'name' => 'model',
|
||||||
|
'data' => '0,'.$base_img.','.$element[$val['model_id']]['base'],
|
||||||
|
'type' => 'other',
|
||||||
|
'layer' => '0',
|
||||||
|
'is_update' => 1,
|
||||||
|
'mode' => $mode['model'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if($element[$val['model_id']]['shadow']){
|
||||||
|
$tempData[] = [
|
||||||
|
'name' => 'shadow',
|
||||||
|
'data' => $element[$val['model_id']]['shadow'],
|
||||||
|
'type' => 'other',
|
||||||
|
'layer' => '0',
|
||||||
|
'is_update' => 0,
|
||||||
|
'mode' => $mode['shadow'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if($element[$val['model_id']]['model_p']){
|
||||||
|
$tempData[] = [
|
||||||
|
'name' => 'model_P',
|
||||||
|
'data' => '0,'.$element[$val['model_id']]['model_p'],
|
||||||
|
'type' => 'other',
|
||||||
|
'layer' => '0',
|
||||||
|
'is_update' => 0,
|
||||||
|
'mode' => $mode['model_P'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$item['data'] = $tempData;
|
||||||
|
$result[] = $item;
|
||||||
|
|
||||||
|
}
|
||||||
|
$log = new CloudRenderLog();
|
||||||
|
$log->title = '接收到python刀版图 -> 3-组装MQ渲染任务队列';
|
||||||
|
$log->time = $render->getMillisecond() - $time_pinjie_begin;
|
||||||
|
$log->user_id = $user_id;
|
||||||
|
$log->post_data = '';
|
||||||
|
$log->post_url = '';
|
||||||
|
$log->result = $res;
|
||||||
|
$log->tag = $inputData['id'];
|
||||||
|
$log->ctime = time();
|
||||||
|
$log->save(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sendData = [
|
||||||
|
'id' => $inputData['id'],
|
||||||
|
'order_id' => 0,
|
||||||
|
'user_id' => \Yii::$app->user->id,
|
||||||
|
'sku_ids' => $inputData['sku_ids'],
|
||||||
|
'tids' => $elementTitles,
|
||||||
|
'data' => $result,
|
||||||
|
'is_thousand_face' => 0,
|
||||||
|
'folder' => '',//todo 千人千面需要使用
|
||||||
|
];
|
||||||
|
return $sendData;*/
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
Name: render
|
Name: render
|
||||||
Host: localhost
|
Host: 0.0.0.0
|
||||||
Port: 8888
|
Port: 9919
|
||||||
ReplicaId: 55
|
|
||||||
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
||||||
Auth:
|
Auth:
|
||||||
AccessSecret: fusen2023
|
AccessSecret: fusen2023
|
||||||
AccessExpire: 2592000
|
AccessExpire: 2592000
|
||||||
RefreshAfter: 1592000
|
RefreshAfter: 1592000
|
||||||
|
SourceRabbitMq: amqp://rabbit001:rabbit001129@110.41.19.98:5672
|
@ -11,4 +11,5 @@ type Config struct {
|
|||||||
SourceMysql string
|
SourceMysql string
|
||||||
Auth types.Auth
|
Auth types.Auth
|
||||||
ReplicaId uint64
|
ReplicaId uint64
|
||||||
|
SourceRabbitMq string
|
||||||
}
|
}
|
||||||
|
@ -11,22 +11,22 @@ import (
|
|||||||
"fusenapi/server/render/internal/types"
|
"fusenapi/server/render/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToUnityHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func GetFaceSliceHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var req types.RequestToUnity
|
var req types.Request
|
||||||
userinfo, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
userinfo, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个业务逻辑层实例
|
// 创建一个业务逻辑层实例
|
||||||
l := logic.NewToUnityLogic(r.Context(), svcCtx)
|
l := logic.NewGetFaceSliceLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
rl := reflect.ValueOf(l)
|
rl := reflect.ValueOf(l)
|
||||||
basic.BeforeLogic(w, r, rl)
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
resp := l.ToUnity(&req, userinfo)
|
resp := l.GetFaceSlice(&req, userinfo)
|
||||||
|
|
||||||
if !basic.AfterLogic(w, r, rl, resp) {
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
basic.NormalAfterLogic(w, r, resp)
|
basic.NormalAfterLogic(w, r, resp)
|
@ -11,22 +11,22 @@ import (
|
|||||||
"fusenapi/server/render/internal/types"
|
"fusenapi/server/render/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReadImagesHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func RenderNotifyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var req types.RequestReadImages
|
var req types.RenderNotifyReq
|
||||||
userinfo, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
userinfo, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个业务逻辑层实例
|
// 创建一个业务逻辑层实例
|
||||||
l := logic.NewReadImagesLogic(r.Context(), svcCtx)
|
l := logic.NewRenderNotifyLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
rl := reflect.ValueOf(l)
|
rl := reflect.ValueOf(l)
|
||||||
basic.BeforeLogic(w, r, rl)
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
resp := l.ReadImages(&req, userinfo)
|
resp := l.RenderNotify(&req, userinfo)
|
||||||
|
|
||||||
if !basic.AfterLogic(w, r, rl, resp) {
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
basic.NormalAfterLogic(w, r, resp)
|
basic.NormalAfterLogic(w, r, resp)
|
@ -13,14 +13,14 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
server.AddRoutes(
|
server.AddRoutes(
|
||||||
[]rest.Route{
|
[]rest.Route{
|
||||||
{
|
{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodPost,
|
||||||
Path: "/api/render/to-unity",
|
Path: "/api/render/render_notify",
|
||||||
Handler: ToUnityHandler(serverCtx),
|
Handler: RenderNotifyHandler(serverCtx),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Method: http.MethodGet,
|
Method: http.MethodPost,
|
||||||
Path: "/api/render/read-images",
|
Path: "/api/render/get_face_slice",
|
||||||
Handler: ReadImagesHandler(serverCtx),
|
Handler: GetFaceSliceHandler(serverCtx),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
69
server/render/internal/logic/getfaceslicelogic.go
Normal file
69
server/render/internal/logic/getfaceslicelogic.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fusenapi/constants"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/render/internal/svc"
|
||||||
|
"fusenapi/server/render/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetFaceSliceLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetFaceSliceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFaceSliceLogic {
|
||||||
|
return &GetFaceSliceLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *GetFaceSliceLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *GetFaceSliceLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *GetFaceSliceLogic) GetFaceSlice(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
if !userinfo.IsUser() && !userinfo.IsGuest() {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeUnAuth, "please login or access cookie")
|
||||||
|
}
|
||||||
|
//获取用户素材信息
|
||||||
|
materialInfo, err := l.svcCtx.AllModels.FsUserMaterial.FindLatestOne(l.ctx, userinfo.UserId, userinfo.GuestId)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "user material info is not exists")
|
||||||
|
}
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get user material info")
|
||||||
|
}
|
||||||
|
if materialInfo.Metadata == nil || *materialInfo.Metadata == "" {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeServiceErr, "user material info`Metadata is empty")
|
||||||
|
}
|
||||||
|
var info map[string]interface{}
|
||||||
|
if err = json.Unmarshal([]byte(*materialInfo.Metadata), &info); err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeJsonErr, "invalid json format of metadata")
|
||||||
|
}
|
||||||
|
str := strings.ReplaceAll(constants.RENDER_FACE_SLICE_TEMPLATE_JSON, "{{MainColorFill}}", info["main_color_fill"].(string))
|
||||||
|
str = strings.ReplaceAll(str, "{{SecondaryColorFill}}", info["secondary_color_fill"].(string))
|
||||||
|
str = strings.ReplaceAll(str, "{{LogoMaterial}}", info["logo_material"].(string))
|
||||||
|
var rspInfo interface{}
|
||||||
|
_ = json.Unmarshal([]byte(str), &rspInfo)
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeOK, "success", rspInfo)
|
||||||
|
}
|
@ -1,42 +0,0 @@
|
|||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fusenapi/utils/auth"
|
|
||||||
"fusenapi/utils/basic"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"fusenapi/server/render/internal/svc"
|
|
||||||
"fusenapi/server/render/internal/types"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ReadImagesLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewReadImagesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ReadImagesLogic {
|
|
||||||
return &ReadImagesLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理进入前逻辑w,r
|
|
||||||
// func (l *ReadImagesLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 处理逻辑后 w,r 如:重定向
|
|
||||||
// func (l *ReadImagesLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (l *ReadImagesLogic) ReadImages(req *types.RequestReadImages, userinfo *auth.UserInfo) (resp *basic.Response) {
|
|
||||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
|
||||||
// userinfo 传入值时, 一定不为null
|
|
||||||
|
|
||||||
return resp.SetStatus(basic.CodeOK)
|
|
||||||
}
|
|
@ -1,14 +1,15 @@
|
|||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fusenapi/constants"
|
|
||||||
"fusenapi/utils/basic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fusenapi/constants"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"fusenapi/utils/websocket_data"
|
||||||
|
|
||||||
"fusenapi/server/websocket/internal/svc"
|
"fusenapi/server/render/internal/svc"
|
||||||
"fusenapi/server/websocket/internal/types"
|
"fusenapi/server/render/internal/types"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
@ -36,50 +37,36 @@ func NewRenderNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Rend
|
|||||||
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq) (resp *basic.Response) {
|
func (l *RenderNotifyLogic) RenderNotify(req *types.RenderNotifyReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
if time.Now().Unix()-120 > req.Time /*|| req.Time > time.Now().Unix() */ {
|
/*if time.Now().Unix()-120 > req.Time || req.Time > time.Now().Unix() {
|
||||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param time")
|
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param time")
|
||||||
|
}*/
|
||||||
|
if req.Info.TaskId == "" {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param task_id")
|
||||||
}
|
}
|
||||||
|
if req.Info.Image == "" {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param image")
|
||||||
|
}
|
||||||
|
/* if req.Sign == "" {
|
||||||
|
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid param sign")
|
||||||
|
}*/
|
||||||
//验证签名 sha256
|
//验证签名 sha256
|
||||||
/*notifyByte, _ := json.Marshal(req.Info)
|
/*notifyByte, _ := json.Marshal(req.Info)
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(fmt.Sprintf(constants.RENDER_NOTIFY_SIGN_KEY, string(notifyByte), req.Time)))
|
h.Write([]byte(fmt.Sprintf(constants.RENDER_NOTIFY_SIGN_KEY, string(notifyByte), req.Time)))
|
||||||
signHex := h.Sum(nil)
|
signHex := h.Sum(nil)
|
||||||
sign := hex.EncodeToString(signHex)
|
sign := hex.EncodeToString(signHex)
|
||||||
//fmt.Println(sign)
|
|
||||||
if req.Sign != sign {
|
if req.Sign != sign {
|
||||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid sign")
|
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid sign")
|
||||||
}*/
|
}*/
|
||||||
//遍历websocket链接把数据传进去
|
data := websocket_data.RenderImageNotify{
|
||||||
mapConnPool.Range(func(key, value any) bool {
|
TaskId: req.Info.TaskId,
|
||||||
//断言连接
|
|
||||||
ws, ok := value.(wsConnectItem)
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
//关闭标识
|
|
||||||
if ws.isClose {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
renderKey := ws.getRenderImageMapKey(req.Info.ProductId, req.Info.TemplateTagId, req.Info.LogoId, req.Info.AlgorithmVersion)
|
|
||||||
//查询有无该渲染任务
|
|
||||||
_, ok = ws.renderProperty.renderImageTask[renderKey]
|
|
||||||
if !ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
b := ws.respondDataFormat(constants.WEBSOCKET_RENDER_IMAGE, types.RenderImageRspMsg{
|
|
||||||
ProductId: req.Info.ProductId,
|
|
||||||
TemplateTagId: req.Info.TemplateTagId,
|
|
||||||
Image: req.Info.Image,
|
Image: req.Info.Image,
|
||||||
})
|
|
||||||
//删除对应的需要渲染的图片map
|
|
||||||
ws.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{
|
|
||||||
Option: 0, //0删除 1添加
|
|
||||||
Key: renderKey,
|
|
||||||
}
|
}
|
||||||
//发送数据到out chan
|
d, _ := json.Marshal(data)
|
||||||
ws.sendToOutChan(b)
|
if err := l.svcCtx.RabbitMq.SendMsg(constants.RABBIT_MQ_RENDER_RESULT_DATA, d); err != nil {
|
||||||
return true
|
logx.Error(err)
|
||||||
})
|
return resp.SetStatus(basic.CodeServiceErr, "failed to send data")
|
||||||
|
}
|
||||||
return resp.SetStatus(basic.CodeOK)
|
return resp.SetStatus(basic.CodeOK)
|
||||||
}
|
}
|
@ -1,42 +0,0 @@
|
|||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fusenapi/utils/auth"
|
|
||||||
"fusenapi/utils/basic"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"fusenapi/server/render/internal/svc"
|
|
||||||
"fusenapi/server/render/internal/types"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ToUnityLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewToUnityLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ToUnityLogic {
|
|
||||||
return &ToUnityLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理进入前逻辑w,r
|
|
||||||
// func (l *ToUnityLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 处理逻辑后 w,r 如:重定向
|
|
||||||
// func (l *ToUnityLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (l *ToUnityLogic) ToUnity(req *types.RequestToUnity, userinfo *auth.UserInfo) (resp *basic.Response) {
|
|
||||||
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
|
||||||
// userinfo 传入值时, 一定不为null
|
|
||||||
|
|
||||||
return resp.SetStatus(basic.CodeOK)
|
|
||||||
}
|
|
@ -21,6 +21,7 @@ type ServiceContext struct {
|
|||||||
|
|
||||||
MysqlConn *gorm.DB
|
MysqlConn *gorm.DB
|
||||||
AllModels *gmodel.AllModelsGen
|
AllModels *gmodel.AllModelsGen
|
||||||
|
RabbitMq *initalize.RabbitMqHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config) *ServiceContext {
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
@ -32,6 +33,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
MysqlConn: conn,
|
MysqlConn: conn,
|
||||||
SharedState: StateServer,
|
SharedState: StateServer,
|
||||||
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
|
AllModels: gmodel.NewAllModels(initalize.InitMysql(c.SourceMysql)),
|
||||||
|
RabbitMq: initalize.InitRabbitMq(c.SourceRabbitMq, nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,17 @@ type RequestToUnity struct {
|
|||||||
type RequestReadImages 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"`
|
||||||
|
}
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"fusenapi/constants"
|
||||||
|
"fusenapi/server/render/consumer"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -29,8 +32,13 @@ func main() {
|
|||||||
defer server.Stop()
|
defer server.Stop()
|
||||||
|
|
||||||
ctx := svc.NewServiceContext(c)
|
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_ASSEMBLE_RENDER_DATA, &consumer.MqConsumerRenderAssemble{})
|
||||||
handler.RegisterHandlers(server, ctx)
|
handler.RegisterHandlers(server, ctx)
|
||||||
|
|
||||||
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
||||||
server.Start()
|
server.Start()
|
||||||
}
|
}
|
||||||
|
6
server/shopping-cart-confirmation/Dockerfile
Executable file
6
server/shopping-cart-confirmation/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-shopping-cart-confirmation-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-shopping-cart-confirmation-srv"]
|
6
server/upload/Dockerfile
Executable file
6
server/upload/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-upload-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-upload-srv"]
|
@ -14,3 +14,6 @@ AWS:
|
|||||||
AccessKeyID: AKIAZB2JKUXDPNRP4YT2
|
AccessKeyID: AKIAZB2JKUXDPNRP4YT2
|
||||||
Secret: sjCEv0JxATnPCxno2KNLm0X8oDc7srUR+4vkYhvm
|
Secret: sjCEv0JxATnPCxno2KNLm0X8oDc7srUR+4vkYhvm
|
||||||
Token:
|
Token:
|
||||||
|
BLMService:
|
||||||
|
ImageProcess:
|
||||||
|
Url: "http://110.41.19.98:8868/removebg"
|
||||||
|
@ -21,4 +21,9 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BLMService struct {
|
||||||
|
ImageProcess struct {
|
||||||
|
Url string
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,31 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
Path: "/api/upload/qrcode",
|
Path: "/api/upload/qrcode",
|
||||||
Handler: UploadQrcodeHandler(serverCtx),
|
Handler: UploadQrcodeHandler(serverCtx),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/api/upload/upload-files-backend",
|
||||||
|
Handler: UploadFilesBackendHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/api/upload/upload-files-frontend",
|
||||||
|
Handler: UploadFilesFrontendHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/api/upload/upload-callback",
|
||||||
|
Handler: UploadCallbackHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/api/upload/up-logo",
|
||||||
|
Handler: UploadLogoHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/api/upload/upload-file-base",
|
||||||
|
Handler: UploadFileBaseHandler(serverCtx),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
35
server/upload/internal/handler/uploadcallbackhandler.go
Normal file
35
server/upload/internal/handler/uploadcallbackhandler.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 UploadCallbackHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.UploadCallbackReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewUploadCallbackLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.UploadCallback(&req, userinfo)
|
||||||
|
|
||||||
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
|
basic.NormalAfterLogic(w, r, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
server/upload/internal/handler/uploadfilebasehandler.go
Normal file
35
server/upload/internal/handler/uploadfilebasehandler.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 UploadFileBaseHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.UploadFileBaseReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewUploadFileBaseLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.UploadFileBase(&req, userinfo)
|
||||||
|
|
||||||
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
|
basic.NormalAfterLogic(w, r, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
server/upload/internal/handler/uploadfilesbackendhandler.go
Normal file
35
server/upload/internal/handler/uploadfilesbackendhandler.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 UploadFilesBackendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.UploadFilesReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewUploadFilesBackendLogic(r, svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.UploadFilesBackend(&req, userinfo)
|
||||||
|
|
||||||
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
|
basic.NormalAfterLogic(w, r, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
server/upload/internal/handler/uploadfilesfrontendhandler.go
Normal file
35
server/upload/internal/handler/uploadfilesfrontendhandler.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 UploadFilesFrontendHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.UploadFilesReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewUploadFilesFrontendLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.UploadFilesFrontend(&req, userinfo)
|
||||||
|
|
||||||
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
|
basic.NormalAfterLogic(w, r, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
server/upload/internal/handler/uploadlogohandler.go
Normal file
35
server/upload/internal/handler/uploadlogohandler.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 UploadLogoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
var req types.UploadLogoReq
|
||||||
|
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个业务逻辑层实例
|
||||||
|
l := logic.NewUploadLogoLogic(r.Context(), svcCtx)
|
||||||
|
|
||||||
|
rl := reflect.ValueOf(l)
|
||||||
|
basic.BeforeLogic(w, r, rl)
|
||||||
|
|
||||||
|
resp := l.UploadLogo(&req, userinfo)
|
||||||
|
|
||||||
|
if !basic.AfterLogic(w, r, rl, resp) {
|
||||||
|
basic.NormalAfterLogic(w, r, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
server/upload/internal/logic/uploadcallbacklogic.go
Normal file
98
server/upload/internal/logic/uploadcallbacklogic.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/upload/internal/svc"
|
||||||
|
"fusenapi/server/upload/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadCallbackLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUploadCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadCallbackLogic {
|
||||||
|
return &UploadCallbackLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UploadCallbackLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UploadCallbackLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UploadCallbackLogic) UploadCallback(req *types.UploadCallbackReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
|
||||||
|
var userId int64
|
||||||
|
var guestId int64
|
||||||
|
|
||||||
|
// 检查用户是否是游客
|
||||||
|
if userinfo.IsGuest() {
|
||||||
|
// 如果是,使用游客ID和游客键名格式
|
||||||
|
guestId = userinfo.GuestId
|
||||||
|
} else {
|
||||||
|
// 否则,使用用户ID和用户键名格式
|
||||||
|
userId = userinfo.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义存储桶名称
|
||||||
|
var bucketName *string
|
||||||
|
|
||||||
|
// 根据类别选择存储桶
|
||||||
|
switch req.UploadBucket {
|
||||||
|
case 2:
|
||||||
|
bucketName = basic.TempfileBucketName
|
||||||
|
default:
|
||||||
|
bucketName = basic.StorageBucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceModel := gmodel.NewFsResourceModel(l.svcCtx.MysqlConn)
|
||||||
|
err := resourceModel.Trans(l.ctx, func(ctx context.Context, connGorm *gorm.DB) (err error) {
|
||||||
|
resourceModelTS := gmodel.NewFsResourceModel(l.svcCtx.MysqlConn)
|
||||||
|
resourceInfo, err := resourceModelTS.FindOneById(ctx, req.ResourceId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var version string = "0.0.1"
|
||||||
|
var fsResource = &gmodel.FsResource{}
|
||||||
|
fsResource.UserId = &userId
|
||||||
|
fsResource.GuestId = &guestId
|
||||||
|
fsResource.ResourceId = req.ResourceId
|
||||||
|
fsResource.ResourceType = &req.ResourceType
|
||||||
|
fsResource.ResourceUrl = &req.ResourceUrl
|
||||||
|
fsResource.Metadata = &req.Metadata
|
||||||
|
fsResource.ApiType = &req.ApiType
|
||||||
|
fsResource.BucketName = bucketName
|
||||||
|
fsResource.Version = &version
|
||||||
|
if resourceInfo.ResourceId == "" {
|
||||||
|
_, err = resourceModelTS.Create(ctx, fsResource)
|
||||||
|
} else {
|
||||||
|
_, err = resourceModelTS.Update(ctx, fsResource)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,UploadCallback failed")
|
||||||
|
}
|
||||||
|
return resp.SetStatus(basic.CodeOK)
|
||||||
|
}
|
154
server/upload/internal/logic/uploadfilebaselogic.go
Normal file
154
server/upload/internal/logic/uploadfilebaselogic.go
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"fusenapi/utils/file"
|
||||||
|
"fusenapi/utils/hash"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/upload/internal/svc"
|
||||||
|
"fusenapi/server/upload/internal/types"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadFileBaseLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUploadFileBaseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFileBaseLogic {
|
||||||
|
return &UploadFileBaseLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UploadFileBaseLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UploadFileBaseLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UploadFileBaseLogic) UploadFileBase(req *types.UploadFileBaseReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
// 定义用户ID和S3键名格式
|
||||||
|
var userId int64
|
||||||
|
var guestId int64
|
||||||
|
|
||||||
|
// 检查用户是否是游客
|
||||||
|
if userinfo.IsGuest() {
|
||||||
|
// 如果是,使用游客ID和游客键名格式
|
||||||
|
guestId = userinfo.GuestId
|
||||||
|
} else {
|
||||||
|
// 否则,使用用户ID和用户键名格式
|
||||||
|
userId = userinfo.UserId
|
||||||
|
}
|
||||||
|
if guestId == 0 {
|
||||||
|
guestId = req.GuestId
|
||||||
|
}
|
||||||
|
if userId == 0 {
|
||||||
|
userId = req.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义存储桶名称
|
||||||
|
var bucketName *string
|
||||||
|
var apiType int64 = req.ApiType
|
||||||
|
|
||||||
|
// 根据类别选择存储桶
|
||||||
|
switch req.UploadBucket {
|
||||||
|
case 2:
|
||||||
|
bucketName = basic.TempfileBucketName
|
||||||
|
default:
|
||||||
|
bucketName = basic.StorageBucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置AWS会话的区域
|
||||||
|
l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1")
|
||||||
|
|
||||||
|
// 创建新的S3服务实例
|
||||||
|
svc := s3.New(l.svcCtx.AwsSession)
|
||||||
|
|
||||||
|
// 定义S3请求和当前时间
|
||||||
|
var s3req *request.Request
|
||||||
|
|
||||||
|
var resourceId string = hash.JsonHashKey(req.FileKey)
|
||||||
|
|
||||||
|
var uploadUrl = UploadUrl{}
|
||||||
|
resourceModel := gmodel.NewFsResourceModel(l.svcCtx.MysqlConn)
|
||||||
|
resourceInfo, err := resourceModel.FindOneById(l.ctx, resourceId)
|
||||||
|
if err == nil && resourceInfo.ResourceId != "" {
|
||||||
|
uploadUrl.Status = 1
|
||||||
|
uploadUrl.ResourceId = resourceId
|
||||||
|
uploadUrl.ResourceUrl = *resourceInfo.ResourceUrl
|
||||||
|
} else {
|
||||||
|
dist, contentType, err := file.FileBase64ToByte(req.FileData)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,base64tobyte error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建S3对象存储请求
|
||||||
|
s3req, _ = svc.PutObjectRequest(
|
||||||
|
&s3.PutObjectInput{
|
||||||
|
Bucket: bucketName,
|
||||||
|
Key: &resourceId,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 设置请求体为文件数据
|
||||||
|
s3req.SetBufferBody(dist)
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
err = s3req.Send()
|
||||||
|
|
||||||
|
// 检查是否有错误
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
uploadUrl.Status = 0
|
||||||
|
} else {
|
||||||
|
var url = s3req.HTTPRequest.URL.String()
|
||||||
|
// 打印请求URL
|
||||||
|
logx.Info(url)
|
||||||
|
uploadUrl.Status = 1
|
||||||
|
uploadUrl.ResourceId = resourceId
|
||||||
|
uploadUrl.ResourceUrl = url
|
||||||
|
var version string = "0.0.1"
|
||||||
|
var nowTime = time.Now()
|
||||||
|
_, err = resourceModel.Create(l.ctx, &gmodel.FsResource{
|
||||||
|
ResourceId: resourceId,
|
||||||
|
UserId: &userId,
|
||||||
|
GuestId: &guestId,
|
||||||
|
ResourceType: &contentType,
|
||||||
|
ResourceUrl: &url,
|
||||||
|
Version: &version,
|
||||||
|
UploadedAt: &nowTime,
|
||||||
|
Metadata: &req.Metadata,
|
||||||
|
ApiType: &apiType,
|
||||||
|
BucketName: bucketName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回成功的响应和上传URL
|
||||||
|
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
|
||||||
|
"upload_data": uploadUrl,
|
||||||
|
})
|
||||||
|
}
|
259
server/upload/internal/logic/uploadfilesbackendlogic.go
Normal file
259
server/upload/internal/logic/uploadfilesbackendlogic.go
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"fusenapi/utils/hash"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/upload/internal/svc"
|
||||||
|
"fusenapi/server/upload/internal/types"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/request"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/core/mr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadFilesBackendLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUploadFilesBackendLogic(r *http.Request, svcCtx *svc.ServiceContext) *UploadFilesBackendLogic {
|
||||||
|
return &UploadFilesBackendLogic{
|
||||||
|
Logger: logx.WithContext(r.Context()),
|
||||||
|
ctx: r.Context(),
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
r: r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UploadFilesBackendLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UploadFilesBackendLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UploadFilesBackendLogic) UploadFilesBackend(req *types.UploadFilesReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
if userinfo.IsOnlooker() {
|
||||||
|
// 如果是,返回未授权的错误码
|
||||||
|
return resp.SetStatus(basic.CodeUnAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义用户ID和S3键名格式
|
||||||
|
var userId int64
|
||||||
|
var guestId int64
|
||||||
|
|
||||||
|
// 检查用户是否是游客
|
||||||
|
if userinfo.IsGuest() {
|
||||||
|
// 如果是,使用游客ID和游客键名格式
|
||||||
|
guestId = userinfo.GuestId
|
||||||
|
} else {
|
||||||
|
// 否则,使用用户ID和用户键名格式
|
||||||
|
userId = userinfo.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
var uploadInfoList []UploadInfo
|
||||||
|
err := json.Unmarshal([]byte(req.UploadInfo), &uploadInfoList)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,params Unmarshal failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileLen = len(uploadInfoList)
|
||||||
|
|
||||||
|
if fileLen == 0 {
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,no files")
|
||||||
|
}
|
||||||
|
if req.ApiType == 1 && fileLen > 100 {
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err, files count is beyond the maximum")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义存储桶名称
|
||||||
|
var bucketName *string
|
||||||
|
|
||||||
|
// 根据类别选择存储桶
|
||||||
|
switch req.UploadBucket {
|
||||||
|
case 2:
|
||||||
|
bucketName = basic.TempfileBucketName
|
||||||
|
default:
|
||||||
|
bucketName = basic.StorageBucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
//设置内存大小
|
||||||
|
l.r.ParseMultipartForm(32 << 20)
|
||||||
|
|
||||||
|
//获取上传的文件组
|
||||||
|
files := l.r.MultipartForm.File["file"]
|
||||||
|
|
||||||
|
// 设置AWS会话的区域
|
||||||
|
l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1")
|
||||||
|
|
||||||
|
// 创建新的S3服务实例
|
||||||
|
svc := s3.New(l.svcCtx.AwsSession)
|
||||||
|
|
||||||
|
// 定义S3请求和当前时间
|
||||||
|
var s3req *request.Request
|
||||||
|
|
||||||
|
resourceModel := gmodel.NewFsResourceModel(l.svcCtx.MysqlConn)
|
||||||
|
result, err := mr.MapReduce(func(source chan<- interface{}) {
|
||||||
|
for i, info := range uploadInfoList {
|
||||||
|
fileType := files[i].Header.Get("Content-Type")
|
||||||
|
// 打开文件
|
||||||
|
file, err := files[i].Open()
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
// 读取数据流
|
||||||
|
ioData, err := io.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一系列业务逻辑....验证类型,文件大小
|
||||||
|
|
||||||
|
var hashKey string = hash.JsonHashKey(info.FileKeys)
|
||||||
|
source <- UploadData{
|
||||||
|
FileKey: info.FileKeys,
|
||||||
|
FileType: fileType,
|
||||||
|
Metadata: info.Metadata,
|
||||||
|
FileData: ioData,
|
||||||
|
ApiType: req.ApiType,
|
||||||
|
Bucket: bucketName,
|
||||||
|
HashKey: hashKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||||
|
uploadDataInfo := item.(UploadData)
|
||||||
|
|
||||||
|
var uploadUrl = UploadUrl{}
|
||||||
|
uploadUrl.Key = uploadDataInfo.FileKey
|
||||||
|
uploadUrl.ApiType = uploadDataInfo.ApiType
|
||||||
|
uploadUrl.ResourceType = uploadDataInfo.FileType
|
||||||
|
|
||||||
|
var resourceId string = uploadDataInfo.HashKey
|
||||||
|
// 查询数据库
|
||||||
|
resourceInfo, err := resourceModel.FindOneById(l.ctx, resourceId)
|
||||||
|
if err == nil && resourceInfo.ResourceId != "" {
|
||||||
|
uploadUrl.Status = 1
|
||||||
|
uploadUrl.ResourceId = resourceId
|
||||||
|
uploadUrl.ResourceUrl = *resourceInfo.ResourceUrl
|
||||||
|
} else {
|
||||||
|
// 创建S3对象存储请求
|
||||||
|
s3req, _ = svc.PutObjectRequest(
|
||||||
|
&s3.PutObjectInput{
|
||||||
|
Bucket: uploadDataInfo.Bucket,
|
||||||
|
Key: &uploadDataInfo.HashKey,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// 设置请求体为文件数据
|
||||||
|
s3req.SetBufferBody(uploadDataInfo.FileData)
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
err = s3req.Send()
|
||||||
|
// 检查是否有错误
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
uploadUrl.Status = 0
|
||||||
|
} else {
|
||||||
|
contentType := http.DetectContentType(uploadDataInfo.FileData)
|
||||||
|
var url = s3req.HTTPRequest.URL.String()
|
||||||
|
// 打印请求URL
|
||||||
|
logx.Info(url)
|
||||||
|
uploadUrl.Status = 1
|
||||||
|
uploadUrl.ResourceId = resourceId
|
||||||
|
uploadUrl.ResourceUrl = url
|
||||||
|
var version string = "0.0.1"
|
||||||
|
var nowTime = time.Now()
|
||||||
|
_, err = resourceModel.Create(l.ctx, &gmodel.FsResource{
|
||||||
|
ResourceId: resourceId,
|
||||||
|
UserId: &userId,
|
||||||
|
GuestId: &guestId,
|
||||||
|
ResourceType: &contentType,
|
||||||
|
ResourceUrl: &url,
|
||||||
|
Version: &version,
|
||||||
|
UploadedAt: &nowTime,
|
||||||
|
Metadata: &uploadDataInfo.Metadata,
|
||||||
|
ApiType: &uploadDataInfo.ApiType,
|
||||||
|
BucketName: bucketName,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notice 这个必须加!
|
||||||
|
writer.Write(uploadUrl)
|
||||||
|
}, func(pipe <-chan interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||||
|
var uploadUrlList = make(map[string][]*UploadUrl)
|
||||||
|
var uploadUrlListFail []*UploadUrl
|
||||||
|
var uploadUrlListSuccess []*UploadUrl
|
||||||
|
for p := range pipe {
|
||||||
|
var uploadUrl = p.(UploadUrl)
|
||||||
|
if uploadUrl.Status == 1 {
|
||||||
|
uploadUrlListSuccess = append(uploadUrlListSuccess, &uploadUrl)
|
||||||
|
} else {
|
||||||
|
uploadUrlListFail = append(uploadUrlListFail, &uploadUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notice 这个必须加!
|
||||||
|
uploadUrlList["success"] = uploadUrlListSuccess
|
||||||
|
uploadUrlList["fail"] = uploadUrlListFail
|
||||||
|
writer.Write(uploadUrlList)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回成功的响应和上传URL
|
||||||
|
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
|
||||||
|
"upload_data": result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadInfo struct {
|
||||||
|
FileSize int64 `json:"file_size"` // 上传文件大小
|
||||||
|
FileKeys string `json:"file_keys"` // 上传文件唯一标识
|
||||||
|
FileData *string `json:"file_data"` // 上传文件Base64
|
||||||
|
Metadata string `json:"meta_data"` // 上传文件额外信息
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadData struct {
|
||||||
|
ApiType int64 `json:"api_type"`
|
||||||
|
FileSize int64 `json:"file_size"`
|
||||||
|
FileType string `json:"file_type"`
|
||||||
|
FileKey string `json:"file_key"`
|
||||||
|
Metadata string `json:"metadata"`
|
||||||
|
Bucket *string `json:"bucket"`
|
||||||
|
HashKey string `json:"hash_key"`
|
||||||
|
FileData []byte `fsfile:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadUrl struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
ApiType int64 `json:"api_type"`
|
||||||
|
ResourceId string `json:"resource_id"`
|
||||||
|
ResourceType string `json:"resource_type"`
|
||||||
|
ResourceUrl string `json:"resource_url"`
|
||||||
|
}
|
149
server/upload/internal/logic/uploadfilesfrontendlogic.go
Normal file
149
server/upload/internal/logic/uploadfilesfrontendlogic.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"fusenapi/utils/hash"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/upload/internal/svc"
|
||||||
|
"fusenapi/server/upload/internal/types"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"github.com/zeromicro/go-zero/core/mr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadFilesFrontendLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUploadFilesFrontendLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadFilesFrontendLogic {
|
||||||
|
return &UploadFilesFrontendLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UploadFilesFrontendLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UploadFilesFrontendLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UploadFilesFrontendLogic) UploadFilesFrontend(req *types.UploadFilesReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
|
||||||
|
var uploadInfoList []UploadInfo
|
||||||
|
err := json.Unmarshal([]byte(req.UploadInfo), &uploadInfoList)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,params Unmarshal failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileLen = len(uploadInfoList)
|
||||||
|
|
||||||
|
if fileLen == 0 {
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,no files")
|
||||||
|
}
|
||||||
|
if req.ApiType == 1 && fileLen > 100 {
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadErr, "file upload err, files count is beyond the maximum")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义存储桶名称
|
||||||
|
var bucketName *string
|
||||||
|
|
||||||
|
// 根据类别选择存储桶
|
||||||
|
switch req.UploadBucket {
|
||||||
|
case 2:
|
||||||
|
bucketName = basic.TempfileBucketName
|
||||||
|
default:
|
||||||
|
bucketName = basic.StorageBucketName
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置AWS会话的区域
|
||||||
|
l.svcCtx.AwsSession.Config.Region = aws.String("us-west-1")
|
||||||
|
|
||||||
|
// 创建新的S3服务实例
|
||||||
|
svc := s3.New(l.svcCtx.AwsSession)
|
||||||
|
|
||||||
|
result, err := mr.MapReduce(func(source chan<- interface{}) {
|
||||||
|
for _, info := range uploadInfoList {
|
||||||
|
if info.FileSize <= 1024*1024*500 {
|
||||||
|
// 一系列业务逻辑....验证类型,文件大小
|
||||||
|
var hashKey string = hash.JsonHashKey(info.FileKeys)
|
||||||
|
source <- UploadData{
|
||||||
|
FileKey: info.FileKeys,
|
||||||
|
FileSize: info.FileSize,
|
||||||
|
Bucket: bucketName,
|
||||||
|
HashKey: hashKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||||
|
uploadDataInfo := item.(UploadData)
|
||||||
|
|
||||||
|
var uploadUrl = UploadUrl{}
|
||||||
|
uploadUrl.Key = uploadDataInfo.FileKey
|
||||||
|
uploadUrl.ApiType = uploadDataInfo.ApiType
|
||||||
|
uploadUrl.ResourceType = uploadDataInfo.FileType
|
||||||
|
|
||||||
|
s3req, _ := svc.PutObjectRequest(
|
||||||
|
&s3.PutObjectInput{
|
||||||
|
Bucket: uploadDataInfo.Bucket,
|
||||||
|
Key: &uploadDataInfo.HashKey,
|
||||||
|
ContentLength: aws.Int64(uploadDataInfo.FileSize),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
url, err := s3req.Presign(time.Minute * 5)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
uploadUrl.Status = 0
|
||||||
|
} else {
|
||||||
|
// 打印请求URL
|
||||||
|
logx.Info(url)
|
||||||
|
uploadUrl.Status = 1
|
||||||
|
uploadUrl.ResourceUrl = url
|
||||||
|
uploadUrl.ResourceId = uploadDataInfo.HashKey
|
||||||
|
}
|
||||||
|
// Notice 这个必须加!
|
||||||
|
writer.Write(uploadUrl)
|
||||||
|
}, func(pipe <-chan interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||||
|
var uploadUrlList = make(map[string][]*UploadUrl)
|
||||||
|
var uploadUrlListFail []*UploadUrl
|
||||||
|
var uploadUrlListSuccess []*UploadUrl
|
||||||
|
for p := range pipe {
|
||||||
|
var uploadUrl = p.(UploadUrl)
|
||||||
|
if uploadUrl.Status == 1 {
|
||||||
|
uploadUrlListSuccess = append(uploadUrlListSuccess, &uploadUrl)
|
||||||
|
} else {
|
||||||
|
uploadUrlListFail = append(uploadUrlListFail, &uploadUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notice 这个必须加!
|
||||||
|
uploadUrlList["success"] = uploadUrlListSuccess
|
||||||
|
uploadUrlList["fail"] = uploadUrlListFail
|
||||||
|
writer.Write(uploadUrlList)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回成功的响应和上传URL
|
||||||
|
return resp.SetStatus(basic.CodeOK, map[string]interface{}{
|
||||||
|
"upload_urls": result,
|
||||||
|
})
|
||||||
|
}
|
144
server/upload/internal/logic/uploadlogologic.go
Normal file
144
server/upload/internal/logic/uploadlogologic.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fusenapi/model/gmodel"
|
||||||
|
"fusenapi/utils/auth"
|
||||||
|
"fusenapi/utils/basic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"fusenapi/server/upload/internal/svc"
|
||||||
|
"fusenapi/server/upload/internal/types"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UploadLogoLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUploadLogoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadLogoLogic {
|
||||||
|
return &UploadLogoLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理进入前逻辑w,r
|
||||||
|
// func (l *UploadLogoLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
||||||
|
// func (l *UploadLogoLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
||||||
|
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (l *UploadLogoLogic) UploadLogo(req *types.UploadLogoReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
||||||
|
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
|
||||||
|
// userinfo 传入值时, 一定不为null
|
||||||
|
if userinfo.IsOnlooker() {
|
||||||
|
// 如果是,返回未授权的错误码
|
||||||
|
return resp.SetStatus(basic.CodeUnAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId int64
|
||||||
|
var guestId int64
|
||||||
|
|
||||||
|
// 检查用户是否是游客
|
||||||
|
if userinfo.IsGuest() {
|
||||||
|
// 如果是,使用游客ID和游客键名格式
|
||||||
|
guestId = userinfo.GuestId
|
||||||
|
} else {
|
||||||
|
// 否则,使用用户ID和用户键名格式
|
||||||
|
userId = userinfo.UserId
|
||||||
|
}
|
||||||
|
|
||||||
|
var logoWidth int64
|
||||||
|
var logoHeight int64
|
||||||
|
// 查看sku是否存在
|
||||||
|
if req.SkuId > 0 {
|
||||||
|
// 查询出产品模板信息
|
||||||
|
productTemplateV2Model := gmodel.NewFsProductTemplateV2Model(l.svcCtx.MysqlConn)
|
||||||
|
productTemplateV2Info, err := productTemplateV2Model.FindOne(l.ctx, req.SkuId)
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadLogoErr, "logo upload err,no product template")
|
||||||
|
}
|
||||||
|
|
||||||
|
logoWidth = *productTemplateV2Info.LogoWidth
|
||||||
|
logoHeight = *productTemplateV2Info.LogoHeight
|
||||||
|
}
|
||||||
|
// 设置默认宽高
|
||||||
|
if logoWidth == 0 || logoHeight == 0 {
|
||||||
|
logoWidth = 300
|
||||||
|
logoHeight = 200
|
||||||
|
}
|
||||||
|
var resultStr string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// apiUrl := l.svcCtx.Config.BLMService.ImageProcess.Url
|
||||||
|
// var onlyScale = true
|
||||||
|
// data := url.Values{}
|
||||||
|
// data.Set("imgurl", req.ResourceUrl)
|
||||||
|
// data.Set("layerwidth", strconv.Itoa(int(logoWidth)))
|
||||||
|
// data.Set("layerheight", strconv.Itoa(int(logoHeight)))
|
||||||
|
// data.Set("is_remove_bg", strconv.Itoa(int(req.IsRemoveBg)))
|
||||||
|
// data.Set("proportion", strconv.Itoa(int(req.Proportion)))
|
||||||
|
// data.Set("only_scale", fmt.Sprintf("%v", onlyScale))
|
||||||
|
|
||||||
|
// u, err := url.ParseRequestURI(apiUrl)
|
||||||
|
// if err != nil {
|
||||||
|
// logx.Error(err)
|
||||||
|
// return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||||
|
// }
|
||||||
|
// u.RawQuery = data.Encode() // URL encode
|
||||||
|
// fmt.Println(u.String())
|
||||||
|
// result, err := http.Get(u.String())
|
||||||
|
// if err != nil {
|
||||||
|
// logx.Error(err)
|
||||||
|
// return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||||
|
// }
|
||||||
|
// defer result.Body.Close()
|
||||||
|
// b, err := io.ReadAll(result.Body)
|
||||||
|
// if err != nil {
|
||||||
|
// logx.Error(err)
|
||||||
|
// return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||||
|
// }
|
||||||
|
// resultStr = string(b)
|
||||||
|
|
||||||
|
// // 上传图片
|
||||||
|
// var reqs types.UploadFileBaseReq
|
||||||
|
// reqs.ApiType = 2
|
||||||
|
// reqs.UploadBucket = 2
|
||||||
|
// reqs.Metadata = ""
|
||||||
|
// reqs.FileData = ""
|
||||||
|
// reqs.FileKey = ""
|
||||||
|
|
||||||
|
// // 创建一个业务逻辑层实例
|
||||||
|
// resUpload := NewUploadFileBaseLogic(l.ctx, l.svcCtx).UploadFileBase(&reqs, userinfo)
|
||||||
|
|
||||||
|
var module = "logo"
|
||||||
|
var nowTime = time.Now().Unix()
|
||||||
|
// 新增记录
|
||||||
|
userMaterialModel := gmodel.NewFsUserMaterialModel(l.svcCtx.MysqlConn)
|
||||||
|
_, err = userMaterialModel.CreateOrUpdate(l.ctx, &gmodel.FsUserMaterial{
|
||||||
|
Module: &module,
|
||||||
|
UserId: &userId,
|
||||||
|
GuestId: &guestId,
|
||||||
|
ResourceId: &req.ResourceId,
|
||||||
|
ResourceUrl: &req.ResourceUrl,
|
||||||
|
Metadata: &resultStr,
|
||||||
|
CreateAt: &nowTime,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logx.Error(err)
|
||||||
|
return resp.SetStatus(basic.CodeFileUploadLogoErr, "service fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.SetStatus(basic.CodeOK)
|
||||||
|
}
|
@ -5,6 +5,45 @@ import (
|
|||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UploadFileBaseReq struct {
|
||||||
|
ApiType int64 `form:"api_type,options=[1,2],default=1"` // 调用类型:1=对外,2=对内
|
||||||
|
FileKey string `form:"file_key"` // 上传唯一标识信息
|
||||||
|
FileData string `form:"file_data"` // 上传文件额外信息
|
||||||
|
Metadata string `form:"meta_data,optional"` // 上传文件额外信息
|
||||||
|
UserId int64 `form:"user_id,optional"` // 上传文件额外信息
|
||||||
|
GuestId int64 `form:"guest_id,optional"` // 上传文件额外信息
|
||||||
|
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadLogoReq struct {
|
||||||
|
ResourceId string `form:"resource_id"` // 资源ID
|
||||||
|
ResourceUrl string `form:"resource_url"` // 资源URL
|
||||||
|
IsRemoveBg int64 `form:"is_remove_bg"` // 是否要去掉背景
|
||||||
|
Proportion int64 `form:"proportion,default=60"` // 贴图在模型面板上的比例
|
||||||
|
SkuId int64 `form:"sku_id,default=0"` // 模板ID
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadInfo struct {
|
||||||
|
FileSize int64 `form:"file_size,optional"` // 上传唯一标识信息
|
||||||
|
FileKeys string `form:"file_keys,optional"` // 上传唯一标识信息
|
||||||
|
Metadata string `form:"meta_data,optional"` // 上传文件额外信息
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadCallbackReq struct {
|
||||||
|
UploadBucket int64 `form:"upload_bucket,options=[1,2],default=1"` // 上传桶名:1=缓存,2=持久
|
||||||
|
ResourceId string `form:"resource_id"` // 资源ID
|
||||||
|
ResourceType string `form:"resource_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=对内
|
||||||
|
}
|
||||||
|
|
||||||
type RequestUpFile struct {
|
type RequestUpFile struct {
|
||||||
UpFile string `form:"upfile"`
|
UpFile string `form:"upfile"`
|
||||||
IsCut string `form:"is_cut"` // 是否裁剪
|
IsCut string `form:"is_cut"` // 是否裁剪
|
||||||
|
6
server/webset/Dockerfile
Executable file
6
server/webset/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-webset-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-webset-srv"]
|
6
server/websocket/Dockerfile
Executable file
6
server/websocket/Dockerfile
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
|
||||||
|
WORKDIR /www/fusenapi/
|
||||||
|
COPY ./bin/api-websocket-srv /www/fusenapi/
|
||||||
|
COPY ./etc /www/fusenapi/etc
|
||||||
|
CMD ["/www/fusenapi/api-websocket-srv"]
|
@ -2,6 +2,7 @@ Name: websocket
|
|||||||
Host: 0.0.0.0
|
Host: 0.0.0.0
|
||||||
Port: 9914
|
Port: 9914
|
||||||
ReplicaId: 75
|
ReplicaId: 75
|
||||||
|
Timeout: 15000 #服务超时时间
|
||||||
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
SourceMysql: fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest
|
||||||
Auth:
|
Auth:
|
||||||
AccessSecret: fusen2023
|
AccessSecret: fusen2023
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fusenapi/server/websocket/internal/logic"
|
|
||||||
"fusenapi/server/websocket/internal/svc"
|
|
||||||
"fusenapi/server/websocket/internal/types"
|
|
||||||
"fusenapi/utils/basic"
|
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RenderNotifyHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req types.RenderNotifyReq
|
|
||||||
_, err := basic.RequestParse(w, r, svcCtx.SharedState, &req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 创建一个业务逻辑层实例
|
|
||||||
l := logic.NewRenderNotifyLogic(r.Context(), svcCtx)
|
|
||||||
|
|
||||||
rl := reflect.ValueOf(l)
|
|
||||||
basic.BeforeLogic(w, r, rl)
|
|
||||||
|
|
||||||
resp := l.RenderNotify(&req)
|
|
||||||
|
|
||||||
if !basic.AfterLogic(w, r, rl, resp) {
|
|
||||||
basic.NormalAfterLogic(w, r, resp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,16 +17,6 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
Path: "/api/websocket/data_transfer",
|
Path: "/api/websocket/data_transfer",
|
||||||
Handler: DataTransferHandler(serverCtx),
|
Handler: DataTransferHandler(serverCtx),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Method: http.MethodPost,
|
|
||||||
Path: "/api/websocket/render_notify",
|
|
||||||
Handler: RenderNotifyHandler(serverCtx),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Method: http.MethodPost,
|
|
||||||
Path: "/api/websocket/third_party_login_notify",
|
|
||||||
Handler: ThirdPartyLoginNotifyHandler(serverCtx),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@ package logic
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"fusenapi/constants"
|
"fusenapi/constants"
|
||||||
"fusenapi/initalize"
|
"fusenapi/initalize"
|
||||||
"fusenapi/server/websocket/internal/types"
|
|
||||||
"fusenapi/utils/auth"
|
"fusenapi/utils/auth"
|
||||||
"fusenapi/utils/id_generator"
|
"fusenapi/utils/id_generator"
|
||||||
|
"fusenapi/utils/websocket_data"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
@ -72,6 +71,7 @@ type wsConnectItem struct {
|
|||||||
inChan chan []byte //接受消息缓冲通道
|
inChan chan []byte //接受消息缓冲通道
|
||||||
outChan chan []byte //发送回客户端的消息
|
outChan chan []byte //发送回客户端的消息
|
||||||
mutex sync.Mutex //互斥锁
|
mutex sync.Mutex //互斥锁
|
||||||
|
userId int64
|
||||||
renderProperty renderProperty //扩展云渲染属性
|
renderProperty renderProperty //扩展云渲染属性
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,10 +84,14 @@ func (l *DataTransferLogic) DataTransfer(svcCtx *svc.ServiceContext, w http.Resp
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
//鉴权不成功10秒后断开
|
//鉴权不成功10秒后断开
|
||||||
/*isAuth, _ := l.checkAuth(svcCtx, r)
|
var (
|
||||||
|
userInfo *auth.UserInfo
|
||||||
|
isAuth bool
|
||||||
|
)
|
||||||
|
isAuth, userInfo = l.checkAuth(svcCtx, r)
|
||||||
if !isAuth {
|
if !isAuth {
|
||||||
time.Sleep(time.Second) //兼容下火狐
|
time.Sleep(time.Second) //兼容下火狐
|
||||||
rsp := types.DataTransferData{
|
rsp := websocket_data.DataTransferData{
|
||||||
T: constants.WEBSOCKET_UNAUTH,
|
T: constants.WEBSOCKET_UNAUTH,
|
||||||
D: nil,
|
D: nil,
|
||||||
}
|
}
|
||||||
@ -97,7 +101,7 @@ func (l *DataTransferLogic) DataTransfer(svcCtx *svc.ServiceContext, w http.Resp
|
|||||||
//发送关闭信息
|
//发送关闭信息
|
||||||
_ = conn.WriteMessage(websocket.CloseMessage, nil)
|
_ = conn.WriteMessage(websocket.CloseMessage, nil)
|
||||||
return
|
return
|
||||||
}*/
|
}
|
||||||
//生成连接唯一标识
|
//生成连接唯一标识
|
||||||
uniqueId := websocketIdGenerator.Get()
|
uniqueId := websocketIdGenerator.Get()
|
||||||
ws := wsConnectItem{
|
ws := wsConnectItem{
|
||||||
@ -108,10 +112,15 @@ func (l *DataTransferLogic) DataTransfer(svcCtx *svc.ServiceContext, w http.Resp
|
|||||||
inChan: make(chan []byte, 1000),
|
inChan: make(chan []byte, 1000),
|
||||||
outChan: make(chan []byte, 1000),
|
outChan: make(chan []byte, 1000),
|
||||||
renderProperty: renderProperty{
|
renderProperty: renderProperty{
|
||||||
renderImageTask: make(map[string]struct{}),
|
renderImageTask: make(map[string]string),
|
||||||
renderImageTaskCtlChan: make(chan renderImageControlChanItem, 100),
|
renderImageTaskCtlChan: make(chan renderImageControlChanItem, 100),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if userInfo.UserId > 0 {
|
||||||
|
ws.userId = userInfo.UserId
|
||||||
|
} else {
|
||||||
|
ws.userId = userInfo.GuestId
|
||||||
|
}
|
||||||
//保存连接
|
//保存连接
|
||||||
mapConnPool.Store(uniqueId, ws)
|
mapConnPool.Store(uniqueId, ws)
|
||||||
defer ws.close()
|
defer ws.close()
|
||||||
@ -146,10 +155,13 @@ func (l *DataTransferLogic) checkAuth(svcCtx *svc.ServiceContext, r *http.Reques
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
} else {
|
//不是登录用户也不是游客
|
||||||
|
if !userInfo.IsUser() && !userInfo.IsGuest() {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return true, userInfo
|
return true, userInfo
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 心跳
|
// 心跳
|
||||||
@ -247,14 +259,9 @@ func (w *wsConnectItem) sendToOutChan(data []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取需要渲染图片的map key
|
|
||||||
func (w *wsConnectItem) getRenderImageMapKey(productId, templateTagId, logoId int64, algorithmVersion string) string {
|
|
||||||
return fmt.Sprintf("%d-%d-%d-%s", productId, templateTagId, logoId, algorithmVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 格式化返回数据
|
// 格式化返回数据
|
||||||
func (w *wsConnectItem) respondDataFormat(msgType string, data interface{}) []byte {
|
func (w *wsConnectItem) respondDataFormat(msgType string, data interface{}) []byte {
|
||||||
d := types.DataTransferData{
|
d := websocket_data.DataTransferData{
|
||||||
T: msgType,
|
T: msgType,
|
||||||
D: data,
|
D: data,
|
||||||
}
|
}
|
||||||
@ -264,7 +271,7 @@ func (w *wsConnectItem) respondDataFormat(msgType string, data interface{}) []by
|
|||||||
|
|
||||||
// 处理接受到的数据
|
// 处理接受到的数据
|
||||||
func (w *wsConnectItem) dealwithReciveData(data []byte) {
|
func (w *wsConnectItem) dealwithReciveData(data []byte) {
|
||||||
var parseInfo types.DataTransferData
|
var parseInfo websocket_data.DataTransferData
|
||||||
if err := json.Unmarshal(data, &parseInfo); err != nil {
|
if err := json.Unmarshal(data, &parseInfo); err != nil {
|
||||||
logx.Error("invalid format of websocket message")
|
logx.Error("invalid format of websocket message")
|
||||||
w.outChan <- w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket message:"+string(data))
|
w.outChan <- w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket message:"+string(data))
|
||||||
@ -275,7 +282,7 @@ func (w *wsConnectItem) dealwithReciveData(data []byte) {
|
|||||||
switch parseInfo.T {
|
switch parseInfo.T {
|
||||||
//图片渲染
|
//图片渲染
|
||||||
case constants.WEBSOCKET_RENDER_IMAGE:
|
case constants.WEBSOCKET_RENDER_IMAGE:
|
||||||
w.SendToCloudRender(d)
|
w.renderImage(d)
|
||||||
default:
|
default:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
53
server/websocket/internal/logic/mq_consumer.go
Normal file
53
server/websocket/internal/logic/mq_consumer.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
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 {
|
||||||
|
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
|
||||||
|
}
|
@ -1,78 +0,0 @@
|
|||||||
package logic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fusenapi/constants"
|
|
||||||
"fusenapi/utils/auth"
|
|
||||||
"fusenapi/utils/basic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"fusenapi/server/websocket/internal/svc"
|
|
||||||
"fusenapi/server/websocket/internal/types"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ThirdPartyLoginNotifyLogic struct {
|
|
||||||
logx.Logger
|
|
||||||
ctx context.Context
|
|
||||||
svcCtx *svc.ServiceContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewThirdPartyLoginNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ThirdPartyLoginNotifyLogic {
|
|
||||||
return &ThirdPartyLoginNotifyLogic{
|
|
||||||
Logger: logx.WithContext(ctx),
|
|
||||||
ctx: ctx,
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理进入前逻辑w,r
|
|
||||||
// func (l *ThirdPartyLoginNotifyLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
|
|
||||||
// func (l *ThirdPartyLoginNotifyLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
|
|
||||||
// // httpx.OkJsonCtx(r.Context(), w, resp)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (l *ThirdPartyLoginNotifyLogic) ThirdPartyLoginNotify(req *types.ThirdPartyLoginNotifyReq, userinfo *auth.UserInfo) (resp *basic.Response) {
|
|
||||||
if time.Now().Unix()-120 > req.Time /*|| req.Time > time.Now().Unix() */ {
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param: time is invalid")
|
|
||||||
}
|
|
||||||
if req.Info.WebsocketId <= 0 {
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:websocket_id is required")
|
|
||||||
}
|
|
||||||
if req.Info.Token == "" {
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "err param:token is required")
|
|
||||||
}
|
|
||||||
//验证签名 sha256
|
|
||||||
/*notifyByte, _ := json.Marshal(req.Info)
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write([]byte(fmt.Sprintf(constants.THIRD_PARTY_LOGIN_NOTIFY_SIGN_KEY, string(notifyByte), req.Time)))
|
|
||||||
signHex := h.Sum(nil)
|
|
||||||
sign := hex.EncodeToString(signHex)
|
|
||||||
//fmt.Println(sign)
|
|
||||||
if req.Sign != sign {
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "invalid sign")
|
|
||||||
}*/
|
|
||||||
//查询对应websocket连接
|
|
||||||
val, ok := mapConnPool.Load(req.Info.WebsocketId)
|
|
||||||
if !ok {
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeOK, "success:websocket connection is not exists")
|
|
||||||
}
|
|
||||||
ws, ok := val.(wsConnectItem)
|
|
||||||
if !ok {
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeServiceErr, "type of websocket connect object is err")
|
|
||||||
}
|
|
||||||
b := ws.respondDataFormat(constants.WEBSOCKET_THIRD_PARTY_LOGIN_NOTIFY, types.ThirdPartyLoginRspMsg{
|
|
||||||
Token: req.Info.Token,
|
|
||||||
})
|
|
||||||
select {
|
|
||||||
case <-ws.closeChan:
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeOK, "websocket connect object is closed")
|
|
||||||
case ws.outChan <- b:
|
|
||||||
return resp.SetStatusWithMessage(basic.CodeOK, "success")
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,20 +3,53 @@ package logic
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fusenapi/constants"
|
"fusenapi/constants"
|
||||||
"fusenapi/server/websocket/internal/types"
|
"fusenapi/utils/hash"
|
||||||
|
"fusenapi/utils/websocket_data"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 云渲染属性
|
// 云渲染属性
|
||||||
type renderProperty struct {
|
type renderProperty struct {
|
||||||
renderImageTask map[string]struct{} //需要渲染的图片任务
|
renderImageTask map[string]string //需要渲染的图片任务 key是taskId val 是renderId
|
||||||
renderImageTaskCtlChan chan renderImageControlChanItem //渲染任务新增移除的控制通道
|
renderImageTaskCtlChan chan renderImageControlChanItem //渲染任务新增移除的控制通道
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染任务新增移除的控制通道的数据
|
// 渲染任务新增移除的控制通道的数据
|
||||||
type renderImageControlChanItem struct {
|
type renderImageControlChanItem struct {
|
||||||
Option int // 0删除 1添加
|
Option int // 0删除 1添加
|
||||||
Key string //map的key
|
TaskId string //map的key
|
||||||
|
RenderId string // map的val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染发送到组装数据组装数据
|
||||||
|
func (w *wsConnectItem) renderImage(data []byte) {
|
||||||
|
var renderImageData websocket_data.RenderImageReqMsg
|
||||||
|
if err := json.Unmarshal(data, &renderImageData); err != nil {
|
||||||
|
w.outChan <- w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket render image message:"+string(data))
|
||||||
|
logx.Error("invalid format of websocket render image message", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logx.Info("收到请求云渲染图片数据:", renderImageData)
|
||||||
|
renderImageData.RenderData.UserId = w.userId
|
||||||
|
//把需要渲染的图片任务加进去
|
||||||
|
taskId := hash.JsonHashKey(renderImageData.RenderData)
|
||||||
|
w.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{
|
||||||
|
Option: 1, //0删除 1添加
|
||||||
|
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(data), "err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logx.Info("发送渲染数据到rabbitmq成功:", string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 操作连接中渲染任务的增加/删除
|
// 操作连接中渲染任务的增加/删除
|
||||||
@ -28,43 +61,10 @@ func (w *wsConnectItem) operationRenderTask() {
|
|||||||
case data := <-w.renderProperty.renderImageTaskCtlChan:
|
case data := <-w.renderProperty.renderImageTaskCtlChan:
|
||||||
switch data.Option {
|
switch data.Option {
|
||||||
case 0: //删除任务
|
case 0: //删除任务
|
||||||
delete(w.renderProperty.renderImageTask, data.Key)
|
delete(w.renderProperty.renderImageTask, data.TaskId)
|
||||||
case 1: //新增任务
|
case 1: //新增任务
|
||||||
w.renderProperty.renderImageTask[data.Key] = struct{}{}
|
w.renderProperty.renderImageTask[data.TaskId] = data.RenderId
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染请求数据处理发送云渲染服务处理
|
|
||||||
func (w *wsConnectItem) SendToCloudRender(data []byte) {
|
|
||||||
var renderImageData types.RenderImageReqMsg
|
|
||||||
if err := json.Unmarshal(data, &renderImageData); err != nil {
|
|
||||||
w.outChan <- w.respondDataFormat(constants.WEBSOCKET_ERR_DATA_FORMAT, "invalid format of websocket render image message:"+string(data))
|
|
||||||
logx.Error("invalid format of websocket render image message", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logx.Info("收到请求云渲染图片数据:", renderImageData)
|
|
||||||
//把需要渲染的图片任务加进去
|
|
||||||
for _, productId := range renderImageData.ProductIds {
|
|
||||||
select {
|
|
||||||
case <-w.closeChan: //连接关闭了
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
//加入渲染任务
|
|
||||||
key := w.getRenderImageMapKey(productId, renderImageData.TemplateTagId, renderImageData.LogoId, renderImageData.AlgorithmVersion)
|
|
||||||
w.renderProperty.renderImageTaskCtlChan <- renderImageControlChanItem{
|
|
||||||
Option: 1, //0删除 1添加
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
//发送给对应的流水线组装数据
|
|
||||||
if err := w.rabbitMq.SendMsg(constants.RABBIT_MQ_ASSEMBLE_RENDER_DATA, data); err != nil {
|
|
||||||
logx.Error("发送渲染任务数据到MQ失败:", string(data))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logx.Info("发送渲染数据到rabbitmq成功:", string(data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -5,55 +5,6 @@ import (
|
|||||||
"fusenapi/utils/basic"
|
"fusenapi/utils/basic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DataTransferData struct {
|
|
||||||
T string `json:"t"` //消息类型
|
|
||||||
D interface{} `json:"d"` //传递的消息
|
|
||||||
}
|
|
||||||
|
|
||||||
type RenderImageReqMsg struct {
|
|
||||||
ProductIds []int64 `json:"product_ids"` //产品 id
|
|
||||||
TemplateTagId int64 `json:"template_tag_id"` //模板标签id
|
|
||||||
LogoId int64 `json:"logo_id"` //logoid
|
|
||||||
AlgorithmVersion string `json:"algorithm_version,optional"` //算法版本
|
|
||||||
}
|
|
||||||
|
|
||||||
type RenderImageRspMsg struct {
|
|
||||||
ProductId int64 `json:"product_id"` //产品 id
|
|
||||||
TemplateTagId int64 `json:"template_tag_id"` //模板标签id
|
|
||||||
AlgorithmVersion string `json:"algorithm_version,optional"` //算法版本
|
|
||||||
LogoId int64 `json:"logo_id"` //logoid
|
|
||||||
Image string `json:"image"` //渲染后的图片
|
|
||||||
}
|
|
||||||
|
|
||||||
type ThirdPartyLoginRspMsg struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RenderNotifyReq struct {
|
|
||||||
Sign string `json:"sign"`
|
|
||||||
Time int64 `json:"time"`
|
|
||||||
Info NotifyInfo `json:"info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotifyInfo struct {
|
|
||||||
ProductId int64 `json:"product_id"` //产品id
|
|
||||||
TemplateTagId int64 `json:"template_tag_id"` //模板标签id
|
|
||||||
AlgorithmVersion string `json:"algorithm_version,optional"` //算法版本
|
|
||||||
LogoId int64 `json:"logo_id"` //logoid
|
|
||||||
Image string `json:"image"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ThirdPartyLoginNotifyReq struct {
|
|
||||||
Sign string `json:"sign"`
|
|
||||||
Time int64 `json:"time"`
|
|
||||||
Info ThirdPartyLoginNotify `json:"info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ThirdPartyLoginNotify struct {
|
|
||||||
WebsocketId uint64 `json:"websocket_id"`
|
|
||||||
Token string `json:"token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"fusenapi/constants"
|
||||||
|
"fusenapi/server/websocket/internal/logic"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
|
|
||||||
"fusenapi/utils/auth"
|
"fusenapi/utils/auth"
|
||||||
|
|
||||||
@ -23,14 +25,18 @@ func main() {
|
|||||||
|
|
||||||
var c config.Config
|
var c config.Config
|
||||||
conf.MustLoad(*configFile, &c)
|
conf.MustLoad(*configFile, &c)
|
||||||
c.Timeout = int64(time.Second * 15)
|
|
||||||
server := rest.MustNewServer(c.RestConf, rest.WithCustomCors(auth.FsCors, func(w http.ResponseWriter) {
|
server := rest.MustNewServer(c.RestConf, rest.WithCustomCors(auth.FsCors, func(w http.ResponseWriter) {
|
||||||
}))
|
}))
|
||||||
defer server.Stop()
|
defer server.Stop()
|
||||||
|
|
||||||
ctx := svc.NewServiceContext(c)
|
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)
|
handler.RegisterHandlers(server, ctx)
|
||||||
|
|
||||||
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
||||||
server.Start()
|
server.Start()
|
||||||
}
|
}
|
||||||
|
@ -56,8 +56,29 @@ service home-user-auth {
|
|||||||
@handler UserOrderCancelHandler
|
@handler UserOrderCancelHandler
|
||||||
get /api/user/order-cancel (UserOrderCancelReq) returns (response);
|
get /api/user/order-cancel (UserOrderCancelReq) returns (response);
|
||||||
|
|
||||||
|
// 用户logo列表
|
||||||
|
@handler UserLogoListHandler
|
||||||
|
get /api/user/logo-list (UserLogoListReq) returns (response);
|
||||||
|
|
||||||
|
// 再来一单
|
||||||
|
@handler UserAgainOrderHandler
|
||||||
|
get /api/user/one-more-order (UserAgainOrderReq) returns (response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
UserAgainOrderReq {
|
||||||
|
Sn string `form:"sn"` // 订单编号
|
||||||
|
}
|
||||||
|
UserAgainOrderRes struct{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
UserLogoListReq {
|
||||||
|
}
|
||||||
|
UserLogoListRes {
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
UserOrderDeleteReq {
|
UserOrderDeleteReq {
|
||||||
ID int64 `form:"id"` //订单id
|
ID int64 `form:"id"` //订单id
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user