github.com/frankrap/okex-api@v1.0.4/client.go (about)

     1  package okex
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/url"
    10  	"strconv"
    11  	"strings"
    12  	"time"
    13  )
    14  
    15  /*
    16   http client, request, response
    17   @author Tony Tian
    18   @date 2018-03-17
    19   @version 1.0.0
    20  */
    21  
    22  type Client struct {
    23  	Config     Config
    24  	HttpClient *http.Client
    25  }
    26  
    27  type ApiMessage struct {
    28  	Code    int    `json:"code"`
    29  	Message string `json:"message"`
    30  }
    31  
    32  /*
    33   Get a http client
    34  */
    35  func NewClient(config Config) *Client {
    36  	var client Client
    37  	client.Config = config
    38  	httpClient := config.HTTPClient
    39  	if httpClient == nil {
    40  		timeout := config.TimeoutSecond
    41  		if timeout <= 0 {
    42  			timeout = 30
    43  		}
    44  		transport := &http.Transport{}
    45  		if config.ProxyURL != "" {
    46  			proxyURL_, err := url.Parse(config.ProxyURL)
    47  			if err != nil {
    48  				return nil
    49  			}
    50  			transport.Proxy = http.ProxyURL(proxyURL_)
    51  		}
    52  		httpClient = &http.Client{
    53  			Transport: transport,
    54  			Timeout:   time.Duration(timeout) * time.Second,
    55  		}
    56  	}
    57  	client.HttpClient = httpClient
    58  	return &client
    59  }
    60  
    61  /*
    62   Send a http request to remote server and get a response data
    63  */
    64  func (client *Client) Request(method string, requestPath string,
    65  	params, result interface{}) (respBody []byte, response *http.Response, err error) {
    66  	config := client.Config
    67  	// uri
    68  	endpoint := config.Endpoint
    69  	if strings.HasSuffix(config.Endpoint, "/") {
    70  		endpoint = config.Endpoint[0 : len(config.Endpoint)-1]
    71  	}
    72  	url := endpoint + requestPath
    73  
    74  	// get json and bin styles request body
    75  	var jsonBody string
    76  	var binBody = bytes.NewReader(make([]byte, 0))
    77  	if params != nil {
    78  		jsonBody, binBody, err = ParseRequestParams(params)
    79  		if err != nil {
    80  			return respBody, response, err
    81  		}
    82  	}
    83  
    84  	// get a http request
    85  	request, err := http.NewRequest(method, url, binBody)
    86  	if err != nil {
    87  		return respBody, response, err
    88  	}
    89  
    90  	// Sign and set request headers
    91  	timestamp := IsoTime()
    92  	preHash := PreHashString(timestamp, method, requestPath, jsonBody)
    93  	sign, err := HmacSha256Base64Signer(preHash, config.SecretKey)
    94  	if err != nil {
    95  		return respBody, response, err
    96  	}
    97  	Headers(request, config, timestamp, sign)
    98  
    99  	if config.IsPrint {
   100  		printRequest(config, request, jsonBody, preHash)
   101  	}
   102  
   103  	// send a request to remote server, and get a response
   104  	response, err = client.HttpClient.Do(request)
   105  	if err != nil {
   106  		return respBody, response, err
   107  	}
   108  	defer response.Body.Close()
   109  
   110  	// get a response results and parse
   111  	status := response.StatusCode
   112  	message := response.Status
   113  	body, err := ioutil.ReadAll(response.Body)
   114  	if err != nil {
   115  		return respBody, response, err
   116  	}
   117  
   118  	respBody = body
   119  
   120  	if config.IsPrint {
   121  		printResponse(status, message, body)
   122  	}
   123  
   124  	responseBodyString := string(body)
   125  
   126  	response.Header.Add(ResultDataJsonString, responseBodyString)
   127  
   128  	limit := response.Header.Get("Ok-Limit")
   129  	if limit != "" {
   130  		var page PageResult
   131  		page.Limit = StringToInt(limit)
   132  		from := response.Header.Get("Ok-From")
   133  		if from != "" {
   134  			page.From = StringToInt(from)
   135  		}
   136  		to := response.Header.Get("Ok-To")
   137  		if to != "" {
   138  			page.To = StringToInt(to)
   139  		}
   140  		pageJsonString, err := Struct2JsonString(page)
   141  		if err != nil {
   142  			return respBody, response, err
   143  		}
   144  		response.Header.Add(ResultPageJsonString, pageJsonString)
   145  	}
   146  
   147  	if status >= 200 && status < 300 {
   148  		//fmt.Printf("Resp: %v", string(body))
   149  		if body != nil && result != nil {
   150  			err := JsonBytes2Struct(body, result)
   151  			if err != nil {
   152  				return respBody, response, err
   153  			}
   154  		}
   155  		return respBody, response, nil
   156  	} else if status >= 400 || status <= 500 {
   157  		errMsg := "Http error(400~500) result: status=" + IntToString(status) + ", message=" + message + ", body=" + responseBodyString
   158  		fmt.Println(errMsg)
   159  		if body != nil {
   160  			err := errors.New(errMsg)
   161  			return respBody, response, err
   162  		}
   163  	} else {
   164  		fmt.Println("Http error result: status=" + IntToString(status) + ", message=" + message + ", body=" + responseBodyString)
   165  		return respBody, response, errors.New(message)
   166  	}
   167  	return respBody, response, nil
   168  }
   169  
   170  func printRequest(config Config, request *http.Request, body string, preHash string) {
   171  	if config.SecretKey != "" {
   172  		fmt.Println("  Secret-Key: " + config.SecretKey)
   173  	}
   174  	fmt.Println("  Request(" + IsoTime() + "):")
   175  	fmt.Println("\tUrl: " + request.URL.String())
   176  	fmt.Println("\tMethod: " + strings.ToUpper(request.Method))
   177  	if len(request.Header) > 0 {
   178  		fmt.Println("\tHeaders: ")
   179  		for k, v := range request.Header {
   180  			if strings.Contains(k, "Ok-") {
   181  				k = strings.ToUpper(k)
   182  			}
   183  			fmt.Println("\t\t" + k + ": " + v[0])
   184  		}
   185  	}
   186  	fmt.Println("\tBody: " + body)
   187  	if preHash != "" {
   188  		fmt.Println("  PreHash: " + preHash)
   189  	}
   190  }
   191  
   192  func printResponse(status int, message string, body []byte) {
   193  	fmt.Println("  Response(" + IsoTime() + "):")
   194  	statusString := strconv.Itoa(status)
   195  	message = strings.Replace(message, statusString, "", -1)
   196  	message = strings.Trim(message, " ")
   197  	fmt.Println("\tStatus: " + statusString)
   198  	fmt.Println("\tMessage: " + message)
   199  	fmt.Println("\tBody: " + string(body))
   200  }