change infra of http client

This commit is contained in:
wuhewuhe 2023-11-03 15:29:17 +01:00
parent 65ab0cd6e2
commit 411090e9d8
11 changed files with 81 additions and 38 deletions

View File

@ -1,13 +1,13 @@
package bybit package bybit_connector
import ( import (
"bybit.go.api/handlers"
"bytes" "bytes"
"context" "context"
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha256"
"encoding/json" "encoding/json"
"fmt" "fmt"
handlers "github.com/wuhewuhe/bybit.go.api/handlers"
"io" "io"
"log" "log"
"net/http" "net/http"
@ -31,6 +31,20 @@ type Client struct {
type doFunc func(req *http.Request) (*http.Response, error) type doFunc func(req *http.Request) (*http.Response, error)
type ClientOption func(*Client)
func WithDebug(debug bool) ClientOption {
return func(c *Client) {
c.Debug = debug
}
}
func WithBaseURL(baseURL string) ClientOption {
return func(c *Client) {
c.BaseURL = baseURL
}
}
func currentTimestamp() int64 { func currentTimestamp() int64 {
return FormatTimestamp(time.Now()) return FormatTimestamp(time.Now())
} }
@ -40,6 +54,14 @@ func FormatTimestamp(t time.Time) int64 {
return t.UnixNano() / int64(time.Millisecond) return t.UnixNano() / int64(time.Millisecond)
} }
type ServerResponse struct {
RetCode int `json:"retCode"`
RetMsg string `json:"retMsg"`
Result interface{} `json:"result"`
RetExtInfo struct{} `json:"retExtInfo"`
Time int64 `json:"time"`
}
func PrettyPrint(i interface{}) string { func PrettyPrint(i interface{}) string {
s, _ := json.MarshalIndent(i, "", "\t") s, _ := json.MarshalIndent(i, "", "\t")
return string(s) return string(s)
@ -51,21 +73,22 @@ func (c *Client) debug(format string, v ...interface{}) {
} }
} }
// NewClient Create client function for initialising new Bybit client // NewBybitHttpClient NewClient Create client function for initialising new Bybit client
func NewClient(apiKey string, secretKey string, baseURL ...string) *Client { func NewBybitHttpClient(apiKey string, secretKey string, options ...ClientOption) *Client {
url := "https://api.bybit.com" c := &Client{
if len(baseURL) > 0 {
url = baseURL[0]
}
return &Client{
APIKey: apiKey, APIKey: apiKey,
SecretKey: secretKey, SecretKey: secretKey,
BaseURL: url, BaseURL: "https://api.bybit.com",
HTTPClient: http.DefaultClient, HTTPClient: http.DefaultClient,
Logger: log.New(os.Stderr, Name, log.LstdFlags), Logger: log.New(os.Stderr, Name, log.LstdFlags),
} }
// Apply the provided options
for _, opt := range options {
opt(c)
}
return c
} }
func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) { func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
@ -120,7 +143,7 @@ func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
if queryString != "" { if queryString != "" {
fullURL = fmt.Sprintf("%s?%s", fullURL, queryString) fullURL = fmt.Sprintf("%s?%s", fullURL, queryString)
} }
// c.debug("full url: %s, body: %s", fullURL, bodyString) c.debug("full url: %s, body: %s", fullURL, bodyString)
r.fullURL = fullURL r.fullURL = fullURL
r.header = header r.header = header
r.body = body r.body = body
@ -135,7 +158,7 @@ func (c *Client) callAPI(ctx context.Context, r *request, opts ...RequestOption)
} }
req = req.WithContext(ctx) req = req.WithContext(ctx)
req.Header = r.header req.Header = r.header
// c.debug("request: %#v", req) c.debug("request: %#v", req)
f := c.do f := c.do
if f == nil { if f == nil {
f = c.HTTPClient.Do f = c.HTTPClient.Do
@ -156,15 +179,17 @@ func (c *Client) callAPI(ctx context.Context, r *request, opts ...RequestOption)
err = cerr err = cerr
} }
}() }()
// c.debug("response: %#v", res) c.debug("response: %#v", res)
c.debug("response body: %s", string(data)) c.debug("response body: %s", string(data))
// c.debug("response status code: %d", res.StatusCode) c.debug("response status code: %d", res.StatusCode)
if res.StatusCode >= http.StatusBadRequest { if res.StatusCode >= http.StatusBadRequest {
apiErr := new(handlers.APIError) var (
apiErr = new(handlers.APIError)
)
e := json.Unmarshal(data, apiErr) e := json.Unmarshal(data, apiErr)
if e != nil { if e != nil {
// c.debug("failed to unmarshal json: %s", e) c.debug("failed to unmarshal json: %s", e)
} }
return nil, apiErr return nil, apiErr
} }

View File

@ -1,4 +1,4 @@
package bybit package bybit_connector
import ( import (
"crypto/hmac" "crypto/hmac"

View File

@ -1,4 +1,4 @@
package bybit package bybit_connector
const ( const (
Name = "bybit.api.go" Name = "bybit.api.go"

View File

@ -1,9 +1,9 @@
package main package main
import ( import (
bybit "bybit.go.api"
"context" "context"
"fmt" "fmt"
bybit "github.com/wuhewuhe/bybit.go.api"
) )
func main() { func main() {
@ -12,12 +12,13 @@ func main() {
func ServerTime() { func ServerTime() {
client := bybit.NewClient("", "") client := bybit.NewBybitHttpClient("", "")
// set to debug mode
client.Debug = true
// NewServerTimeService // NewServerTimeService
serverTime := client.NewServerTimeService().Do(context.Background()) serverTime, err := client.NewServerTimeService().Do(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Println(bybit.PrettyPrint(serverTime)) fmt.Println(bybit.PrettyPrint(serverTime))
} }

2
go.mod
View File

@ -1,4 +1,4 @@
module bybit.go.api module github.com/wuhewuhe/bybit.go.api
go 1.21 go 1.21

View File

@ -1,6 +1,9 @@
package handlers package handlers
import "fmt" import (
"errors"
"fmt"
)
// APIError define API error when response status is 4xx or 5xx // APIError define API error when response status is 4xx or 5xx
type APIError struct { type APIError struct {
@ -15,6 +18,7 @@ func (e APIError) Error() string {
// IsAPIError check if e is an API error // IsAPIError check if e is an API error
func IsAPIError(e error) bool { func IsAPIError(e error) bool {
_, ok := e.(*APIError) var APIError *APIError
ok := errors.As(e, &APIError)
return ok return ok
} }

View File

@ -1,23 +1,36 @@
package bybit package bybit_connector
import ( import (
"context" "context"
"encoding/json"
"net/http" "net/http"
) )
// Binance Check Server Time endpoint (GET /v5/market/time) type ServerTimeResult struct {
TimeSecond string `json:"timeSecond"`
TimeNano string `json:"timeNano"`
}
// ServerTime Binance Check Server Time endpoint (GET /v5/market/time)
type ServerTime struct { type ServerTime struct {
c *Client c *Client
} }
// Send the request // Do Send the request
func (s *ServerTime) Do(ctx context.Context, opts ...RequestOption) (res []byte) { func (s *ServerTime) Do(ctx context.Context, opts ...RequestOption) (res *ServerResponse, err error) {
r := &request{ r := &request{
method: http.MethodGet, method: http.MethodGet,
endpoint: "/v5/market/time", endpoint: "/v5/market/time",
secType: secTypeNone, secType: secTypeNone,
} }
data, _ := s.c.callAPI(ctx, r, opts...) data, err := s.c.callAPI(ctx, r, opts...)
res = data if err != nil {
return res return nil, err
}
res = new(ServerResponse)
err = json.Unmarshal(data, res)
if err != nil {
return nil, err
}
return res, nil
} }

View File

@ -1,4 +1,4 @@
package bybit package bybit_connector
import ( import (
"fmt" "fmt"

View File

@ -1 +1 @@
package bybit package bybit_connector