256 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package helper
 | |
| 
 | |
| import (
 | |
| 	"crypto"
 | |
| 	"crypto/hmac"
 | |
| 	"crypto/rand"
 | |
| 	"crypto/rsa"
 | |
| 	"crypto/sha256"
 | |
| 	"crypto/tls"
 | |
| 	"crypto/x509"
 | |
| 	"encoding/base64"
 | |
| 	"encoding/json"
 | |
| 	"encoding/pem"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| // BitgetClient Bitget HTTP客户端
 | |
| type BitgetClient struct {
 | |
| 	APIKey     string
 | |
| 	APISecret  string
 | |
| 	Passphrase string
 | |
| 	HTTPClient *http.Client
 | |
| 	BaseURL    string
 | |
| 	SignType   string
 | |
| }
 | |
| 
 | |
| // NewBitgetClient 创建新的Bitget客户端
 | |
| func NewBitgetClient(apiKey, apiSecret, passphrase string, proxyUrl string) (*BitgetClient, error) {
 | |
| 	var proxyType, proxyAddr string
 | |
| 	if proxyUrl != "" {
 | |
| 		if strings.HasPrefix(proxyUrl, "http://") {
 | |
| 			proxyType = "http"
 | |
| 			proxyAddr = proxyUrl
 | |
| 		} else if strings.HasPrefix(proxyUrl, "https://") {
 | |
| 			proxyType = "https"
 | |
| 			proxyAddr = proxyUrl
 | |
| 		} else if strings.HasPrefix(proxyUrl, "socks5://") {
 | |
| 			proxyType = "socks5"
 | |
| 			proxyAddr = proxyUrl
 | |
| 		} else {
 | |
| 			// 默认为http代理
 | |
| 			proxyType = "http"
 | |
| 			proxyAddr = "http://" + proxyUrl
 | |
| 		}
 | |
| 	}
 | |
| 	// 创建HTTP客户端
 | |
| 	client := &http.Client{
 | |
| 		Transport: &http.Transport{
 | |
| 			MaxIdleConns:    1000,
 | |
| 			IdleConnTimeout: 10 * time.Second,
 | |
| 			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	// 设置代理
 | |
| 	if proxyAddr != "" {
 | |
| 		err := CreateHtppProxy(proxyType, proxyAddr, client)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &BitgetClient{
 | |
| 		APIKey:     apiKey,
 | |
| 		APISecret:  apiSecret,
 | |
| 		Passphrase: passphrase,
 | |
| 		HTTPClient: client,
 | |
| 		BaseURL:    "https://api.bitget.com",
 | |
| 		SignType:   "SHA256",
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // DoGet 执行GET请求
 | |
| func (bc *BitgetClient) DoGet(uri string, params map[string]string) ([]byte, error) {
 | |
| 	timestamp := bc.getTimestamp()
 | |
| 	body := bc.buildGetParams(params)
 | |
| 
 | |
| 	sign := bc.sign("GET", uri, body, timestamp)
 | |
| 	requestURL := bc.BaseURL + uri + body
 | |
| 
 | |
| 	request, err := http.NewRequest("GET", requestURL, nil)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	bc.setHeaders(request, timestamp, sign)
 | |
| 
 | |
| 	response, err := bc.HTTPClient.Do(request)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer response.Body.Close()
 | |
| 
 | |
| 	return ioutil.ReadAll(response.Body)
 | |
| }
 | |
| 
 | |
| // DoPost 执行POST请求
 | |
| func (bc *BitgetClient) DoPost(uri string, params interface{}) ([]byte, error) {
 | |
| 	timestamp := bc.getTimestamp()
 | |
| 
 | |
| 	var body string
 | |
| 	if params != nil {
 | |
| 		bodyBytes, err := json.Marshal(params)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		body = string(bodyBytes)
 | |
| 	}
 | |
| 
 | |
| 	sign := bc.sign("POST", uri, body, timestamp)
 | |
| 	requestURL := bc.BaseURL + uri
 | |
| 
 | |
| 	request, err := http.NewRequest("POST", requestURL, strings.NewReader(body))
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	bc.setHeaders(request, timestamp, sign)
 | |
| 
 | |
| 	response, err := bc.HTTPClient.Do(request)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	defer response.Body.Close()
 | |
| 
 | |
| 	return ioutil.ReadAll(response.Body)
 | |
| }
 | |
| 
 | |
| // getTimestamp 获取时间戳
 | |
| func (bc *BitgetClient) getTimestamp() string {
 | |
| 	return strconv.FormatInt(time.Now().Unix()*1000, 10)
 | |
| }
 | |
| 
 | |
| // setHeaders 设置请求头
 | |
| func (bc *BitgetClient) setHeaders(request *http.Request, timestamp, sign string) {
 | |
| 	request.Header.Add("Content-Type", "application/json")
 | |
| 	request.Header.Add("ACCESS-KEY", bc.APIKey)
 | |
| 	request.Header.Add("ACCESS-SIGN", sign)
 | |
| 	request.Header.Add("ACCESS-TIMESTAMP", timestamp)
 | |
| 	request.Header.Add("ACCESS-PASSPHRASE", bc.Passphrase)
 | |
| }
 | |
| 
 | |
| // sign 生成签名
 | |
| func (bc *BitgetClient) sign(method, requestPath, body, timestamp string) string {
 | |
| 	var payload strings.Builder
 | |
| 	payload.WriteString(timestamp)
 | |
| 	payload.WriteString(method)
 | |
| 	payload.WriteString(requestPath)
 | |
| 	if body != "" && body != "?" {
 | |
| 		payload.WriteString(body)
 | |
| 	}
 | |
| 
 | |
| 	if bc.SignType == "RSA" {
 | |
| 		return bc.signByRSA(payload.String())
 | |
| 	}
 | |
| 
 | |
| 	return bc.signByHMAC(payload.String())
 | |
| }
 | |
| 
 | |
| // signByHMAC HMAC签名
 | |
| func (bc *BitgetClient) signByHMAC(payload string) string {
 | |
| 	hash := hmac.New(sha256.New, []byte(bc.APISecret))
 | |
| 	hash.Write([]byte(payload))
 | |
| 	return base64.StdEncoding.EncodeToString(hash.Sum(nil))
 | |
| }
 | |
| 
 | |
| // signByRSA RSA签名
 | |
| func (bc *BitgetClient) signByRSA(payload string) string {
 | |
| 	sign, _ := bc.rsaSign([]byte(payload), []byte(bc.APISecret), crypto.SHA256)
 | |
| 	return base64.StdEncoding.EncodeToString(sign)
 | |
| }
 | |
| 
 | |
| // rsaSign RSA签名实现
 | |
| func (bc *BitgetClient) rsaSign(src []byte, priKey []byte, hash crypto.Hash) ([]byte, error) {
 | |
| 	block, _ := pem.Decode(priKey)
 | |
| 	if block == nil {
 | |
| 		return nil, errors.New("key is invalid format")
 | |
| 	}
 | |
| 
 | |
| 	var pkixPrivateKey interface{}
 | |
| 	var err error
 | |
| 	if block.Type == "RSA PRIVATE KEY" {
 | |
| 		pkixPrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
 | |
| 	} else if block.Type == "PRIVATE KEY" {
 | |
| 		pkixPrivateKey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
 | |
| 	}
 | |
| 
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	h := hash.New()
 | |
| 	_, err = h.Write(src)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	bytes := h.Sum(nil)
 | |
| 	sign, err := rsa.SignPKCS1v15(rand.Reader, pkixPrivateKey.(*rsa.PrivateKey), hash, bytes)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return sign, nil
 | |
| }
 | |
| 
 | |
| // buildGetParams 构建GET请求参数
 | |
| func (bc *BitgetClient) buildGetParams(params map[string]string) string {
 | |
| 	if len(params) == 0 {
 | |
| 		return ""
 | |
| 	}
 | |
| 	return "?" + bc.sortParams(params)
 | |
| }
 | |
| 
 | |
| // sortParams 参数排序
 | |
| func (bc *BitgetClient) sortParams(params map[string]string) string {
 | |
| 	keys := make([]string, 0, len(params))
 | |
| 	for k := range params {
 | |
| 		keys = append(keys, k)
 | |
| 	}
 | |
| 	sort.Strings(keys)
 | |
| 
 | |
| 	sorted := make([]string, 0, len(params))
 | |
| 	for _, k := range keys {
 | |
| 		sorted = append(sorted, k+"="+params[k])
 | |
| 	}
 | |
| 	return strings.Join(sorted, "&")
 | |
| }
 | |
| 
 | |
| // SendSpotRequestAuth 发送现货认证请求
 | |
| func (bc *BitgetClient) SendSpotRequestAuth(endpoint, method string, params map[string]interface{}) ([]byte, *http.Response, error) {
 | |
| 	if method == "GET" {
 | |
| 		paramStr := make(map[string]string)
 | |
| 		for k, v := range params {
 | |
| 			paramStr[k] = fmt.Sprintf("%v", v)
 | |
| 		}
 | |
| 		resp, err := bc.DoGet(endpoint, paramStr)
 | |
| 		return resp, nil, err
 | |
| 	} else {
 | |
| 		resp, err := bc.DoPost(endpoint, params)
 | |
| 		return resp, nil, err
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // SendFuturesRequestAuth 发送合约认证请求
 | |
| func (bc *BitgetClient) SendFuturesRequestAuth(endpoint, method string, params map[string]interface{}) ([]byte, *http.Response, error) {
 | |
| 	return bc.SendSpotRequestAuth(endpoint, method, params)
 | |
| }
 |