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) }