v5sdkgo/rest/rest.go

376 lines
8.0 KiB
Go
Raw Normal View History

2024-12-14 19:09:06 +08:00
package rest
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
2025-03-05 20:52:20 +08:00
"gitea.zjmud.xyz/phyer/v5sdkgo/utils"
2024-12-14 19:09:06 +08:00
"io/ioutil"
"net/http"
"strings"
"time"
)
type RESTAPI struct {
EndPoint string `json:"endPoint"`
// GET/POST
Method string `json:"method"`
Uri string `json:"uri"`
Param map[string]interface{} `json:"param"`
Timeout time.Duration
ApiKeyInfo *APIKeyInfo
isSimulate bool
}
type APIKeyInfo struct {
ApiKey string
PassPhrase string
SecKey string
UserId string
}
type RESTAPIResult struct {
Url string `json:"url"`
Param string `json:"param"`
Header string `json:"header"`
Code int `json:"code"`
// 原始返回信息
Body string `json:"body"`
// okexV5返回的数据
V5Response Okexv5APIResponse `json:"v5Response"`
ReqUsedTime time.Duration `json:"reqUsedTime"`
TotalUsedTime time.Duration `json:"totalUsedTime"`
}
2025-03-05 22:21:00 +08:00
// ResponseData 定义统一的响应数据接口
type ResponseData interface {
GetCode() string
GetMsg() string
GetData() interface{}
}
2024-12-14 19:09:06 +08:00
type Okexv5APIResponse struct {
2025-03-05 21:42:33 +08:00
Code string `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
2024-12-14 19:09:06 +08:00
}
2025-03-05 22:21:00 +08:00
// 实现 ResponseData 接口
func (r Okexv5APIResponse) GetCode() string {
return r.Code
}
func (r Okexv5APIResponse) GetMsg() string {
return r.Msg
}
func (r Okexv5APIResponse) GetData() interface{} {
return r.Data
}
type CandleDataResponse struct {
2025-03-05 22:03:38 +08:00
Code string `json:"code"`
Msg string `json:"msg"`
Data [][]interface{} `json:"data"` // 用二维数组来接收 candles 数据
}
2025-03-05 22:21:00 +08:00
// 实现 ResponseData 接口
func (r CandleDataResponse) GetCode() string {
return r.Code
}
func (r CandleDataResponse) GetMsg() string {
return r.Msg
}
func (r CandleDataResponse) GetData() interface{} {
return r.Data
}
2024-12-14 19:09:06 +08:00
/*
2024-12-16 11:41:20 +08:00
endPoint:请求地址
apiKey
isSimulate: 是否为模拟环境
2024-12-14 19:09:06 +08:00
*/
func NewRESTClient(endPoint string, apiKey *APIKeyInfo, isSimulate bool) *RESTAPI {
res := &RESTAPI{
EndPoint: endPoint,
ApiKeyInfo: apiKey,
isSimulate: isSimulate,
Timeout: 5 * time.Second,
}
return res
}
func NewRESTAPI(ep, method, uri string, param *map[string]interface{}) *RESTAPI {
//TODO:参数校验
reqParam := make(map[string]interface{})
if param != nil {
reqParam = *param
}
res := &RESTAPI{
EndPoint: ep,
Method: method,
Uri: uri,
Param: reqParam,
Timeout: 150 * time.Second,
}
return res
}
func (this *RESTAPI) SetSimulate(b bool) *RESTAPI {
this.isSimulate = b
return this
}
func (this *RESTAPI) SetAPIKey(apiKey, secKey, passPhrase string) *RESTAPI {
if this.ApiKeyInfo == nil {
this.ApiKeyInfo = &APIKeyInfo{
ApiKey: apiKey,
PassPhrase: passPhrase,
SecKey: secKey,
}
} else {
this.ApiKeyInfo.ApiKey = apiKey
this.ApiKeyInfo.PassPhrase = passPhrase
this.ApiKeyInfo.SecKey = secKey
}
return this
}
func (this *RESTAPI) SetUserId(userId string) *RESTAPI {
if this.ApiKeyInfo == nil {
fmt.Println("ApiKey为空")
return this
}
this.ApiKeyInfo.UserId = userId
return this
}
func (this *RESTAPI) SetTimeOut(timeout time.Duration) *RESTAPI {
this.Timeout = timeout
return this
}
2025-03-05 22:03:38 +08:00
// GetCandles 获取蜡烛图数据
2025-03-05 22:26:30 +08:00
func (this *RESTAPI) GetCandles(ctx context.Context, uri string, param *map[string]interface{}) (res ResponseData, err error) {
2024-12-14 19:09:06 +08:00
this.Method = GET
this.Uri = uri
reqParam := make(map[string]interface{})
if param != nil {
reqParam = *param
}
this.Param = reqParam
return this.Run(ctx)
}
// POST请求
2025-03-05 22:33:33 +08:00
func (this *RESTAPI) Post(ctx context.Context, uri string, param *map[string]interface{}) (res ResponseData, err error) {
2024-12-14 19:09:06 +08:00
this.Method = POST
this.Uri = uri
reqParam := make(map[string]interface{})
if param != nil {
reqParam = *param
}
this.Param = reqParam
return this.Run(ctx)
}
2025-03-05 22:21:00 +08:00
func (this *RESTAPI) Run(ctx context.Context) (ResponseData, error) {
var res *RESTAPIResult
var err error
2024-12-14 19:09:06 +08:00
if this.ApiKeyInfo == nil {
err = errors.New("APIKey不可为空")
2025-03-05 22:21:00 +08:00
if err != nil {
return nil, err
}
return res.V5Response, nil
2024-12-14 19:09:06 +08:00
}
procStart := time.Now()
defer func() {
if res != nil {
res.TotalUsedTime = time.Since(procStart)
}
}()
client := &http.Client{
Timeout: this.Timeout,
}
uri, body, err := this.GenReqInfo()
if err != nil {
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
url := this.EndPoint + uri
bodyBuf := new(bytes.Buffer)
bodyBuf.ReadFrom(strings.NewReader(body))
req, err := http.NewRequest(this.Method, url, bodyBuf)
if err != nil {
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
res = &RESTAPIResult{
Url: url,
Param: body,
}
// Sign and set request headers
2025-03-05 20:52:20 +08:00
timestamp := utils.IsoTime()
preHash := utils.PreHashString(timestamp, this.Method, uri, body)
2024-12-14 19:09:06 +08:00
//log.Println("preHash:", preHash)
2025-03-05 20:52:20 +08:00
sign, err := utils.HmacSha256Base64Signer(preHash, this.ApiKeyInfo.SecKey)
2024-12-14 19:09:06 +08:00
if err != nil {
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
//log.Println("sign:", sign)
headStr := this.SetHeaders(req, timestamp, sign)
res.Header = headStr
this.PrintRequest(req, body, preHash)
resp, err := client.Do(req)
if err != nil {
fmt.Println("请求失败!", err)
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
defer resp.Body.Close()
res.ReqUsedTime = time.Since(procStart)
resBuff, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("获取请求结果失败!", err)
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
res.Body = string(resBuff)
res.Code = resp.StatusCode
// 解析结果
var v5rsp Okexv5APIResponse
err = json.Unmarshal(resBuff, &v5rsp)
if err != nil {
fmt.Println("解析v5返回失败", err)
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
res.V5Response = v5rsp
2025-03-05 22:33:33 +08:00
return nil, err
2024-12-14 19:09:06 +08:00
}
/*
2024-12-16 11:41:20 +08:00
生成请求对应的参数
2024-12-14 19:09:06 +08:00
*/
func (this *RESTAPI) GenReqInfo() (uri string, body string, err error) {
uri = this.Uri
switch this.Method {
case GET:
getParam := []string{}
if len(this.Param) == 0 {
return
}
for k, v := range this.Param {
getParam = append(getParam, fmt.Sprintf("%v=%v", k, v))
}
uri = uri + "?" + strings.Join(getParam, "&")
case POST:
var rawBody []byte
rawBody, err = json.Marshal(this.Param)
if err != nil {
return
}
body = string(rawBody)
default:
err = errors.New("request type unknown!")
return
}
return
}
/*
2024-12-16 11:41:20 +08:00
Set http request headers:
Accept: application/json
Content-Type: application/json; charset=UTF-8 (default)
Cookie: locale=en_US (English)
OK-ACCESS-KEY: (Your setting)
OK-ACCESS-SIGN: (Use your setting, auto sign and add)
OK-ACCESS-TIMESTAMP: (Auto add)
OK-ACCESS-PASSPHRASE: Your setting
2024-12-14 19:09:06 +08:00
*/
func (this *RESTAPI) SetHeaders(request *http.Request, timestamp string, sign string) (header string) {
request.Header.Add(ACCEPT, APPLICATION_JSON)
header += ACCEPT + ":" + APPLICATION_JSON + "\n"
request.Header.Add(CONTENT_TYPE, APPLICATION_JSON_UTF8)
header += CONTENT_TYPE + ":" + APPLICATION_JSON_UTF8 + "\n"
request.Header.Add(COOKIE, LOCALE+ENGLISH)
header += COOKIE + ":" + LOCALE + ENGLISH + "\n"
request.Header.Add(OK_ACCESS_KEY, this.ApiKeyInfo.ApiKey)
header += OK_ACCESS_KEY + ":" + this.ApiKeyInfo.ApiKey + "\n"
request.Header.Add(OK_ACCESS_SIGN, sign)
header += OK_ACCESS_SIGN + ":" + sign + "\n"
request.Header.Add(OK_ACCESS_TIMESTAMP, timestamp)
header += OK_ACCESS_TIMESTAMP + ":" + timestamp + "\n"
request.Header.Add(OK_ACCESS_PASSPHRASE, this.ApiKeyInfo.PassPhrase)
header += OK_ACCESS_PASSPHRASE + ":" + this.ApiKeyInfo.PassPhrase + "\n"
//模拟盘交易标记
if this.isSimulate {
request.Header.Add(X_SIMULATE_TRADING, "1")
header += X_SIMULATE_TRADING + ":1" + "\n"
}
return
}
/*
2024-12-16 11:41:20 +08:00
打印header信息
2024-12-14 19:09:06 +08:00
*/
func (this *RESTAPI) PrintRequest(request *http.Request, body string, preHash string) {
if this.ApiKeyInfo.SecKey != "" {
fmt.Println(" Secret-Key: " + this.ApiKeyInfo.SecKey)
}
2025-03-05 20:52:20 +08:00
fmt.Println(" Request(" + utils.IsoTime() + "):")
2024-12-14 19:09:06 +08:00
fmt.Println("\tUrl: " + request.URL.String())
fmt.Println("\tMethod: " + strings.ToUpper(request.Method))
if len(request.Header) > 0 {
fmt.Println("\tHeaders: ")
for k, v := range request.Header {
if strings.Contains(k, "Ok-") {
k = strings.ToUpper(k)
}
fmt.Println("\t\t" + k + ": " + v[0])
}
}
fmt.Println("\tBody: " + body)
if preHash != "" {
fmt.Println(" PreHash: " + preHash)
}
}