From f5e8a4b990281226302c9a03d2282545531c871c Mon Sep 17 00:00:00 2001 From: zhongqiang <15375399426> Date: Fri, 27 Jun 2025 17:16:51 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=89=80=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jtt_tool/jtt_client.go | 200 ++++++++++++++++++++++++++++++++++++ jtt_tool/jtt_client_test.go | 1 + 2 files changed, 201 insertions(+) create mode 100644 jtt_tool/jtt_client.go create mode 100644 jtt_tool/jtt_client_test.go diff --git a/jtt_tool/jtt_client.go b/jtt_tool/jtt_client.go new file mode 100644 index 0000000..628ece6 --- /dev/null +++ b/jtt_tool/jtt_client.go @@ -0,0 +1,200 @@ +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(paramMap) + if err != nil { + return + } + + err = json.Unmarshal(postRes, &res) + if err != nil { + err = fmt.Errorf("转换FindUserForTokenMessageRes结构体失败: %s", string(postRes)) + return + } + + if res == nil { + err = fmt.Errorf("查询交易所数据失败: %w, 地址:%s", err, address) + return + } + + return + +} + +type FindUserForTokenMessageRes struct { + 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(paramMap map[string]any) (res []byte, err error) { + + bodyByte, _ := json.Marshal(paramMap) + + req, err := http.NewRequest(http.MethodPost, j.ApiUrl+"/findUserForTokenMessage", 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 +} diff --git a/jtt_tool/jtt_client_test.go b/jtt_tool/jtt_client_test.go new file mode 100644 index 0000000..bbd3a58 --- /dev/null +++ b/jtt_tool/jtt_client_test.go @@ -0,0 +1 @@ +package jtt_tool From 8b245587bb92008546d8f194d7a98a7a08b1977d Mon Sep 17 00:00:00 2001 From: zhongqiang <15375399426> Date: Fri, 27 Jun 2025 17:26:16 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=89=80=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jtt_tool/jtt_client.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jtt_tool/jtt_client.go b/jtt_tool/jtt_client.go index 628ece6..563b943 100644 --- a/jtt_tool/jtt_client.go +++ b/jtt_tool/jtt_client.go @@ -50,7 +50,7 @@ func (j *JttClient) FindUserForTokenMessage(address string) (res *FindUserForTok paramMap["publicKey"] = j.PublicKey paramMap["address"] = address - postRes, err := j.JttPost(paramMap) + postRes, err := j.JttPost("/findUserForTokenMessage", paramMap) if err != nil { return } @@ -71,6 +71,7 @@ func (j *JttClient) FindUserForTokenMessage(address string) (res *FindUserForTok } type FindUserForTokenMessageRes struct { + Code int `json:"code"` Data *Data `json:"data"` } @@ -85,11 +86,11 @@ type UserToken struct { WalletAddress string `json:"walletAddress"` } -func (j *JttClient) JttPost(paramMap map[string]any) (res []byte, err error) { +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+"/findUserForTokenMessage", bytes.NewBuffer(bodyByte)) + req, err := http.NewRequest(http.MethodPost, j.ApiUrl+url, bytes.NewBuffer(bodyByte)) if err != nil { return } From 2835ad200b76e9cf2921105fabfcd047a7baa37d Mon Sep 17 00:00:00 2001 From: zhongqiang <15375399426> Date: Fri, 27 Jun 2025 17:28:58 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=89=80=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jtt_tool/jtt_client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jtt_tool/jtt_client.go b/jtt_tool/jtt_client.go index 563b943..5bf8dae 100644 --- a/jtt_tool/jtt_client.go +++ b/jtt_tool/jtt_client.go @@ -61,8 +61,8 @@ func (j *JttClient) FindUserForTokenMessage(address string) (res *FindUserForTok return } - if res == nil { - err = fmt.Errorf("查询交易所数据失败: %w, 地址:%s", err, address) + if res == nil || res.Code != 200 { + err = fmt.Errorf("查询交易所数据失败: %w, res: %+v , 地址:%s", err, res, address) return } From f26c317144d0e4a4a9823d51d074a36bda54b474 Mon Sep 17 00:00:00 2001 From: zhongqiang <15375399426> Date: Mon, 30 Jun 2025 14:13:39 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=89=80=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jtt_tool/jtt_client_test.go | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/jtt_tool/jtt_client_test.go b/jtt_tool/jtt_client_test.go index bbd3a58..4279f5b 100644 --- a/jtt_tool/jtt_client_test.go +++ b/jtt_tool/jtt_client_test.go @@ -1 +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) + } + }) + } +}