Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
26bc6b3bcc | ||
![]() |
755c39089b | ||
![]() |
ace2872c2d | ||
![]() |
d2a1182c66 | ||
![]() |
f26c317144 | ||
![]() |
2835ad200b | ||
![]() |
8b245587bb | ||
![]() |
f5e8a4b990 |
4
go.mod
4
go.mod
@@ -1,6 +1,8 @@
|
|||||||
module git.ssgfgtfy.com/public/ssgf_utils
|
module git.ssgfgtfy.com/public/ssgf_utils
|
||||||
|
|
||||||
go 1.18.0
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.7
|
||||||
|
201
jtt_tool/jtt_client.go
Normal file
201
jtt_tool/jtt_client.go
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
package jtt_tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JttClient struct {
|
||||||
|
AppId string
|
||||||
|
ApiUrl string
|
||||||
|
PublicKey string
|
||||||
|
PrivateKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJttClient(appId, apiUrl, publicKey, privateKey string) *JttClient {
|
||||||
|
return &JttClient{
|
||||||
|
AppId: appId,
|
||||||
|
ApiUrl: apiUrl,
|
||||||
|
PublicKey: publicKey,
|
||||||
|
PrivateKey: privateKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JttClient) FindUserForTokenMessage(address string) (res *FindUserForTokenMessageRes, err error) {
|
||||||
|
if address == "" {
|
||||||
|
return nil, fmt.Errorf("address is empty")
|
||||||
|
}
|
||||||
|
fmt.Println("address", address)
|
||||||
|
|
||||||
|
paramMap := make(map[string]any)
|
||||||
|
|
||||||
|
paramMap["appId"] = j.AppId
|
||||||
|
paramMap["timestamp"] = time.Now().Unix()
|
||||||
|
paramMap["publicKey"] = j.PublicKey
|
||||||
|
paramMap["address"] = address
|
||||||
|
|
||||||
|
postRes, err := j.JttPost("/findUserForTokenMessage", paramMap)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(postRes, &res)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("转换FindUserForTokenMessageRes结构体失败: %s", string(postRes))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if res == nil || res.Code != 200 {
|
||||||
|
err = fmt.Errorf("查询交易所数据失败: %w, res: %+v , 地址:%s", err, res, address)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type FindUserForTokenMessageRes struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Data *Data `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
UserTokenList []*UserToken `json:"userTokenList"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserToken struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Mes string `json:"mes"`
|
||||||
|
TokenNum float64 `json:"tokenNum"`
|
||||||
|
WalletAddress string `json:"walletAddress"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JttClient) JttPost(url string, paramMap map[string]any) (res []byte, err error) {
|
||||||
|
|
||||||
|
bodyByte, _ := json.Marshal(paramMap)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, j.ApiUrl+url, bytes.NewBuffer(bodyByte))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
sign, err := j.ToSign(paramMap)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
paramMap["sign"] = sign
|
||||||
|
|
||||||
|
// 创建 HTTP 客户端
|
||||||
|
client := &http.Client{}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
//log.Printf("WPSPost resp: %+v\n", resp)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("发送请求失败: %+v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func(Body io.ReadCloser) {
|
||||||
|
_ = Body.Close()
|
||||||
|
}(resp.Body)
|
||||||
|
|
||||||
|
// 读取响应体
|
||||||
|
res, err = io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("res: %s\n", string(res))
|
||||||
|
|
||||||
|
if !json.Valid(res) {
|
||||||
|
return nil, errors.New("响应体不是有效的JSON格式")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *JttClient) ToSign(reqData map[string]interface{}) (sign []byte, errs error) {
|
||||||
|
sortedStr, err := s.GetSortedStr(reqData)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
privateKeyStr := "-----BEGIN PRIVATE KEY-----\r\n" + s.PrivateKey + "\r\n-----END PRIVATE KEY-----"
|
||||||
|
sign, err = s.Sign(sortedStr, privateKeyStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *JttClient) Sign(signData string, privateKeyStr string) (sign []byte, errs error) {
|
||||||
|
hashedMessage := md5.Sum([]byte(signData))
|
||||||
|
if privateKeyStr == "" {
|
||||||
|
return nil, errors.New("private key is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _ := pem.Decode([]byte(privateKeyStr))
|
||||||
|
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sign, err = rsa.SignPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), crypto.MD5, hashedMessage[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sign = []byte(base64.StdEncoding.EncodeToString(sign))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *JttClient) GetSortedStr(data any) (str string, err error) {
|
||||||
|
tmp := map[string]interface{}{}
|
||||||
|
if reflect.ValueOf(data).Kind() == reflect.Struct {
|
||||||
|
jsStr, _ := json.Marshal(data)
|
||||||
|
_ = json.Unmarshal(jsStr, &tmp)
|
||||||
|
} else {
|
||||||
|
ok := false
|
||||||
|
tmp, ok = data.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("data type error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := []string{}
|
||||||
|
for key := range tmp {
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(keys)
|
||||||
|
sortedParams := []string{}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
value := tmp[key]
|
||||||
|
if key == "sign" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := value.(type) {
|
||||||
|
case int, uint, int16, int32, int64:
|
||||||
|
sortedParams = append(sortedParams, fmt.Sprintf("%s=%d", key, v))
|
||||||
|
case float64, float32:
|
||||||
|
sortedParams = append(sortedParams, fmt.Sprintf("%s=%f", key, v))
|
||||||
|
default:
|
||||||
|
sortedParams = append(sortedParams, key+"="+value.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str = strings.Join(sortedParams, "&")
|
||||||
|
return
|
||||||
|
}
|
51
jtt_tool/jtt_client_test.go
Normal file
51
jtt_tool/jtt_client_test.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package jtt_tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJttClient_FindUserForTokenMessage(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
AppId string
|
||||||
|
ApiUrl string
|
||||||
|
PublicKey string
|
||||||
|
PrivateKey string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
address string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
wantRes *FindUserForTokenMessageRes
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "test1",
|
||||||
|
fields: fields{},
|
||||||
|
args: args{
|
||||||
|
address: "0x123456",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
h := &JttClient{
|
||||||
|
AppId: test.fields.AppId,
|
||||||
|
ApiUrl: test.fields.ApiUrl,
|
||||||
|
PublicKey: test.fields.PublicKey,
|
||||||
|
PrivateKey: test.fields.PrivateKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
gotRes, err := h.FindUserForTokenMessage(test.args.address)
|
||||||
|
|
||||||
|
log.Println(gotRes, err)
|
||||||
|
|
||||||
|
if (err != nil) != test.wantErr {
|
||||||
|
t.Errorf("FindUserForTokenMessage() error = %v, wantErr %v", err, test.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -160,19 +160,19 @@ type GoodsItem struct {
|
|||||||
|
|
||||||
// 商品SKU信息
|
// 商品SKU信息
|
||||||
type GoodsSkuItem struct {
|
type GoodsSkuItem struct {
|
||||||
CFatherGoodsID string `json:"c_father_goods_id"` // 父级商品ID
|
CFatherGoodsID string `json:"c_father_goods_id"` // 父级商品ID
|
||||||
CGoodsID string `json:"c_goods_id"` // 商品ID
|
CGoodsID string `json:"c_goods_id"` // 商品ID
|
||||||
CGoodsName string `json:"c_goods_name"` // 商品规格名称
|
CGoodsName string `json:"c_goods_name"` // 商品规格名称
|
||||||
COriginalPrice string `json:"c_original_price"` // 商品市场价
|
COriginalPrice string `json:"c_original_price"` // 商品市场价
|
||||||
CInPrice string `json:"c_in_price"` // 商品进价
|
CInPrice string `json:"c_in_price"` // 商品进价
|
||||||
CSalePrice string `json:"c_sale_price"` // 商品建议售价
|
CSalePrice string `json:"c_sale_price"` // 商品建议售价
|
||||||
CGoodsColor string `json:"c_goods_color"` // 商品颜色
|
CGoodsColor string `json:"c_goods_color"` // 商品颜色
|
||||||
CGoodsSize string `json:"c_goods_size"` // 商品尺寸
|
CGoodsSize string `json:"c_goods_size"` // 商品尺寸
|
||||||
CGoodsImage string `json:"c_goods_image"` // 商品列表图片
|
CGoodsImage string `json:"c_goods_image"` // 商品列表图片
|
||||||
CGoodsStockStart int `json:"c_goods_stock_start"` // 初始总库存
|
CGoodsStockStart interface{} `json:"c_goods_stock_start"` // 初始总库存
|
||||||
CGoodsStockValid int `json:"c_goods_stock_valid"` // 有效库存(下单库存参考)
|
CGoodsStockValid interface{} `json:"c_goods_stock_valid"` // 有效库存(下单库存参考)
|
||||||
CBuyMinNum int `json:"c_buy_min_num"` // 最小购买数量
|
CBuyMinNum interface{} `json:"c_buy_min_num"` // 最小购买数量
|
||||||
CBuyMaxNum int `json:"c_buy_max_num"` // 最大购买数量
|
CBuyMaxNum interface{} `json:"c_buy_max_num"` // 最大购买数量
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetGoodsDetailsReq struct {
|
type GetGoodsDetailsReq struct {
|
||||||
|
@@ -38,7 +38,7 @@ type SkuData struct {
|
|||||||
GoodName string `json:"goodName"` //商品名称
|
GoodName string `json:"goodName"` //商品名称
|
||||||
Num interface{} `json:"num"` //数量
|
Num interface{} `json:"num"` //数量
|
||||||
//Num int `json:"num"` //数量
|
//Num int `json:"num"` //数量
|
||||||
Price string `json:"price"` //单价
|
Price interface{} `json:"price"` //单价
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetOrderInfoRes struct {
|
type GetOrderInfoRes struct {
|
||||||
|
Reference in New Issue
Block a user