From 2d3aded2ef1d95656c290792e46f0273bbc488ee Mon Sep 17 00:00:00 2001 From: wuchao <1272174216@qq.com> Date: Mon, 17 Jun 2024 14:10:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0--=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/constants/errorcode/error_code.go | 13 +- app/http/controllers/base.go | 3 + app/http/middlewares/base.go | 39 ++- app/http/routes/route.go | 1 + app/third/market/config.go | 90 ++++++ app/third/market/market_api.go | 62 +++++ app/third/market/market_api_test.go | 34 +++ app/third/market/rsa.go | 137 +++++++++ app/third/openapiService/openapi_service.go | 164 +++++++++++ app/utils/sm2/sm2.go | 160 +++++++++++ app/utils/util.go | 290 +++++++++++++++++++- config/config.go | 41 +++ go.mod | 21 +- go.sum | 25 +- main.go | 5 +- 15 files changed, 1066 insertions(+), 19 deletions(-) create mode 100644 app/third/market/config.go create mode 100644 app/third/market/market_api.go create mode 100644 app/third/market/market_api_test.go create mode 100644 app/third/market/rsa.go create mode 100644 app/third/openapiService/openapi_service.go create mode 100644 app/utils/sm2/sm2.go diff --git a/app/constants/errorcode/error_code.go b/app/constants/errorcode/error_code.go index e7d5380..9d16981 100644 --- a/app/constants/errorcode/error_code.go +++ b/app/constants/errorcode/error_code.go @@ -18,6 +18,9 @@ const ( //系统错误 SystemError = 500 + + //未登录 + NotLogin = 1000 ) var MsgEN = map[int]string{ @@ -28,7 +31,15 @@ var MsgEN = map[int]string{ NotFound: "not found", SystemError: "system error", } -var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgEN} + +var MsgZH = map[int]string{ + Success: "请求成功", + ParamError: "参数错误", + NotFound: "数据不存在", + NotAuth: "未经授权", + NotLogin: "未登录", +} +var MsgMap map[string]map[int]string = map[string]map[int]string{"en": MsgZH} func GetMsg(code int, local string) string { if local == "" { diff --git a/app/http/controllers/base.go b/app/http/controllers/base.go index 71d54d0..887be73 100644 --- a/app/http/controllers/base.go +++ b/app/http/controllers/base.go @@ -150,6 +150,9 @@ func HandRes(c *gin.Context, data interface{}, err error) { } } func HandCodeRes(c *gin.Context, data interface{}, code int) { + if utils.IsNil(data) { + data = struct{}{} + } if code == errorcode.Success { Success(c, data, errorcode.GetMsg(code, c.GetHeader("local"))) } else { diff --git a/app/http/middlewares/base.go b/app/http/middlewares/base.go index c333221..f992a6c 100644 --- a/app/http/middlewares/base.go +++ b/app/http/middlewares/base.go @@ -15,22 +15,45 @@ import ( func Auth() gin.HandlerFunc { return func(c *gin.Context) { - var token = c.GetHeader("token") - //将token放入redis - var playerId, err = redis.GetRedis().Get(context.Background(), utils.GetRealKey(common.TOKEN_PRE+token)).Result() - if rs, errRedis := redis.GetRedis().SIsMember(context.Background(), "disabled_uids", playerId).Result(); errRedis == nil && rs { - err = errors.New(errorcode.GetMsg(errorcode.NotFound, "")) - redis.GetRedis().SRem(context.Background(), "disabled_uids", playerId) + c.ClientIP() + var tokens = strings.SplitN(c.GetHeader("Authorization"), " ", 2) + if len(tokens) != 2 || tokens[0] != "Bearer" { + controllers.HandCodeRes(c, nil, errorcode.NotLogin) + c.Abort() + return + } + // 验证token + token, claims, err := utils.ParseToken(tokens[1]) + if err != nil || !token.Valid { + controllers.HandCodeRes(c, nil, errorcode.NotAuth) + c.Abort() + return } if err == nil { - c.Set("playerId", playerId) + c.Set("userId", claims.Id) + c.Set("phone", claims.Phone) c.Next() return } else { - controllers.HandCodeRes(c, nil, errorcode.Forbidden) + controllers.HandCodeRes(c, nil, errorcode.NotAuth) c.Abort() } + } +} +func Cors() gin.HandlerFunc { + return func(c *gin.Context) { + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") + c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, platform,Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control,token, X-Requested-With") + c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE") + + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(204) + return + } + + c.Next() } } diff --git a/app/http/routes/route.go b/app/http/routes/route.go index 5972f7a..54b5230 100644 --- a/app/http/routes/route.go +++ b/app/http/routes/route.go @@ -40,6 +40,7 @@ func RegisterRoute(router *gin.Engine) { } } + router.Use(middlewares.Cors()) router.NoRoute(controllers.Error404) //api版本 diff --git a/app/third/market/config.go b/app/third/market/config.go new file mode 100644 index 0000000..b75ad06 --- /dev/null +++ b/app/third/market/config.go @@ -0,0 +1,90 @@ +package market + +import ( + "bytes" + "encoding/json" + "github.com/pkg/errors" + "io/ioutil" + "net/http" + "qteam/config" +) + +type MarketClient struct { + cfg config.MarketConfig +} + +type MarketSendRequest struct { + AppId string `json:"app_id"` //APP ID + Sign string `json:"sign"` //签名 + ReqCode string `json:"req_code"` //固定值:voucher.create + MemId string `json:"mem_id"` //商户号 + ReqSerialNo string `json:"req_serial_no"` //请求唯一流水号 最大32位 + TimeTamp string `json:"timestamp"` //时间戳 yyyyMMddHHmmss + PosId string `json:"pos_id"` //商户方平台号 + VoucherId string `json:"voucher_id"` //制码批次号 + VoucherNum int `json:"voucher_num"` //请券数量,默认是 1 + MobileNo string `json:"mobile_no"` //11 手机号,可传空字符串 + SendMsg string `json:"send_msg"` //是否发送短信:2- 发送 1-不发送 +} + +type MarketSenResponse struct { + VoucherId string `json:"voucher_id"` //制码批次号 + VoucherCode string `json:"voucher_code"` //券码 + ShortUrl string `json:"short_url"` //含二维码、条码的短链接 + VoucherSdate string `json:"voucher_sdate"` //有效期起 + VoucherEdate string `json:"voucher_edate"` //有效期止 + CodeType string `json:"code_type"` //码类型: 00- 代金券 01- 满减券 +} + +type MarketResponse struct { + ErrCode string `json:"errCode"` //00-成功 其他:失败 + Msg string `json:"msg"` //描 述 (失败时必填) + Data MarketSenResponse `json:"data"` +} + +func (this *MarketSendRequest) toMap() (resultMap map[string]interface{}) { + // Marshal the struct to JSON, ignoring omitempty fields. + jsonBytes, err := json.Marshal(this) + if err != nil { + return + } + // Unmarshal the JSON into a map to get the final result. + err = json.Unmarshal(jsonBytes, &resultMap) + if err != nil { + return + } + + return resultMap +} + +func (this *MarketClient) doPost(url string, jsonBytes []byte) (body []byte, err error) { + // 创建POST请求 + url = this.cfg.Host + url + req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBytes)) + if err != nil { + return + } + + // 设置Content-Type头 + req.Header.Set("Content-Type", "application/json") + + // 创建HTTP客户端 + client := &http.Client{} + + // 发送请求并处理响应 + resp, err := client.Do(req) + if err != nil { + return + } + defer resp.Body.Close() + // 读取响应体 + if resp.StatusCode != http.StatusOK { + err = errors.New("HTTP request failed: " + resp.Status) + return + } + body, err = ioutil.ReadAll(resp.Body) + if err != nil { + return + } + return +} diff --git a/app/third/market/market_api.go b/app/third/market/market_api.go new file mode 100644 index 0000000..ddf0605 --- /dev/null +++ b/app/third/market/market_api.go @@ -0,0 +1,62 @@ +package market + +import ( + "encoding/json" + "qteam/app/utils/encrypt" + "qteam/config" + "time" +) + +func NewMarketClient(cfg config.MarketConfig) *MarketClient { + cfg.Sign = "-----BEGIN RSA PRIVATE KEY-----\n" + cfg.Sign + "\n-----END RSA PRIVATE KEY-----" + return &MarketClient{ + cfg: cfg, + } +} + +/* +MarketSend +券码生成接口 +- 请求地址:/openApi/v1/market/key/send +- 说明:发券接口应支持使用同一流水号进行重复请求,即:当调用该接口失败时,可 以使用同一流水号进行再次请求,接口需要根据请求的流水号进行判断,若无该流水 号的券码信息则新生成后返回,若有该流水号的券码信息则直接返回该券码的信息 +orderNo: 订单号 +VoucherId: 制码批次号 +MobileNo: 11 手机号,可传空字符串 +SendMsg: 是否发送短信:2- 发送 1-不发送 +*/ +func (this *MarketClient) MarketSend(orderNo, VoucherId, MobileNo, SendMsg string) (res MarketResponse, err error) { + url := "/openApi/v1/market/key/send" + request := MarketSendRequest{ + AppId: this.cfg.AppId, + ReqCode: this.cfg.ReqCode, + MemId: this.cfg.MemId, + PosId: this.cfg.PosId, + TimeTamp: time.Now().Format("20060102150405"), + VoucherId: VoucherId, + ReqSerialNo: orderNo, + VoucherNum: 1, + MobileNo: MobileNo, + SendMsg: SendMsg, + } + + request.Sign, err = MakeRsaSign(this.cfg.Sign, request.toMap()) + if err != nil { + return res, err + } + + bytes, err := json.Marshal(request) + if err != nil { + return res, err + } + + data, err := this.doPost(url, bytes) + if err != nil { + return res, err + } + err = json.Unmarshal(data, &res) + // 加密 + if len(res.Data.ShortUrl) > 0 { + res.Data.ShortUrl = encrypt.AesEncryptCBC([]byte(res.Data.ShortUrl), []byte(this.cfg.SecretKey)) + } + return res, err +} diff --git a/app/third/market/market_api_test.go b/app/third/market/market_api_test.go new file mode 100644 index 0000000..6dca249 --- /dev/null +++ b/app/third/market/market_api_test.go @@ -0,0 +1,34 @@ +package market + +import ( + "fmt" + "github.com/qit-team/snow-core/kernel/server" + "os" + "qteam/app/utils" + "qteam/config" + "testing" +) + +func TestMarketSendRequest_Market(t *testing.T) { + opts := config.GetOptions() + if opts.ShowVersion { + fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate) + os.Exit(0) + } + + //加载配置 + conf, err := config.Load(opts.ConfFile) + if err != nil { + utils.Log(nil, "err", err.Error()) + return + } + client := NewMarketClient(conf.OpenApiMarketConfig) + + //data, err := client.MarketSend("123456789111", "1717567048171", "", "2") + data, err := client.MarketSend("123111", "1717", "", "2") + + if err != nil { + t.Error(err) + } + t.Log(data) +} diff --git a/app/third/market/rsa.go b/app/third/market/rsa.go new file mode 100644 index 0000000..1389433 --- /dev/null +++ b/app/third/market/rsa.go @@ -0,0 +1,137 @@ +package market + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "sort" +) + +// getSignString 使用 xx=aa&yy=bb 的字符串拼接 +func getSignString(data map[string]interface{}) string { + keys := make([]string, 0, len(data)) + for key := range data { + keys = append(keys, key) + } + sort.Strings(keys) + + signString := "" + separator := "" + for _, key := range keys { + value := data[key] + if key == "sign" || value == nil { + continue + } + signString += fmt.Sprintf("%s%s=%v", separator, key, value) + separator = "&" + } + return signString +} + +// VerifyRsaSign 签名验证 +func VerifyRsaSign(publicKey string, data map[string]interface{}) (map[string]interface{}, error) { + // 对 sign nonce timestamp appId 升序排序 + // 使用 xx=aa&yy=bb 的字符串拼接 + // 商户的公钥验签 RSA2验签 + signString := getSignString(data) + + rsaPubKey, err := parseRSAPublicKeyFromPEM([]byte(publicKey)) + if err != nil { + return nil, err + } + + signature, err := base64.StdEncoding.DecodeString(data["sign"].(string)) + if err != nil { + return nil, err + } + + hashed := sha256.Sum256([]byte(signString)) + err = rsa.VerifyPKCS1v15(rsaPubKey, crypto.SHA256, hashed[:], signature) + if err != nil { + return nil, errors.New("签名验证失败") + } + + return data, nil +} + +// MakeRsaSign 生成签名 +func MakeRsaSign(privateKey string, data map[string]interface{}) (string, error) { + // 对 sign nonce timestamp appId 升序排序 + // 使用 xx=aa&yy=bb 的字符串拼接 + // 营销系统生成的私钥生成签名 RSA2加签 + signString := getSignString(data) + + privKey, err := parseRSAPrivateKeyFromPEM([]byte(privateKey)) + if err != nil { + return "", errors.New("私钥解析失败") + } + + hashed := sha256.Sum256([]byte(signString)) + signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hashed[:]) + if err != nil { + return "", errors.New("签名失败") + } + + return base64.StdEncoding.EncodeToString(signature), nil +} + +// ParseRSAPrivateKeyFromPEM 解析私钥 +func parseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) { + var err error + + // Parse PEM block + var block *pem.Block + if block, _ = pem.Decode(key); block == nil { + return nil, errors.New("私钥解析失败: 无效的PEM格式") + } + + var parsedKey interface{} + if parsedKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil { + if parsedKey, err = x509.ParsePKCS8PrivateKey(block.Bytes); err != nil { + return nil, err + } + } + + var pkey *rsa.PrivateKey + var ok bool + if pkey, ok = parsedKey.(*rsa.PrivateKey); !ok { + return nil, errors.New("密钥不是有效的RSA私钥") + } + + return pkey, nil +} + +// parseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key +func parseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) { + var err error + + // Parse PEM block + var block *pem.Block + if block, _ = pem.Decode(key); block == nil { + return nil, errors.New("公钥解析失败: 无效的PEM格式") + } + + // Parse the key + var parsedKey interface{} + if parsedKey, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil { + if cert, err := x509.ParseCertificate(block.Bytes); err == nil { + parsedKey = cert.PublicKey + } else { + return nil, err + } + } + + var pkey *rsa.PublicKey + var ok bool + if pkey, ok = parsedKey.(*rsa.PublicKey); !ok { + return nil, errors.New("密钥不是有效的RSA公钥") + } + + return pkey, nil +} diff --git a/app/third/openapiService/openapi_service.go b/app/third/openapiService/openapi_service.go new file mode 100644 index 0000000..64be38b --- /dev/null +++ b/app/third/openapiService/openapi_service.go @@ -0,0 +1,164 @@ +package openapiService + +import ( + "context" + "crypto/aes" + "encoding/base64" + "gitee.com/chengdu_blue_brothers/openapi-go-sdk/api" + "gitee.com/chengdu_blue_brothers/openapi-go-sdk/notify" + "net/http" + "qteam/app/models/orderdetailsmodel" + "qteam/app/models/ordersmodel" + "qteam/app/models/usercouponmodel" + "qteam/app/utils" + "qteam/config" + "time" +) + +func CreatClient() (client *api.Client, err error) { + merchantId := config.GetConf().OpenApi.MerchantId + secretKey := config.GetConf().OpenApi.SecretKey + isProd := config.GetConf().OpenApi.IsProd + timeout := 10 * time.Second // 请求超时时间 + + client, err = api.NewClient(merchantId, secretKey, isProd, timeout) + if err != nil { + return nil, err + } + return client, nil +} + +type RechargeOrderReq struct { + OutTradeNo string + ProductId int + RechargeAccount string + AccountType int + Number int +} + +func RechargeOrder(rechargeOrderReq RechargeOrderReq) (result *api.RechargeOrderResp, err error) { + req := &api.RechargeOrderReq{ + OutTradeNo: rechargeOrderReq.OutTradeNo, + ProductId: rechargeOrderReq.ProductId, + RechargeAccount: rechargeOrderReq.RechargeAccount, + AccountType: 0, + Number: 1, + NotifyUrl: config.GetConf().OpenApi.NotifyUrl, + } + client, err := CreatClient() + if err != nil { + return nil, err + } + result, err = client.RechargeOrder(context.Background(), req) + if err != nil { + return nil, err + } + if result.Code != api.CodeCreateOrderSuccess { + return + } + return +} + +func ReCardOrder(CardOrderReq api.CardOrderReq) (result *api.CardOrderResp, err error) { + req := &api.CardOrderReq{ + OutTradeNo: CardOrderReq.OutTradeNo, + ProductId: CardOrderReq.ProductId, + AccountType: 0, + Number: 1, + NotifyUrl: config.GetConf().OpenApi.NotifyUrl, + } + client, err := CreatClient() + if err != nil { + return nil, err + } + result, err = client.CardOrder(context.Background(), req) + if err != nil { + return nil, err + } + if result.Code != api.CodeCreateOrderSuccess { + return + } + return +} + +func DecryptCard(encCode string) (decode string, err error) { + defer func() error { + if r := recover(); r != nil { + utils.Log(nil, "解密错误", err) + + } + return err + }() + client, err := CreatClient() + if err != nil { + return + } + decryptedCode, err := decryptAES(encCode, client.GetSecretKey()) + if err != nil { + return + } + return decryptedCode, nil +} + +// AES 解密 +func decryptAES(encryptedData string, secretKey string) (string, error) { + // 第一步:对加密的卡密做base64 decode + encryptedBytes, err := base64.StdEncoding.DecodeString(encryptedData) + if err != nil { + return "", err + } + + // 第二步:使用aes-256-ecb解密 + cipher, _ := aes.NewCipher([]byte(secretKey)) + decrypted := make([]byte, len(encryptedBytes)) + size := 16 + for bs, be := 0, size; bs < len(encryptedBytes); bs, be = bs+size, be+size { + cipher.Decrypt(decrypted[bs:be], encryptedBytes[bs:be]) + } + paddingSize := int(decrypted[len(decrypted)-1]) + return string(decrypted[0 : len(decrypted)-paddingSize]), nil +} + +func ParseAndVerify(request *http.Request) (req *notify.OrderReq, err error) { + // 第一步:初使化client实例 + merchantId := config.GetConf().OpenApi.MerchantId + secretKey := config.GetConf().OpenApi.SecretKey + client := notify.NewNotify(merchantId, secretKey) + + // 第二步:验签并解析结果 + req, err = client.ParseAndVerify(request) + if err != nil { + return nil, err + } + return +} + +// NotifyOperation /** +func NotifyOperation(order ordersmodel.Orders, req *notify.OrderReq) (err error) { + var session = ordersmodel.GetInstance().GetDb().NewSession() + session.Begin() + updateOrder := ordersmodel.Orders{Status: 3} + _, err = session.Where("Id = ?", order.Id).Update(&updateOrder) + if err != nil { + session.Rollback() + return + } + //卡密 + if req.CardCode != "" { + //订单详情 + updateOrderDetail := orderdetailsmodel.OrderDetails{Url: req.CardCode.Value()} + _, err = session.Where("OrderId = ?", order.Id).Update(&updateOrderDetail) + if err != nil { + session.Rollback() + return + } + userCouponDetail := usercouponmodel.UserCoupon{OrderInfo: req.CardCode.Value()} + _, err = session.Where("OrderId = ?", order.Id).Update(&userCouponDetail) + if err != nil { + session.Rollback() + return + } + } + session.Commit() + return +} diff --git a/app/utils/sm2/sm2.go b/app/utils/sm2/sm2.go new file mode 100644 index 0000000..9f40a90 --- /dev/null +++ b/app/utils/sm2/sm2.go @@ -0,0 +1,160 @@ +package sm2 + +import ( + "crypto/rand" + "encoding/base64" + "encoding/hex" + "fmt" + "github.com/tjfoc/gmsm/sm2" + "math/big" + "qteam/config" + "strings" +) + +// 生成公钥、私钥 +func GenerateSM2Key() (PublicKey string, PrivateKey string, err error) { + // 生成私钥、公钥 + privKey, err := sm2.GenerateKey(rand.Reader) + if err != nil { + fmt.Println("生成密钥对失败:", err) + return "", "", err + } + return PublicKeyToString(&privKey.PublicKey), PrivateKeyToString(privKey), nil +} + +// PublicKeyToString 公钥sm2.PublicKey转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用) +func PublicKeyToString(publicKey *sm2.PublicKey) string { + xBytes := publicKey.X.Bytes() + yBytes := publicKey.Y.Bytes() + + // 确保坐标字节切片长度相同 + byteLen := len(xBytes) + if len(yBytes) > byteLen { + byteLen = len(yBytes) + } + + // 为坐标补齐前导零 + xBytes = append(make([]byte, byteLen-len(xBytes)), xBytes...) + yBytes = append(make([]byte, byteLen-len(yBytes)), yBytes...) + + // 添加 "04" 前缀 + publicKeyBytes := append([]byte{0x04}, append(xBytes, yBytes...)...) + + return strings.ToUpper(hex.EncodeToString(publicKeyBytes)) +} + +// PrivateKeyToString 私钥sm2.PrivateKey 转字符串(与java中org.bouncycastle.crypto生成的公私钥完全互通使用) +func PrivateKeyToString(privateKey *sm2.PrivateKey) string { + return strings.ToUpper(hex.EncodeToString(privateKey.D.Bytes())) +} + +func SM2Decrypt(cipherText string) (string, error) { + if cipherText == "" { + return "", nil + } + decodedBytes, err := base64.StdEncoding.DecodeString(cipherText) + if err != nil { + fmt.Println("解码错误:", err) + return "", nil + } + decrypt, err := decryptLoc(config.GetConf().Sm2.PublicKey, config.GetConf().Sm2.PrivateKey, string(decodedBytes)) + if err != nil { + return "", err + } + return decrypt, nil +} + +func SM2Encrypt(cipherText string) (string, error) { + if cipherText == "" { + return "", nil + } + decrypt, err := encryptLoc(config.GetConf().Sm2.PublicKey, cipherText) + if err != nil { + return "", err + } + return decrypt, nil +} + +func encryptLoc(publicKeyStr, data string) (string, error) { + publicKeyObj, err := StringToPublicKey(publicKeyStr) + if err != nil { + fmt.Println(err) + } + decrypt, err := sm2.Encrypt(publicKeyObj, []byte(data), rand.Reader, sm2.C1C2C3) + if err != nil { + fmt.Println(err) + } + resultStr := hex.EncodeToString(decrypt) + return base64.StdEncoding.EncodeToString([]byte(resultStr)), nil +} + +func decryptLoc(publicKeyStr, privateKeyStr, cipherText string) (string, error) { + publicKeyObj, err := StringToPublicKey(publicKeyStr) + if err != nil { + fmt.Println(err) + } + privateKeyObj, err := StringToPrivateKey(privateKeyStr, publicKeyObj) + if err != nil { + fmt.Println(err) + } + decodeString, err := hex.DecodeString(cipherText) + decrypt, err := sm2.Decrypt(privateKeyObj, decodeString, sm2.C1C2C3) + if err != nil { + fmt.Println(err) + } + resultStr := string(decrypt) + fmt.Println("解密后的字符串:", resultStr) + return resultStr, nil +} + +// StringToPrivateKey 私钥还原为 sm2.PrivateKey对象(与java中org.bouncycastle.crypto生成的公私钥完全互通使用) +func StringToPrivateKey(privateKeyStr string, publicKey *sm2.PublicKey) (*sm2.PrivateKey, error) { + privateKeyBytes, err := hex.DecodeString(privateKeyStr) + if err != nil { + return nil, err + } + + // 将字节切片转换为大整数 + d := new(big.Int).SetBytes(privateKeyBytes) + + // 创建 sm2.PrivateKey 对象 + privateKey := &sm2.PrivateKey{ + PublicKey: *publicKey, + D: d, + } + + return privateKey, nil +} + +// StringToPublicKey 公钥字符串还原为 sm2.PublicKey 对象(与java中org.bouncycastle.crypto生成的公私钥完全互通使用) +func StringToPublicKey(publicKeyStr string) (*sm2.PublicKey, error) { + publicKeyBytes, err := hex.DecodeString(publicKeyStr) + if err != nil { + return nil, err + } + + // 提取 x 和 y 坐标字节切片 + curve := sm2.P256Sm2().Params() + byteLen := (curve.BitSize + 7) / 8 + xBytes := publicKeyBytes[1 : byteLen+1] + yBytes := publicKeyBytes[byteLen+1 : 2*byteLen+1] + + // 将字节切片转换为大整数 + x := new(big.Int).SetBytes(xBytes) + y := new(big.Int).SetBytes(yBytes) + + // 创建 sm2.PublicKey 对象 + publicKey := &sm2.PublicKey{ + Curve: curve, + X: x, + Y: y, + } + + return publicKey, nil +} + +// 验证签名 +func VerSm2Sig(pub *sm2.PublicKey, msg []byte, sign []byte) bool { + isok := pub.Verify(msg, sign) + return isok +} diff --git a/app/utils/util.go b/app/utils/util.go index 7d3cb3b..633149d 100644 --- a/app/utils/util.go +++ b/app/utils/util.go @@ -3,17 +3,30 @@ package utils import ( "context" "crypto/md5" + "crypto/rand" + "crypto/sha256" + "crypto/sha512" "encoding/hex" "fmt" + "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" + "github.com/pkg/errors" "github.com/qit-team/snow-core/redis" + "github.com/tjfoc/gmsm/sm2" + "github.com/tjfoc/gmsm/x509" + mrand "math/rand" "net" + "os" + "path/filepath" + "qteam/app/constants/common" "qteam/config" "reflect" + "regexp" "runtime" - "strconv" "strings" "time" + "unicode" ) const ( @@ -67,19 +80,140 @@ func Encode(number int64) string { } // 生成用户touken -func GeneratorToken(playerName string, playerId string) string { +func GeneratorToken(playerName string, playerId int) string { //去生成一个token返回给客户端 m5 := SToMd5(playerName + time.Now().String()) - var pid, _ = strconv.ParseInt(playerId, 10, 64) + var pid = int64(playerId) bsCode := Encode(pid) tk := m5 + bsCode //将token放入redis - _, err := redis.GetRedis(redis.SingletonMain).SetEX(context.Background(), GetRealKey(tk), playerId, 3600).Result() + _, err := redis.GetRedis(redis.SingletonMain).SetEX(context.Background(), GetRealKey(common.TOKEN_PRE+tk), playerId, time.Duration(3600)*time.Second).Result() if err != nil { Log(nil, "token", err) } return tk } + +// ExistFile 检查给定的文件是否存在 +func ExistFile(dirPath string) (exist bool, err error) { + // 使用filepath.Abs获取绝对路径,确保我们处理的是实际存在的路径 + absPath, err := filepath.Abs(dirPath) + if err != nil { + return exist, fmt.Errorf("failed to get absolute path: %v", err) + } + + // 使用os.Stat检查路径是否存在 + _, err = os.Stat(absPath) + if errors.Is(err, os.ErrNotExist) { + return exist, nil + } + + return true, err +} + +// StrToTimeShanghai 字符串转时间 +func StrToTimeShanghai(strTime string) (t time.Time, err error) { + location, _ := time.LoadLocation("Asia/Shanghai") + return time.ParseInLocation(time.DateTime, strTime, location) +} + +func GenIncrementId(tableName string) (int, error) { + var id, err = redis.GetRedis().Incr(context.Background(), GetRealKey(tableName)).Result() + + return int(id), err +} + +// CheckOrCreateYmdDirectory 创建ymd目录 +func CheckOrCreateYmdDirectory(dirPath string) (SavePath string, err error) { + // 使用filepath.Abs获取绝对路径,确保我们处理的是实际存在的路径 + now := time.Now() + year := now.Year() + month := now.Month() + day := now.Day() + savePath := filepath.Join("uploads", dirPath, fmt.Sprintf("%d", year), fmt.Sprintf("%d", month), fmt.Sprintf("%d", day)) + absPath, err := filepath.Abs(savePath) + if err != nil { + return SavePath, fmt.Errorf("failed to get absolute path: %v", err) + } + // 使用os.Stat检查路径是否存在 + info, err := os.Stat(absPath) + if err != nil { + if !os.IsNotExist(err) { + return SavePath, fmt.Errorf("error checking directory: %v", err) + } + + // 目录不存在,尝试创建 + err = os.MkdirAll(absPath, 0755) // 0755是默认权限,可以按需调整 + if err != nil { + return SavePath, fmt.Errorf("failed to create directory: %v", err) + } + } else if !info.IsDir() { + return SavePath, fmt.Errorf("%s exists but it's not a directory", absPath) + } + SavePath = absPath + return SavePath, nil +} + +// CheckOrCreateDirectory 检查给定的目录是否存在,如果不存在则创建它 +func CheckOrCreateDirectory(dirPath string) error { + // 使用filepath.Abs获取绝对路径,确保我们处理的是实际存在的路径 + absPath, err := filepath.Abs(dirPath) + if err != nil { + return fmt.Errorf("failed to get absolute path: %v", err) + } + + // 使用os.Stat检查路径是否存在 + info, err := os.Stat(absPath) + if err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("error checking directory: %v", err) + } + + // 目录不存在,尝试创建 + err = os.MkdirAll(absPath, 0755) // 0755是默认权限,可以按需调整 + if err != nil { + return fmt.Errorf("failed to create directory: %v", err) + } + } else if !info.IsDir() { + return fmt.Errorf("%s exists but it's not a directory", absPath) + } + + return nil +} + +func ToSnakeCase(s string) string { + ch, en := splitChineseEnglish(s) + fmt.Println(ch, en) + re := regexp.MustCompile("([a-z0-9])([A-Z])") + snake := re.ReplaceAllString(en, "${1}_${2}") + return strings.ToLower(snake) + ch +} + +func splitChineseEnglish(input string) (chinese string, english string) { + var index = findChineseStartIndex(input) + + return input[index:], input[0:index] +} + +func findChineseStartIndex(input string) int { + runes := []rune(input) + for i, r := range runes { + if unicode.Is(unicode.Han, r) { + return i + } + } + return -1 // 如果没有找到中文字符,返回-1 +} + +func DownloadFileFromOss(url, savePath string) error { + _, bucket, err := AliOssClient() + if err != nil { + return err + } + err = bucket.GetObjectToFileWithURL(url, savePath) + return err +} + func EntityCopy(dst, src interface{}) { dstValue := reflect.ValueOf(dst).Elem() srcValue := reflect.ValueOf(src).Elem() @@ -128,3 +262,151 @@ func EntityCopy(dst, src interface{}) { } } } + +// AliOssClient 返回Oss客户链接 +func AliOssClient() (client *oss.Client, Bucket *oss.Bucket, err error) { + /* + oss 的相关配置信息 + */ + bucketName := config.GetConf().AliOss.BucKet + endpoint := config.GetConf().AliOss.EndPoint + accessKeyId := config.GetConf().AliOss.AccessKey + accessKeySecret := config.GetConf().AliOss.AccessKeySecret + //domain := config.GetConf().AliOss.Domain + //Dir := config.GetConf().AliOss.Dir + + //创建OSSClient实例 + client, err = oss.New(endpoint, accessKeyId, accessKeySecret) + if err != nil { + return nil, nil, err + } + + // 获取存储空间 + Bucket, err = client.Bucket(bucketName) + if err != nil { + return nil, nil, err + } + return client, Bucket, nil +} +func GetSHA256HashCode(message []byte) string { + //方法一: + //创建一个基于SHA256算法的hash.Hash接口的对象 + hash := sha256.New() + //输入数据 + hash.Write(message) + //计算哈希值 + bytes := hash.Sum(nil) + //将字符串编码为16进制格式,返回字符串 + hashCode := hex.EncodeToString(bytes) + //返回哈希值 + return hashCode + + //方法二: + //bytes2:=sha256.Sum256(message)//计算哈希值,返回一个长度为32的数组 + //hashcode2:=hex.EncodeToString(bytes2[:])//将数组转换成切片,转换成16进制,返回字符串 + //return hashcode2 +} +func GetSHA512HashCode(message []byte) string { + + hash := sha512.New() + hash.Write(message) + bytes := hash.Sum(nil) + hashCode := hex.EncodeToString(bytes) + return hashCode +} + +// SM2Encode sm2公钥加密 +func SM2Encode(pubKey string, plaintext string, mode int) (string, error) { + pubMen, err := x509.ReadPublicKeyFromHex(pubKey) + if err != nil { + return "", err + } + msg := []byte(plaintext) + ciphertxt, err := sm2.Encrypt(pubMen, msg, rand.Reader, mode) + if err != nil { + return "", err + } + return hex.EncodeToString(ciphertxt), nil +} + +// SM2Decode sm2私钥解密 +func SM2Decode(privKey string, data string, mode int) (string, error) { + priv, err := x509.ReadPrivateKeyFromHex(privKey) + if err != nil { + return "", err + } + ciphertext, err := hex.DecodeString(data) + if err != nil { + return "", err + } + plaintext, err := sm2.Decrypt(priv, []byte(ciphertext), mode) + if err != nil { + return "", err + } + return string(plaintext), nil +} + +func GenerateOrderNumber() string { + // 生成当前日期部分(例如:20231008) + datePart := time.Now().Format("20060102150405") + + // 生成随机数部分(4位随机数) + mrand.Seed(time.Now().UnixNano()) + randomPart := fmt.Sprintf("%04d", mrand.Intn(10000)) + + // 添加固定前缀 + prefix := "SN" + + // 最终的订单号由前缀、日期和随机数部分组成 + orderNumber := fmt.Sprintf("%s%s%s", prefix, datePart, randomPart) + + return orderNumber +} +func IsNil(x interface{}) bool { + if x == nil { + return true + } + rv := reflect.ValueOf(x) + return rv.Kind() == reflect.Ptr && rv.IsNil() +} + +type User struct { + Id int + Phone string +} + +func GeneratorJwtToken(user User) string { + // 定义一个用于签名的密钥 + secretKey := []byte(config.GetConf().Jwt.SecretKey) + + // 创建一个MapClaims对象,用于存放自定义的声明信息 + claims := jwt.MapClaims{ + "id": user.Id, + "phone": user.Phone, + "exp": time.Now().Add(time.Hour * 24).Unix(), // 设置过期时间为24小时后 + } + // 使用HS256算法创建一个Token对象 + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + // 使用密钥对Token进行签名,生成JWT字符串 + tokenString, err := token.SignedString(secretKey) + if err != nil { + fmt.Println("Failed to create token:", err) + return "" + } + return tokenString +} + +type Claims struct { + Id int + Phone string + jwt.StandardClaims +} + +func ParseToken(tokenString string) (*jwt.Token, *Claims, error) { + Claims := &Claims{} + token, err := jwt.ParseWithClaims(tokenString, Claims, func(token *jwt.Token) (i interface{}, err error) { + return []byte(config.GetConf().Jwt.SecretKey), nil + }) + return token, Claims, err +} diff --git a/config/config.go b/config/config.go index 4b1ab23..5863e4a 100644 --- a/config/config.go +++ b/config/config.go @@ -32,6 +32,47 @@ type Config struct { Nacos Nacos `toml:"Nacas"` Rpc Rpc `toml:"Rpc"` AppKey string `toml:"AppKey"` + Sm2 Sm2 `toml:"Sm2"` + OpenApiMarketConfig MarketConfig `toml:"MarketConfig"` + OpenApi OpenApi `toml:"OpenApi"` + Jwt Jwt `toml:"Jwt"` + AliOss AliOss `toml:"AliOss"` +} + +type AliOss struct { + AccessKey string + AccessKeySecret string + EndPoint string + BucKet string + Domain string + Dir string +} + +type Jwt struct { + SecretKey string +} + +type OpenApi struct { + MerchantId string + SecretKey string + IsProd bool + NotifyUrl string + TimeOut int +} + +type MarketConfig struct { + AppId string `json:"app_id"` //APP ID + Sign string `json:"sign"` //签名 + ReqCode string `json:"req_code"` //固定值:voucher.create + MemId string `json:"mem_id"` //商户号 + PosId string `json:"pos_id"` //商户方平台号 + Host string `json:"-"` + SecretKey string +} + +type Sm2 struct { + PublicKey string + PrivateKey string } type Rpc struct { diff --git a/go.mod b/go.mod index a178231..11ba3a8 100644 --- a/go.mod +++ b/go.mod @@ -3,26 +3,32 @@ module qteam go 1.21 require ( + gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2 github.com/BurntSushi/toml v0.4.1 - github.com/ahmetb/go-linq/v3 v3.2.0 + github.com/Shopify/sarama v1.19.0 + github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/forgoer/openssl v1.6.0 github.com/gin-gonic/gin v1.7.7 github.com/go-playground/locales v0.14.0 github.com/go-playground/universal-translator v0.18.0 github.com/go-sql-driver/mysql v1.6.0 + github.com/golang-jwt/jwt/v4 v4.5.0 github.com/nacos-group/nacos-sdk-go/v2 v2.2.5 + github.com/nats-io/nats.go v1.9.1 github.com/openzipkin/zipkin-go v0.2.2 + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.2 github.com/qit-team/snow-core v0.1.28 github.com/qit-team/work v0.3.11 github.com/robfig/cron v1.2.0 + github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 github.com/swaggo/gin-swagger v1.3.3 github.com/swaggo/swag v1.7.9 + github.com/tjfoc/gmsm v1.4.1 github.com/valyala/fasthttp v1.31.0 google.golang.org/grpc v1.56.3 google.golang.org/protobuf v1.30.0 gopkg.in/go-playground/validator.v9 v9.31.0 - xorm.io/builder v0.3.9 ) require ( @@ -40,7 +46,11 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/eapache/go-resiliency v1.1.0 // indirect + github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect + github.com/eapache/queue v1.1.0 // indirect github.com/emirpasic/gods v1.12.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -68,10 +78,14 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/nats-io/jwt v0.3.2 // indirect + github.com/nats-io/nkeys v0.1.3 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + github.com/pierrec/lz4 v2.0.5+incompatible // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect @@ -96,6 +110,7 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect stathat.com/c/consistent v1.0.0 // indirect + xorm.io/builder v0.3.9 // indirect xorm.io/core v0.7.3 // indirect xorm.io/xorm v1.2.5 // indirect ) diff --git a/go.sum b/go.sum index 449a90f..a3fda71 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2 h1:f4Rj4jVshXYX7wl7aIrd7W9DbGfqxYrZ/c7ppoVL4a4= +gitee.com/chengdu_blue_brothers/openapi-go-sdk v0.0.2/go.mod h1:OEBHFTBQOvsJGzLyMZS8K98F8aZHWg+O8Stycuh94Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= @@ -51,14 +53,14 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0 h1:9oksLxC6uxVPHPVYUmq6xhr1BOF/hHobWH2UzO67z1s= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs= github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= -github.com/ahmetb/go-linq/v3 v3.2.0 h1:BEuMfp+b59io8g5wYzNoFe9pWPalRklhlhbiU3hYZDE= -github.com/ahmetb/go-linq/v3 v3.2.0/go.mod h1:haQ3JfOeWK8HpVxMtHHEMPVgBKiYyQ+f1/kLZh/cj9U= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -78,6 +80,8 @@ github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2/go.mod h1:GDtq+Kw+v0fO+j5B github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7 h1:olLiPI2iM8Hqq6vKnSxpM3awCrm9/BeOgHpzQkOYnI4= github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7/go.mod h1:oDg1j4kFxnhgftaiLJABkGeSvuEvSF5Lo6UmRAMruX4= github.com/aliyun/aliyun-mns-go-sdk v1.0.2/go.mod h1:eD/mEH7SwtLSwI9p8fP9VTH2cYM3wFSY1WNaxEdLIFU= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= +github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyunmq/mq-http-go-sdk v1.0.3/go.mod h1:JYfRMQoPexERvnNNBcal0ZQ2TVQ5ialDiW9ScjaadEM= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= @@ -142,8 +146,11 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0 h1:1NtRmCAqadE2FN4ZcN6g90TP3uk8cg9rn9eNK2197aU= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= @@ -235,6 +242,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -515,11 +524,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/nacos-group/nacos-sdk-go/v2 v2.2.5 h1:r0wwT7PayEjvEHzWXwr1ROi/JSqzujM4w+1L5ikThzQ= github.com/nacos-group/nacos-sdk-go/v2 v2.2.5/go.mod h1:OObBon0prVJVPoIbSZxpEkFiBfL0d1LcBtuAMiNn+8c= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= @@ -560,6 +574,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -605,6 +620,7 @@ github.com/qit-team/snow-core v0.1.28 h1:RrX7i6GLbcMMSVzAT1lXgS/S3M2b1OrAnsoPaRG github.com/qit-team/snow-core v0.1.28/go.mod h1:J9CNj6P2IRh72yVa7rut4T8ikq/4DjaisLqXZy40TNg= github.com/qit-team/work v0.3.11 h1:AAtLTCOJ01WMFcvviK9rDGhHzaHE3bvunMOnSZ/80k8= github.com/qit-team/work v0.3.11/go.mod h1:h5m1cZjn+BznChuAyMiR/+IUyWEmaMylPKRhq/AlxKw= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -658,6 +674,7 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -690,6 +707,8 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= +github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -767,6 +786,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= @@ -849,6 +869,7 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= diff --git a/main.go b/main.go index 6b29a67..736894f 100644 --- a/main.go +++ b/main.go @@ -117,7 +117,10 @@ func startServer(opts *config.Options) (err error) { err = rpc.StartRpc() case "admin": err = server.StartHttp(pidFile, conf.Admin, routes.RegisterAdminRoute) - + case "all": + go server.StartHttp(pidFile, conf.Api, routes.RegisterRoute) + go server.StartHttp(pidFile, conf.Admin, routes.RegisterAdminRoute) + select {} default: err = errors.New("no server start") }