|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"github.com/afex/hystrix-go/hystrix"
|
|
|
|
consul "github.com/asim/go-micro/plugins/registry/consul/v4"
|
|
|
|
"github.com/dtm-labs/dtm/client/dtmcli"
|
|
|
|
"github.com/go-micro/plugins/v4/wrapper/select/roundrobin"
|
|
|
|
opentracing2 "github.com/go-micro/plugins/v4/wrapper/trace/opentracing"
|
|
|
|
"github.com/lithammer/shortuuid/v3"
|
|
|
|
"github.com/opentracing/opentracing-go"
|
|
|
|
"go-micro.dev/v4/client"
|
|
|
|
"go-micro.dev/v4/web"
|
|
|
|
"goproduct/common"
|
|
|
|
"goproduct/proto"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"go-micro.dev/v4"
|
|
|
|
"go-micro.dev/v4/registry"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 获取远程服务的客户端
|
|
|
|
func main() {
|
|
|
|
const (
|
|
|
|
//DTM 服务地址
|
|
|
|
DtmServer = "http://192.168.100.131:36789/api/dtmsvr"
|
|
|
|
QSBusi = "http://192.168.1.135:6668" //注意
|
|
|
|
)
|
|
|
|
var CartId int32 = 1
|
|
|
|
var Number int32 = 1
|
|
|
|
resp := &proto.AddCartResp{}
|
|
|
|
|
|
|
|
router := gin.Default()
|
|
|
|
|
|
|
|
//注册到consul
|
|
|
|
consulReg := consul.NewRegistry(func(options *registry.Options) {
|
|
|
|
options.Addrs = []string{"192.168.100.131:8500"}
|
|
|
|
})
|
|
|
|
//初始化链路追踪的jaeper
|
|
|
|
t, io, err := common.NewTracer("shop-cart-client", "192.168.100.131:6831")
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
defer io.Close()
|
|
|
|
opentracing.SetGlobalTracer(t)
|
|
|
|
|
|
|
|
//熔断器
|
|
|
|
hystrixStreamHandler := hystrix.NewStreamHandler()
|
|
|
|
hystrixStreamHandler.Start()
|
|
|
|
go func() {
|
|
|
|
err := http.ListenAndServe(net.JoinHostPort("192.168.100.1", "9096"), hystrixStreamHandler)
|
|
|
|
if err != nil {
|
|
|
|
log.Panic(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
rpcServer := micro.NewService(
|
|
|
|
//micro.Name("shop-product-client"),
|
|
|
|
micro.Registry(consulReg), //服务发现
|
|
|
|
micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),
|
|
|
|
//加入熔断器
|
|
|
|
micro.WrapClient(NewClientHystrixWrapper()),
|
|
|
|
//负载均衡
|
|
|
|
micro.WrapClient(roundrobin.NewClientWrapper()),
|
|
|
|
)
|
|
|
|
AddCartClient := proto.NewAddCartService("shop-cart", rpcServer.Client())
|
|
|
|
UpdateCartClient := proto.NewUpdateCartService("shop-cart", rpcServer.Client())
|
|
|
|
ShowProductDetailClient := proto.NewShowProductDetailService("shop-product", rpcServer.Client())
|
|
|
|
ShowDetailSkuClient := proto.NewShowDetailSkuService("shop-product", rpcServer.Client())
|
|
|
|
GetUserTokenClient := proto.NewGetUserTokenService("shop-user", rpcServer.Client())
|
|
|
|
UpdateSkuClient := proto.NewUpdateSkuService("shop-product", rpcServer.Client())
|
|
|
|
|
|
|
|
//添加购物车
|
|
|
|
router.GET("/increase", func(c *gin.Context) {
|
|
|
|
number, _ := strconv.Atoi(c.Request.FormValue("number"))
|
|
|
|
productId, _ := strconv.Atoi(c.Request.FormValue("productId"))
|
|
|
|
productSkuId, _ := strconv.Atoi(c.Request.FormValue("productSkuId"))
|
|
|
|
uuid := c.Request.Header["Uuid"][0]
|
|
|
|
cc := common.GetInput(uuid)
|
|
|
|
out := common.SQ(cc)
|
|
|
|
sum := 0
|
|
|
|
for o := range out {
|
|
|
|
sum += o
|
|
|
|
}
|
|
|
|
//Token校验
|
|
|
|
//拼接请求信息
|
|
|
|
tokenReq := &proto.TokenReq{
|
|
|
|
Uuid: uuid,
|
|
|
|
}
|
|
|
|
//响应
|
|
|
|
tokenResp, err := GetUserTokenClient.GetUserToken(context.TODO(), tokenReq)
|
|
|
|
//拼接请求信息
|
|
|
|
respErr := &proto.AddCartResp{}
|
|
|
|
if err != nil || tokenResp.IsLogin == false {
|
|
|
|
log.Println("GetUserToken err : ", err)
|
|
|
|
common.RespFail(c.Writer, respErr, "未登录!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Println("GetUserToken success : ", tokenResp)
|
|
|
|
|
|
|
|
//拼接请求信息
|
|
|
|
req := &proto.AddCartReq{
|
|
|
|
Number: int32(number),
|
|
|
|
ProductId: int32(productId),
|
|
|
|
ProductSkuId: int32(productSkuId),
|
|
|
|
UserId: int32(sum),
|
|
|
|
}
|
|
|
|
resp := &proto.AddCartResp{}
|
|
|
|
//商品详情
|
|
|
|
reqDetail := &proto.ProductDetailReq{
|
|
|
|
Id: int32(productId),
|
|
|
|
}
|
|
|
|
respDetail, err := ShowProductDetailClient.ShowProductDetail(context.TODO(), reqDetail)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("ShowProductDetail err : ", err)
|
|
|
|
common.RespFail(c.Writer, respErr, "查询商品详情失败!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respDetail != nil {
|
|
|
|
req.ProductName = respDetail.ProductDetail[0].Name
|
|
|
|
req.ProductMainPicture = respDetail.ProductDetail[0].MainPicture
|
|
|
|
}
|
|
|
|
|
|
|
|
//log.Println(" /ShowProductDetail resp :", respDetail)
|
|
|
|
//SKU详情
|
|
|
|
reqDetail.Id = req.ProductSkuId
|
|
|
|
respSkuDetail, err := ShowDetailSkuClient.ShowDetailSku(context.TODO(), reqDetail)
|
|
|
|
//log.Println(" /ShowDetailSku resp :", respSkuDetail)
|
|
|
|
//添加购物车 远程调用服务
|
|
|
|
//log.Println(" /AddCart req :", req)
|
|
|
|
|
|
|
|
if respSkuDetail.ProductSku[0].Stock < req.Number {
|
|
|
|
common.RespFail(c.Writer, &proto.AddCartResp{}, "库存不足,添加失败")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
sku := respSkuDetail.ProductSku[0]
|
|
|
|
sku.Stock -= req.Number
|
|
|
|
updateSkuReq := &proto.UpdateSkuReq{
|
|
|
|
ProductSku: sku,
|
|
|
|
}
|
|
|
|
respUpdate, err := UpdateSkuClient.UpdateSku(context.TODO(), updateSkuReq)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(" /UpdateSku err :", err)
|
|
|
|
common.RespFail(c.Writer, resp, "修改库存失败!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Println(" /UpdateSkuClient resp :", respUpdate.IsSuccess)
|
|
|
|
//开始增加购物车
|
|
|
|
resp, err = AddCartClient.AddCart(context.TODO(), req)
|
|
|
|
//根据响应做输出
|
|
|
|
if err != nil {
|
|
|
|
log.Println("addCart err ", err)
|
|
|
|
updateSkuReq.ProductSku.Stock += req.Number
|
|
|
|
_, err = UpdateSkuClient.UpdateSku(context.TODO(), updateSkuReq)
|
|
|
|
log.Println("rollback sku is Err :", err)
|
|
|
|
common.RespFail(c.Writer, resp, "添加购物车失败!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
resp.ProductSkuSimple = respSkuDetail.ProductSku[0]
|
|
|
|
resp.ProductSimple = respDetail.ProductDetail[0]
|
|
|
|
log.Println(" /AddCart resp :", resp)
|
|
|
|
////writer data message row total field
|
|
|
|
common.RespOK(c.Writer, resp, "请求成功")
|
|
|
|
})
|
|
|
|
|
|
|
|
//开始拆分 DTM服务
|
|
|
|
//
|
|
|
|
router.POST("/updateSku", func(c *gin.Context) {
|
|
|
|
req := &proto.UpdateSkuReq{}
|
|
|
|
if err := c.BindJSON(req); err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
_, err := UpdateSkuClient.UpdateSku(context.TODO(), req)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("/updateSku err ", err)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "修改库存失败!"})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"updateSku": "SUCCESS", "Message": "修改库存成功!"})
|
|
|
|
})
|
|
|
|
router.POST("/updateSku-compensate", func(c *gin.Context) {
|
|
|
|
req := &proto.UpdateSkuReq{}
|
|
|
|
if err := c.BindJSON(req); err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
req.ProductSku.Stock += Number
|
|
|
|
_, err := UpdateSkuClient.UpdateSku(context.TODO(), req)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("/updateSku err ", err)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "回滚库存失败!"})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"updateSku-compensate": "SUCCESS", "Message": "回滚库存成功!"})
|
|
|
|
})
|
|
|
|
router.POST("/addCart", func(c *gin.Context) {
|
|
|
|
req := &proto.AddCartReq{}
|
|
|
|
if err := c.BindJSON(req); err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
resp, err = AddCartClient.AddCart(context.TODO(), req)
|
|
|
|
CartId = resp.ID
|
|
|
|
//测试异常
|
|
|
|
//err = errors.New("400", "测试异常", 400)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("/addCart err ", err)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "新增购物车失败!"})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{"addCart": "SUCCESS", "Message": "新增购物车成功!"})
|
|
|
|
})
|
|
|
|
router.POST("/addCart-compensate", func(c *gin.Context) {
|
|
|
|
req := &proto.AddCartReq{}
|
|
|
|
if err := c.BindJSON(req); err != nil {
|
|
|
|
log.Fatalln(err)
|
|
|
|
}
|
|
|
|
req.Id = CartId
|
|
|
|
resp, err = UpdateCartClient.UpdateCart(context.TODO(), req)
|
|
|
|
CartId = resp.ID
|
|
|
|
if err != nil {
|
|
|
|
log.Println("/addCart-compensate err ", err)
|
|
|
|
c.JSON(http.StatusOK, gin.H{"dtm_reslut": "FAILURE", "Message": "删除购物车失败!"})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"addCart-compensate": "SUCCESS", "Message": "删除购物车成功!"})
|
|
|
|
})
|
|
|
|
|
|
|
|
router.GET("/addShoppingCart", func(c *gin.Context) {
|
|
|
|
number, _ := strconv.Atoi(c.Request.FormValue("number"))
|
|
|
|
productId, _ := strconv.Atoi(c.Request.FormValue("productId"))
|
|
|
|
productSkuId, _ := strconv.Atoi(c.Request.FormValue("productSkuId"))
|
|
|
|
uuid := c.Request.Header["Uuid"][0]
|
|
|
|
cc := common.GetInput(uuid)
|
|
|
|
out := common.SQ(cc)
|
|
|
|
sum := 0
|
|
|
|
for o := range out {
|
|
|
|
sum += o
|
|
|
|
}
|
|
|
|
//Token校验
|
|
|
|
//拼接请求信息
|
|
|
|
tokenReq := &proto.TokenReq{
|
|
|
|
Uuid: uuid,
|
|
|
|
}
|
|
|
|
//响应
|
|
|
|
tokenResp, err := GetUserTokenClient.GetUserToken(context.TODO(), tokenReq)
|
|
|
|
//拼接请求信息
|
|
|
|
respErr := &proto.AddCartResp{}
|
|
|
|
if err != nil || tokenResp.IsLogin == false {
|
|
|
|
log.Println("GetUserToken err : ", err)
|
|
|
|
common.RespFail(c.Writer, respErr, "未登录!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Println("GetUserToken success : ", tokenResp)
|
|
|
|
|
|
|
|
//拼接请求信息
|
|
|
|
req := &proto.AddCartReq{
|
|
|
|
Number: int32(number),
|
|
|
|
ProductId: int32(productId),
|
|
|
|
ProductSkuId: int32(productSkuId),
|
|
|
|
UserId: int32(sum),
|
|
|
|
}
|
|
|
|
resp := &proto.AddCartResp{}
|
|
|
|
//商品详情
|
|
|
|
reqDetail := &proto.ProductDetailReq{
|
|
|
|
Id: int32(productId),
|
|
|
|
}
|
|
|
|
respDetail, err := ShowProductDetailClient.ShowProductDetail(context.TODO(), reqDetail)
|
|
|
|
if err != nil {
|
|
|
|
log.Println("ShowProductDetail err : ", err)
|
|
|
|
common.RespFail(c.Writer, respErr, "查询商品详情失败!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if respDetail != nil {
|
|
|
|
req.ProductName = respDetail.ProductDetail[0].Name
|
|
|
|
req.ProductMainPicture = respDetail.ProductDetail[0].MainPicture
|
|
|
|
}
|
|
|
|
|
|
|
|
//log.Println(" /ShowProductDetail resp :", respDetail)
|
|
|
|
//SKU详情
|
|
|
|
reqDetail.Id = req.ProductSkuId
|
|
|
|
respSkuDetail, err := ShowDetailSkuClient.ShowDetailSku(context.TODO(), reqDetail)
|
|
|
|
//log.Println(" /ShowDetailSku resp :", respSkuDetail)
|
|
|
|
//添加购物车 远程调用服务
|
|
|
|
//log.Println(" /AddCart req :", req)
|
|
|
|
|
|
|
|
if respSkuDetail.ProductSku[0].Stock < req.Number {
|
|
|
|
common.RespFail(c.Writer, &proto.AddCartResp{}, "库存不足,添加失败")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
sku := respSkuDetail.ProductSku[0]
|
|
|
|
sku.Stock -= req.Number
|
|
|
|
Number = req.Number //
|
|
|
|
updateSkuReq := &proto.UpdateSkuReq{
|
|
|
|
ProductSku: sku,
|
|
|
|
}
|
|
|
|
resp.ProductSkuSimple = respSkuDetail.ProductSku[0]
|
|
|
|
resp.ProductSimple = respDetail.ProductDetail[0]
|
|
|
|
|
|
|
|
//全局事务
|
|
|
|
gid := shortuuid.New()
|
|
|
|
saga := dtmcli.NewSaga(DtmServer, gid).
|
|
|
|
Add(QSBusi+"/updateSku", QSBusi+"/updateSku-compensate", updateSkuReq).
|
|
|
|
Add(QSBusi+"/addCart", QSBusi+"/addCart-compensate", req)
|
|
|
|
err = saga.Submit()
|
|
|
|
if err != nil {
|
|
|
|
log.Println("saga submit err :", err)
|
|
|
|
common.RespFail(c.Writer, resp, "添加失败")
|
|
|
|
}
|
|
|
|
log.Println(" /saga submit submit :", gid)
|
|
|
|
////writer data message row total field
|
|
|
|
common.RespOK(c.Writer, resp, "请求成功")
|
|
|
|
})
|
|
|
|
|
|
|
|
service := web.NewService(
|
|
|
|
web.Address(":6668"),
|
|
|
|
web.Name("shop-cart-client"),
|
|
|
|
web.Registry(consulReg),
|
|
|
|
web.Handler(router),
|
|
|
|
)
|
|
|
|
//启动服务
|
|
|
|
service.Run()
|
|
|
|
}
|
|
|
|
|
|
|
|
type clientWrapper struct {
|
|
|
|
client.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c clientWrapper) Call(ctx context.Context, req client.Request, resp interface{}, opts ...client.CallOption) error {
|
|
|
|
return hystrix.Do(req.Service()+"."+req.Endpoint(), func() error {
|
|
|
|
//正常执行
|
|
|
|
fmt.Println("call success ", req.Service()+"."+req.Endpoint())
|
|
|
|
return c.Client.Call(ctx, req, resp, opts...)
|
|
|
|
}, func(err error) error {
|
|
|
|
fmt.Println("call err :", err)
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewClientHystrixWrapper() client.Wrapper {
|
|
|
|
return func(i client.Client) client.Client {
|
|
|
|
return &clientWrapper{i}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|