mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Update request.go to fix concurrency nonce issues (#285)
* Updates nonce generation to adhere to fifo channel buffer before request executes by routine * removed unused variables, lns etc * Fix requested changes and added in timer that disengages lock if out of scope error occurs * Fixed woopsy daisy issue * Add benchmark, reduce time in force to unlock before stack insertion, add nil check for edge case * Remove unusued waitgroup field * use return nonce.Value and method, rm redundant nonce code, fix tests. * Fix linter issue: unnecessary conversion
This commit is contained in:
committed by
Adrian Gallagher
parent
1967507d40
commit
35b94268e0
@@ -730,6 +730,7 @@ func (c *Coinmarketcap) SendHTTPRequest(method, endpoint string, v url.Values, r
|
||||
strings.NewReader(""),
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
c.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ func (c *CurrencyConverter) SendHTTPRequest(endPoint string, values url.Values,
|
||||
nil,
|
||||
&result,
|
||||
auth,
|
||||
false,
|
||||
c.Verbose)
|
||||
if err != nil {
|
||||
return fmt.Errorf("currency converter API SendHTTPRequest error %s with path %s",
|
||||
|
||||
@@ -239,5 +239,6 @@ func (c *CurrencyLayer) SendHTTPRequest(endPoint string, values url.Values, resu
|
||||
nil,
|
||||
&result,
|
||||
auth,
|
||||
false,
|
||||
c.Verbose)
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ func (e *ExchangeRates) SendHTTPRequest(endPoint string, values url.Values, resu
|
||||
nil,
|
||||
&result,
|
||||
false,
|
||||
false,
|
||||
e.Verbose)
|
||||
if err != nil {
|
||||
return fmt.Errorf("exchangeRatesAPI SendHTTPRequest error %s with path %s",
|
||||
|
||||
@@ -263,5 +263,6 @@ func (f *Fixer) SendOpenHTTPRequest(endpoint string, v url.Values, result interf
|
||||
nil,
|
||||
result,
|
||||
auth,
|
||||
false,
|
||||
f.Verbose)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package fixer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
|
||||
)
|
||||
|
||||
// Please set API key and apikey subscription level for correct due diligence
|
||||
@@ -14,7 +16,20 @@ const (
|
||||
|
||||
var f Fixer
|
||||
|
||||
var isSetup bool
|
||||
|
||||
func setup(t *testing.T) {
|
||||
if !isSetup {
|
||||
err := f.Setup(base.Settings{})
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - Setup error", err)
|
||||
}
|
||||
isSetup = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRates(t *testing.T) {
|
||||
setup(t)
|
||||
_, err := f.GetRates("EUR", "AUD")
|
||||
if err == nil {
|
||||
t.Error("test failed - fixer GetRates() error", err)
|
||||
@@ -22,6 +37,7 @@ func TestGetRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetLatestRates(t *testing.T) {
|
||||
setup(t)
|
||||
_, err := f.GetLatestRates("EUR", "AUD")
|
||||
if err == nil {
|
||||
t.Error("test failed - fixer GetLatestRates() error", err)
|
||||
@@ -29,6 +45,7 @@ func TestGetLatestRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetHistoricalRates(t *testing.T) {
|
||||
setup(t)
|
||||
_, err := f.GetHistoricalRates("2013-12-24", "EUR", []string{"AUD,KRW"})
|
||||
if err == nil {
|
||||
t.Error("test failed - fixer GetHistoricalRates() error", err)
|
||||
@@ -36,6 +53,7 @@ func TestGetHistoricalRates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConvertCurrency(t *testing.T) {
|
||||
setup(t)
|
||||
_, err := f.ConvertCurrency("AUD", "EUR", "", 1337)
|
||||
if err == nil {
|
||||
t.Error("test failed - fixer ConvertCurrency() error", err)
|
||||
@@ -43,6 +61,7 @@ func TestConvertCurrency(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetTimeSeriesData(t *testing.T) {
|
||||
setup(t)
|
||||
_, err := f.GetTimeSeriesData("2013-12-24", "2013-12-25", "EUR", []string{"AUD,KRW"})
|
||||
if err == nil {
|
||||
t.Error("test failed - fixer GetTimeSeriesData() error", err)
|
||||
@@ -50,6 +69,7 @@ func TestGetTimeSeriesData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFluctuationData(t *testing.T) {
|
||||
setup(t)
|
||||
_, err := f.GetFluctuationData("2013-12-24", "2013-12-25", "EUR", []string{"AUD,KRW"})
|
||||
if err == nil {
|
||||
t.Error("test failed - fixer GetFluctuationData() error", err)
|
||||
|
||||
@@ -263,5 +263,6 @@ func (o *OXR) SendHTTPRequest(endpoint string, values url.Values, result interfa
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
o.Verbose)
|
||||
}
|
||||
|
||||
@@ -534,7 +534,7 @@ func (a *Alphapoint) SendHTTPRequest(method, path string, data map[string]interf
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, a.Verbose)
|
||||
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, false, a.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
@@ -543,17 +543,14 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name)
|
||||
}
|
||||
|
||||
if a.Nonce.Get() == 0 {
|
||||
a.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
a.Nonce.Inc()
|
||||
}
|
||||
n := a.Requester.GetNonce(true)
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/json"
|
||||
data["apiKey"] = a.APIKey
|
||||
data["apiNonce"] = a.Nonce.Get()
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(a.Nonce.String()+a.ClientID+a.APIKey), []byte(a.APISecret))
|
||||
data["apiNonce"] = n
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(n.String()+a.ClientID+a.APIKey),
|
||||
[]byte(a.APISecret))
|
||||
data["apiSig"] = common.StringToUpper(common.HexEncodeToString(hmac))
|
||||
path = fmt.Sprintf("%s/ajax/v%s/%s", a.APIUrl, alphapointAPIVersion, path)
|
||||
|
||||
@@ -562,5 +559,5 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, a.Verbose)
|
||||
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose)
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (a *ANX) SendHTTPRequest(path string, result interface{}) error {
|
||||
return a.SendPayload(http.MethodGet, path, nil, nil, result, false, a.Verbose)
|
||||
return a.SendPayload(http.MethodGet, path, nil, nil, result, false, false, a.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends a authenticated HTTP request
|
||||
@@ -411,14 +411,9 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name)
|
||||
}
|
||||
|
||||
if a.Nonce.Get() == 0 {
|
||||
a.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
a.Nonce.Inc()
|
||||
}
|
||||
|
||||
n := a.Requester.GetNonce(true)
|
||||
req := make(map[string]interface{})
|
||||
req["nonce"] = a.Nonce.String()[0:13]
|
||||
req["nonce"] = n.String()[0:13]
|
||||
path = fmt.Sprintf("api/%s/%s", anxAPIVersion, path)
|
||||
|
||||
for key, value := range params {
|
||||
@@ -440,7 +435,7 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf
|
||||
headers["Rest-Sign"] = common.Base64Encode(hmac)
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
return a.SendPayload(http.MethodPost, a.APIUrl+path, headers, bytes.NewBuffer(PayloadJSON), result, true, a.Verbose)
|
||||
return a.SendPayload(http.MethodPost, a.APIUrl+path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -594,7 +594,7 @@ func (b *Binance) GetAccount() (*Account, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (b *Binance) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthHTTPRequest sends an authenticated HTTP request
|
||||
@@ -630,7 +630,7 @@ func (b *Binance) SendAuthHTTPRequest(method, path string, params url.Values, re
|
||||
Message string `json:"msg"`
|
||||
}{}
|
||||
|
||||
err := b.SendPayload(method, path, headers, bytes.NewBuffer(nil), &interim, true, b.Verbose)
|
||||
err := b.SendPayload(method, path, headers, bytes.NewBuffer(nil), &interim, true, false, b.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -616,6 +616,7 @@ func (b *Bitfinex) WithdrawCryptocurrency(withdrawType, wallet, address, payment
|
||||
&response)
|
||||
}
|
||||
|
||||
// WithdrawFIAT requests a withdrawal from a designated fiat wallet
|
||||
func (b *Bitfinex) WithdrawFIAT(withdrawalType, walletType string, withdrawRequest *exchange.WithdrawRequest) ([]Withdrawal, error) {
|
||||
response := []Withdrawal{}
|
||||
req := make(map[string]interface{})
|
||||
@@ -1000,7 +1001,7 @@ func (b *Bitfinex) CloseMarginFunding(swapID int64) (Offer, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (b *Bitfinex) SendHTTPRequest(path string, result interface{}, verbose bool) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an autheticated http request and json
|
||||
@@ -1011,15 +1012,11 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
|
||||
b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
n := b.Requester.GetNonce(true)
|
||||
|
||||
req := make(map[string]interface{})
|
||||
req["request"] = fmt.Sprintf("%s%s", bitfinexAPIVersion, path)
|
||||
req["nonce"] = b.Nonce.String()
|
||||
req["nonce"] = n.String()
|
||||
|
||||
for key, value := range params {
|
||||
req[key] = value
|
||||
@@ -1048,6 +1045,7 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
|
||||
nil,
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
b.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -378,7 +378,7 @@ func (b *Bitflyer) GetTradingCommission() {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (b *Bitflyer) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthHTTPRequest sends an authenticated HTTP request
|
||||
|
||||
@@ -543,7 +543,7 @@ func (b *Bithumb) MarketSellOrder(currency string, units float64) (MarketSell, e
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *Bithumb) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bithumb
|
||||
@@ -556,15 +556,11 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r
|
||||
params = url.Values{}
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano() / int64(time.Millisecond))
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
n := b.Requester.GetNonceMilli().String()
|
||||
|
||||
params.Set("endpoint", path)
|
||||
payload := params.Encode()
|
||||
hmacPayload := path + string(0) + payload + string(0) + b.Nonce.String()
|
||||
hmacPayload := path + string(0) + payload + string(0) + n
|
||||
hmac := common.GetHMAC(common.HashSHA512,
|
||||
[]byte(hmacPayload),
|
||||
[]byte(b.APISecret))
|
||||
@@ -573,7 +569,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r
|
||||
headers := make(map[string]string)
|
||||
headers["Api-Key"] = b.APIKey
|
||||
headers["Api-Sign"] = common.Base64Encode([]byte(hmacStr))
|
||||
headers["Api-Nonce"] = b.Nonce.String()
|
||||
headers["Api-Nonce"] = n
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
var intermediary json.RawMessage
|
||||
@@ -589,6 +585,7 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r
|
||||
bytes.NewBufferString(payload),
|
||||
&intermediary,
|
||||
true,
|
||||
true,
|
||||
b.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -850,14 +850,14 @@ func (b *Bitmex) SendHTTPRequest(path string, params Parameter, result interface
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = b.SendPayload(http.MethodGet, encodedPath, nil, nil, &respCheck, false, b.Verbose)
|
||||
err = b.SendPayload(http.MethodGet, encodedPath, nil, nil, &respCheck, false, false, b.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.CaptureError(respCheck, result)
|
||||
}
|
||||
}
|
||||
err := b.SendPayload(http.MethodGet, path, nil, nil, &respCheck, false, b.Verbose)
|
||||
err := b.SendPayload(http.MethodGet, path, nil, nil, &respCheck, false, false, b.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -907,6 +907,7 @@ func (b *Bitmex) SendAuthenticatedHTTPRequest(verb, path string, params Paramete
|
||||
bytes.NewBuffer([]byte(payload)),
|
||||
&respCheck,
|
||||
true,
|
||||
false,
|
||||
b.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -645,7 +645,7 @@ func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount s
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *Bitstamp) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
@@ -654,19 +654,15 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
n := b.Requester.GetNonce(true).String()
|
||||
|
||||
if values == nil {
|
||||
values = url.Values{}
|
||||
}
|
||||
|
||||
values.Set("key", b.APIKey)
|
||||
values.Set("nonce", b.Nonce.String())
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(b.Nonce.String()+b.ClientID+b.APIKey), []byte(b.APISecret))
|
||||
values.Set("nonce", n)
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(n+b.ClientID+b.APIKey), []byte(b.APISecret))
|
||||
values.Set("signature", common.StringToUpper(common.HexEncodeToString(hmac)))
|
||||
|
||||
if v2 {
|
||||
@@ -691,7 +687,7 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
|
||||
Error string `json:"error"`
|
||||
}{}
|
||||
|
||||
err := b.SendPayload(http.MethodPost, path, headers, readerValues, &interim, true, b.Verbose)
|
||||
err := b.SendPayload(http.MethodPost, path, headers, readerValues, &interim, true, true, b.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -493,7 +493,7 @@ func (b *Bittrex) GetDepositHistory(currency string) (WithdrawalHistory, error)
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *Bittrex) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated http request to a desired
|
||||
@@ -503,13 +503,10 @@ func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, r
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
n := b.Requester.GetNonce(true).String()
|
||||
|
||||
values.Set("apikey", b.APIKey)
|
||||
values.Set("nonce", b.Nonce.String())
|
||||
values.Set("nonce", n)
|
||||
rawQuery := path + "?" + values.Encode()
|
||||
hmac := common.GetHMAC(
|
||||
common.HashSHA512, []byte(rawQuery), []byte(b.APISecret),
|
||||
@@ -517,7 +514,7 @@ func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, r
|
||||
headers := make(map[string]string)
|
||||
headers["apisign"] = common.HexEncodeToString(hmac)
|
||||
|
||||
return b.SendPayload(http.MethodGet, rawQuery, headers, nil, result, true, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, rawQuery, headers, nil, result, true, true, b.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -431,7 +431,7 @@ func (b *BTCMarkets) WithdrawAUD(accountName, accountNumber, bankName, bsbNumber
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *BTCMarkets) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, b.Verbose)
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedRequest sends an authenticated HTTP request
|
||||
@@ -441,11 +441,8 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
|
||||
b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
n := b.Requester.GetNonce(true).String()[0:13]
|
||||
|
||||
var req string
|
||||
payload := []byte("")
|
||||
|
||||
@@ -454,9 +451,9 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req = path + "\n" + b.Nonce.String()[0:13] + "\n" + string(payload)
|
||||
req = path + "\n" + n + "\n" + string(payload)
|
||||
} else {
|
||||
req = path + "\n" + b.Nonce.String()[0:13] + "\n"
|
||||
req = path + "\n" + n + "\n"
|
||||
}
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA512,
|
||||
@@ -474,7 +471,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
|
||||
headers["Accept-Charset"] = "UTF-8"
|
||||
headers["Content-Type"] = "application/json"
|
||||
headers["apikey"] = b.APIKey
|
||||
headers["timestamp"] = b.Nonce.String()[0:13]
|
||||
headers["timestamp"] = n
|
||||
headers["signature"] = common.Base64Encode(hmac)
|
||||
|
||||
return b.SendPayload(reqType,
|
||||
@@ -483,6 +480,7 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
|
||||
bytes.NewBuffer(payload),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
b.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ func (b *BTSE) GetFills(orderID, productID, before, after, limit string) (*Fille
|
||||
// SendHTTPRequest sends an HTTP request to the desired endpoint
|
||||
func (b *BTSE) SendHTTPRequest(method, endpoint string, result interface{}) error {
|
||||
p := fmt.Sprintf("%s/%s", btseAPIURL, endpoint)
|
||||
return b.SendPayload(method, p, nil, nil, &result, false, b.Verbose)
|
||||
return b.SendPayload(method, p, nil, nil, &result, false, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the desired endpoint
|
||||
@@ -278,7 +278,7 @@ func (b *BTSE) SendAuthenticatedHTTPRequest(method, endpoint string, req map[str
|
||||
log.Debugf("Sending %s request to URL %s with params %s\n", method, p, string(payload))
|
||||
}
|
||||
return b.SendPayload(method, p, headers, strings.NewReader(string(payload)),
|
||||
&result, true, b.Verbose)
|
||||
&result, true, false, b.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -792,7 +792,7 @@ func (c *CoinbasePro) GetTrailingVolume() ([]Volume, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (c *CoinbasePro) SendHTTPRequest(path string, result interface{}) error {
|
||||
return c.SendPayload(http.MethodGet, path, nil, nil, result, false, c.Verbose)
|
||||
return c.SendPayload(http.MethodGet, path, nil, nil, result, false, false, c.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP reque
|
||||
@@ -815,12 +815,12 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m
|
||||
}
|
||||
}
|
||||
|
||||
nonce := c.Nonce.GetValue(c.Name, false).String()
|
||||
message := nonce + method + "/" + path + string(payload)
|
||||
n := c.Requester.GetNonce(true).String()
|
||||
message := n + method + "/" + path + string(payload)
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(c.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["CB-ACCESS-SIGN"] = common.Base64Encode(hmac)
|
||||
headers["CB-ACCESS-TIMESTAMP"] = nonce
|
||||
headers["CB-ACCESS-TIMESTAMP"] = n
|
||||
headers["CB-ACCESS-KEY"] = c.APIKey
|
||||
headers["CB-ACCESS-PASSPHRASE"] = c.ClientID
|
||||
headers["Content-Type"] = "application/json"
|
||||
@@ -831,6 +831,7 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m
|
||||
bytes.NewBuffer(payload),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
c.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -338,16 +338,12 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name)
|
||||
}
|
||||
|
||||
if c.Nonce.Get() == 0 {
|
||||
c.Nonce.Set(time.Now().Unix())
|
||||
} else {
|
||||
c.Nonce.Inc()
|
||||
}
|
||||
n := c.Requester.GetNonce(false)
|
||||
|
||||
if params == nil {
|
||||
params = map[string]interface{}{}
|
||||
}
|
||||
params["nonce"] = c.Nonce.Get()
|
||||
params["nonce"] = n
|
||||
params["request"] = apiRequest
|
||||
|
||||
payload, err := common.JSONEncode(params)
|
||||
@@ -374,6 +370,7 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{
|
||||
bytes.NewBuffer(payload),
|
||||
&rawMsg,
|
||||
authenticated,
|
||||
true,
|
||||
c.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -225,7 +225,7 @@ func (c *COINUT) GetNonce() int64 {
|
||||
c.Nonce.Inc()
|
||||
}
|
||||
|
||||
return c.Nonce.Get()
|
||||
return int64(c.Nonce.Get())
|
||||
}
|
||||
|
||||
// WsSetInstrumentList fetches instrument list and propagates a local cache
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/nonce"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
@@ -262,7 +261,6 @@ type Base struct {
|
||||
APIWithdrawPermissions uint32
|
||||
APIAuthPEMKeySupport bool
|
||||
APISecret, APIKey, APIAuthPEMKey, ClientID string
|
||||
Nonce nonce.Nonce
|
||||
TakerFee, MakerFee, Fee float64
|
||||
BaseCurrencies currency.Currencies
|
||||
AvailablePairs currency.Pairs
|
||||
|
||||
@@ -371,7 +371,7 @@ func (e *EXMO) GetWalletHistory(date int64) (WalletHistory, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (e *EXMO) SendHTTPRequest(path string, result interface{}) error {
|
||||
return e.SendPayload(http.MethodGet, path, nil, nil, result, false, e.Verbose)
|
||||
return e.SendPayload(http.MethodGet, path, nil, nil, result, false, false, e.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
|
||||
@@ -381,12 +381,8 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va
|
||||
e.Name)
|
||||
}
|
||||
|
||||
if e.Nonce.Get() == 0 {
|
||||
e.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
e.Nonce.Inc()
|
||||
}
|
||||
vals.Set("nonce", e.Nonce.String())
|
||||
n := e.Requester.GetNonce(true).String()
|
||||
vals.Set("nonce", n)
|
||||
|
||||
payload := vals.Encode()
|
||||
hash := common.GetHMAC(common.HashSHA512,
|
||||
@@ -413,6 +409,7 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va
|
||||
strings.NewReader(payload),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
e.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -391,7 +391,7 @@ func (g *Gateio) CancelExistingOrder(orderID int64, symbol string) (bool, error)
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (g *Gateio) SendHTTPRequest(path string, result interface{}) error {
|
||||
return g.SendPayload(http.MethodGet, path, nil, nil, result, false, g.Verbose)
|
||||
return g.SendPayload(http.MethodGet, path, nil, nil, result, false, false, g.Verbose)
|
||||
}
|
||||
|
||||
// CancelAllExistingOrders all orders for a given symbol and side
|
||||
@@ -484,6 +484,7 @@ func (g *Gateio) SendAuthenticatedHTTPRequest(method, endpoint, param string, re
|
||||
strings.NewReader(param),
|
||||
&intermidiary,
|
||||
true,
|
||||
false,
|
||||
g.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -490,7 +490,7 @@ func (g *Gemini) PostHeartbeat() (string, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (g *Gemini) SendHTTPRequest(path string, result interface{}) error {
|
||||
return g.SendPayload(http.MethodGet, path, nil, nil, result, false, g.Verbose)
|
||||
return g.SendPayload(http.MethodGet, path, nil, nil, result, false, false, g.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the
|
||||
@@ -503,7 +503,7 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
|
||||
headers := make(map[string]string)
|
||||
req := make(map[string]interface{})
|
||||
req["request"] = fmt.Sprintf("/v%s/%s", geminiAPIVersion, path)
|
||||
req["nonce"] = g.Nonce.GetValue(g.Name, false)
|
||||
req["nonce"] = g.Requester.GetNonce(true).String()
|
||||
|
||||
for key, value := range params {
|
||||
req[key] = value
|
||||
@@ -528,7 +528,7 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
|
||||
headers["X-GEMINI-SIGNATURE"] = common.HexEncodeToString(hmac)
|
||||
headers["Cache-Control"] = "no-cache"
|
||||
|
||||
return g.SendPayload(method, g.APIUrl+"/v1/"+path, headers, strings.NewReader(""), result, true, g.Verbose)
|
||||
return g.SendPayload(method, g.APIUrl+"/v1/"+path, headers, strings.NewReader(""), result, true, false, g.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -591,7 +591,7 @@ func (h *HitBTC) TransferBalance(currency, from, to string, amount float64) (boo
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (h *HitBTC) SendHTTPRequest(path string, result interface{}) error {
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, h.Verbose)
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated http request
|
||||
@@ -611,6 +611,7 @@ func (h *HitBTC) SendAuthenticatedHTTPRequest(method, endpoint string, values ur
|
||||
bytes.NewBufferString(values.Encode()),
|
||||
result,
|
||||
true,
|
||||
false,
|
||||
h.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -831,7 +831,7 @@ func (h *HUOBI) CancelWithdraw(withdrawID int64) (int64, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (h *HUOBI) SendHTTPRequest(path string, result interface{}) error {
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, h.Verbose)
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API
|
||||
@@ -908,7 +908,7 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url
|
||||
body = encoded
|
||||
}
|
||||
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewReader(body), result, true, h.Verbose)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewReader(body), result, true, false, h.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -826,7 +826,7 @@ func (h *HUOBIHADAX) CancelWithdraw(withdrawID int64) (int64, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (h *HUOBIHADAX) SendHTTPRequest(path string, result interface{}) error {
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, h.Verbose)
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPPostRequest sends authenticated requests to the HUOBI API
|
||||
@@ -853,7 +853,7 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPPostRequest(method, endpoint, postBody
|
||||
signatureParams.Set("Signature", common.Base64Encode(hmac))
|
||||
urlPath := common.EncodeURLValues(fmt.Sprintf("%s%s", h.APIUrl, endpoint),
|
||||
signatureParams)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(postBodyValues), result, true, h.Verbose)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(postBodyValues), result, true, false, h.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API
|
||||
@@ -879,7 +879,7 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPRequest(method, endpoint string, value
|
||||
|
||||
urlPath := common.EncodeURLValues(fmt.Sprintf("%s%s", h.APIUrl, endpoint),
|
||||
values)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(""), result, true, h.Verbose)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(""), result, true, false, h.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -343,7 +343,7 @@ func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (i *ItBit) SendHTTPRequest(path string, result interface{}) error {
|
||||
return i.SendPayload(http.MethodGet, path, nil, nil, result, false, i.Verbose)
|
||||
return i.SendPayload(http.MethodGet, path, nil, nil, result, false, false, i.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request to itBit
|
||||
@@ -377,22 +377,22 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method, path string, params map[str
|
||||
}
|
||||
}
|
||||
|
||||
nonce := i.Nonce.GetValue(i.Name, false).String()
|
||||
n := i.Requester.GetNonce(true).String()
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
|
||||
|
||||
message, err := common.JSONEncode([]string{method, urlPath, string(PayloadJSON), nonce, timestamp})
|
||||
message, err := common.JSONEncode([]string{method, urlPath, string(PayloadJSON), n, timestamp})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hash := common.GetSHA256([]byte(nonce + string(message)))
|
||||
hash := common.GetSHA256([]byte(n + string(message)))
|
||||
hmac := common.GetHMAC(common.HashSHA512, []byte(urlPath+string(hash)), []byte(i.APISecret))
|
||||
signature := common.Base64Encode(hmac)
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Authorization"] = i.ClientID + ":" + signature
|
||||
headers["X-Auth-Timestamp"] = timestamp
|
||||
headers["X-Auth-Nonce"] = nonce
|
||||
headers["X-Auth-Nonce"] = n
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
var intermediary json.RawMessage
|
||||
@@ -403,7 +403,7 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method, path string, params map[str
|
||||
RequestID string `json:"requestId"`
|
||||
}{}
|
||||
|
||||
err = i.SendPayload(method, urlPath, headers, bytes.NewBuffer(PayloadJSON), &intermediary, true, i.Verbose)
|
||||
err = i.SendPayload(method, urlPath, headers, bytes.NewBuffer(PayloadJSON), &intermediary, true, true, i.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -926,7 +926,7 @@ func GetError(apiErrors []string) error {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP requests
|
||||
func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
|
||||
return k.SendPayload(http.MethodGet, path, nil, nil, result, false, k.Verbose)
|
||||
return k.SendPayload(http.MethodGet, path, nil, nil, result, false, false, k.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
|
||||
@@ -937,13 +937,9 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values,
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("/%s/private/%s", krakenAPIVersion, method)
|
||||
if k.Nonce.Get() == 0 {
|
||||
k.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
k.Nonce.Inc()
|
||||
}
|
||||
|
||||
params.Set("nonce", k.Nonce.String())
|
||||
n := k.Requester.GetNonce(true).String()
|
||||
params.Set("nonce", n)
|
||||
|
||||
secret, err := common.Base64Decode(k.APISecret)
|
||||
if err != nil {
|
||||
@@ -972,6 +968,7 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values,
|
||||
strings.NewReader(encoded),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
k.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -410,7 +410,7 @@ type WebsocketSubscriptionData struct {
|
||||
Depth int64 `json:"depth,omitempty"` // Optional - depth associated with book subscription in number of levels each side, default 10. Valid Options are: 10, 25, 100, 500, 1000
|
||||
}
|
||||
|
||||
// WebsocketDataResponse holds all data response types
|
||||
// WebsocketEventResponse holds all data response types
|
||||
type WebsocketEventResponse struct {
|
||||
Event string `json:"event"`
|
||||
Status string `json:"status"`
|
||||
@@ -422,26 +422,32 @@ type WebsocketEventResponse struct {
|
||||
WebsocketErrorResponse
|
||||
}
|
||||
|
||||
// WebsocketSubscriptionEventResponse defines a websocket socket event response
|
||||
type WebsocketSubscriptionEventResponse struct {
|
||||
ChannelID int64 `json:"channelID"`
|
||||
}
|
||||
|
||||
// WebsocketSubscriptionResponseData defines a websocket subscription response
|
||||
type WebsocketSubscriptionResponseData struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// WebsocketStatusResponse defines a websocket status response
|
||||
type WebsocketStatusResponse struct {
|
||||
ConnectionID float64 `json:"connectionID"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
// WebsocketDataResponse defines a websocket data type
|
||||
type WebsocketDataResponse []interface{}
|
||||
|
||||
// WebsocketErrorResponse defines a websocket error response
|
||||
type WebsocketErrorResponse struct {
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
}
|
||||
|
||||
// Holds relevant data for channels to identify what we're doing
|
||||
// WebsocketChannelData Holds relevant data for channels to identify what we're
|
||||
// doing
|
||||
type WebsocketChannelData struct {
|
||||
Subscription string
|
||||
Pair currency.Pair
|
||||
|
||||
@@ -267,7 +267,7 @@ func (k *Kraken) WsHandleDataResponse(response WebsocketDataResponse) {
|
||||
}
|
||||
}
|
||||
|
||||
// WsHandleDataResponse classifies the WS response and sends to appropriate handler
|
||||
// WsHandleEventResponse classifies the WS response and sends to appropriate handler
|
||||
func (k *Kraken) WsHandleEventResponse(response *WebsocketEventResponse) {
|
||||
switch response.Event {
|
||||
case krakenWsHeartbeat:
|
||||
@@ -391,7 +391,7 @@ func getSubscriptionChannelData(id int64) WebsocketChannelData {
|
||||
return WebsocketChannelData{}
|
||||
}
|
||||
|
||||
// resubscribeToChannel will attempt to unsubscribe and resubscribe to a channel
|
||||
// ResubscribeToChannel will attempt to unsubscribe and resubscribe to a channel
|
||||
func (k *Kraken) ResubscribeToChannel(channel string, pair currency.Pair) {
|
||||
// Kraken WS formats pairs with / but config and REST use -
|
||||
formattedPair := strings.ToUpper(strings.Replace(pair.String(), "-", "/", 1))
|
||||
|
||||
@@ -334,7 +334,7 @@ func (l *LakeBTC) CreateWithdraw(amount float64, accountID string) (Withdraw, er
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated http request
|
||||
func (l *LakeBTC) SendHTTPRequest(path string, result interface{}) error {
|
||||
return l.SendPayload(http.MethodGet, path, nil, nil, result, false, l.Verbose)
|
||||
return l.SendPayload(http.MethodGet, path, nil, nil, result, false, false, l.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an autheticated HTTP request to a LakeBTC
|
||||
@@ -343,13 +343,9 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
|
||||
}
|
||||
|
||||
if l.Nonce.Get() == 0 {
|
||||
l.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
l.Nonce.Inc()
|
||||
}
|
||||
n := l.Requester.GetNonce(true).String()
|
||||
|
||||
req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", l.Nonce.String(), l.APIKey, method, params)
|
||||
req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", n, l.APIKey, method, params)
|
||||
hmac := common.GetHMAC(common.HashSHA1, []byte(req), []byte(l.APISecret))
|
||||
|
||||
if l.Verbose {
|
||||
@@ -371,7 +367,7 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
|
||||
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(l.APIKey+":"+common.HexEncodeToString(hmac)))
|
||||
headers["Content-Type"] = "application/json-rpc"
|
||||
|
||||
return l.SendPayload(http.MethodPost, l.APIUrl, headers, strings.NewReader(string(data)), result, true, l.Verbose)
|
||||
return l.SendPayload(http.MethodPost, l.APIUrl, headers, strings.NewReader(string(data)), result, true, true, l.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -726,7 +726,7 @@ func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (l *LocalBitcoins) SendHTTPRequest(path string, result interface{}) error {
|
||||
return l.SendPayload(http.MethodGet, path, nil, nil, result, false, l.Verbose)
|
||||
return l.SendPayload(http.MethodGet, path, nil, nil, result, false, false, l.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to
|
||||
@@ -736,19 +736,15 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, params
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
|
||||
}
|
||||
|
||||
if l.Nonce.Get() == 0 {
|
||||
l.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
l.Nonce.Inc()
|
||||
}
|
||||
n := l.Requester.GetNonce(true).String()
|
||||
|
||||
path = "/api/" + path
|
||||
encoded := params.Encode()
|
||||
message := l.Nonce.String() + l.APIKey + path + encoded
|
||||
message := n + l.APIKey + path + encoded
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(l.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["Apiauth-Key"] = l.APIKey
|
||||
headers["Apiauth-Nonce"] = l.Nonce.String()
|
||||
headers["Apiauth-Nonce"] = n
|
||||
headers["Apiauth-Signature"] = common.StringToUpper(common.HexEncodeToString(hmac))
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
@@ -760,7 +756,7 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, params
|
||||
path += "?" + encoded
|
||||
}
|
||||
|
||||
return l.SendPayload(method, l.APIUrl+path, headers, strings.NewReader(encoded), result, true, l.Verbose)
|
||||
return l.SendPayload(method, l.APIUrl+path, headers, strings.NewReader(encoded), result, true, true, l.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -2,18 +2,12 @@ package nonce
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Nonce struct holds the nonce value
|
||||
type Nonce struct {
|
||||
// Standard nonce
|
||||
n int64
|
||||
// Hash table exclusive exchange specific nonce values
|
||||
boundedCall map[string]int64
|
||||
boundedMtx sync.Mutex
|
||||
}
|
||||
|
||||
// Inc increments the nonce value
|
||||
@@ -22,12 +16,12 @@ func (n *Nonce) Inc() {
|
||||
}
|
||||
|
||||
// Get retrives the nonce value
|
||||
func (n *Nonce) Get() int64 {
|
||||
return atomic.LoadInt64(&n.n)
|
||||
func (n *Nonce) Get() Value {
|
||||
return Value(atomic.LoadInt64(&n.n))
|
||||
}
|
||||
|
||||
// GetInc increments and returns the value of the nonce
|
||||
func (n *Nonce) GetInc() int64 {
|
||||
func (n *Nonce) GetInc() Value {
|
||||
n.Inc()
|
||||
return n.Get()
|
||||
}
|
||||
@@ -39,34 +33,12 @@ func (n *Nonce) Set(val int64) {
|
||||
|
||||
// String returns a string version of the nonce
|
||||
func (n *Nonce) String() string {
|
||||
return strconv.FormatInt(n.Get(), 10)
|
||||
return n.Get().String()
|
||||
}
|
||||
|
||||
// Value is a return type for GetValue
|
||||
type Value int64
|
||||
|
||||
// GetValue returns a nonce value and can be set as a higher precision. Values
|
||||
// stored in an exchange specific hash table using a single locked call.
|
||||
func (n *Nonce) GetValue(exchName string, nanoPrecision bool) Value {
|
||||
n.boundedMtx.Lock()
|
||||
defer n.boundedMtx.Unlock()
|
||||
|
||||
if n.boundedCall == nil {
|
||||
n.boundedCall = make(map[string]int64)
|
||||
}
|
||||
|
||||
if n.boundedCall[exchName] == 0 {
|
||||
if nanoPrecision {
|
||||
n.boundedCall[exchName] = time.Now().UnixNano()
|
||||
return Value(n.boundedCall[exchName])
|
||||
}
|
||||
n.boundedCall[exchName] = time.Now().Unix()
|
||||
return Value(n.boundedCall[exchName])
|
||||
}
|
||||
n.boundedCall[exchName]++
|
||||
return Value(n.boundedCall[exchName])
|
||||
}
|
||||
|
||||
// String is a Value method that changes format to a string
|
||||
func (v Value) String() string {
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package nonce
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -10,7 +9,7 @@ func TestInc(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(1)
|
||||
nonce.Inc()
|
||||
expected := int64(2)
|
||||
expected := Value(2)
|
||||
result := nonce.Get()
|
||||
if result != expected {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
@@ -20,7 +19,7 @@ func TestInc(t *testing.T) {
|
||||
func TestGet(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(112321313)
|
||||
expected := int64(112321313)
|
||||
expected := Value(112321313)
|
||||
result := nonce.Get()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
@@ -30,7 +29,7 @@ func TestGet(t *testing.T) {
|
||||
func TestGetInc(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(1)
|
||||
expected := int64(2)
|
||||
expected := Value(2)
|
||||
result := nonce.GetInc()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
@@ -40,7 +39,7 @@ func TestGetInc(t *testing.T) {
|
||||
func TestSet(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(1)
|
||||
expected := int64(1)
|
||||
expected := Value(1)
|
||||
result := nonce.Get()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
@@ -55,30 +54,10 @@ func TestString(t *testing.T) {
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %s got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetValue(t *testing.T) {
|
||||
var nonce Nonce
|
||||
timeNowNano := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
nValue := nonce.GetValue("dingdong", true).String()
|
||||
|
||||
if timeNowNano == nValue {
|
||||
t.Error("Test failed - GetValue() error, incorrect values")
|
||||
}
|
||||
|
||||
if len(nValue) != 19 {
|
||||
t.Error("Test failed - GetValue() error, incorrect values")
|
||||
}
|
||||
|
||||
timeNowUnix := nonce.GetValue("dongding", false)
|
||||
if len(timeNowUnix.String()) != 10 {
|
||||
t.Error("Test failed - GetValue() error, incorrect values")
|
||||
}
|
||||
|
||||
n := nonce.GetValue("dongding", false)
|
||||
if n != timeNowUnix+1 {
|
||||
t.Error("Test failed - GetValue() error, incorrect values")
|
||||
v := nonce.Get()
|
||||
if expected != v.String() {
|
||||
t.Errorf("Test failed. Expected %s got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +73,7 @@ func TestNonceConcurrency(t *testing.T) {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
result := nonce.Get()
|
||||
expected := int64(12312 + 1000)
|
||||
expected := Value(12312 + 1000)
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ func (o *OKGroup) SendHTTPRequest(httpMethod, requestType, requestPath string, d
|
||||
|
||||
errCap := errCapFormat{}
|
||||
errCap.Result = true
|
||||
err = o.SendPayload(strings.ToUpper(httpMethod), path, headers, bytes.NewBuffer(payload), &intermediary, authenticated, o.Verbose)
|
||||
err = o.SendPayload(strings.ToUpper(httpMethod), path, headers, bytes.NewBuffer(payload), &intermediary, authenticated, false, o.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package poloniex
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -479,14 +480,21 @@ func (p *Poloniex) GetAuthenticatedTradeHistory(start, end, limit int64) (Authen
|
||||
}
|
||||
|
||||
values.Set("currencyPair", "all")
|
||||
var result AuthenticatedTradeHistoryAll
|
||||
var result json.RawMessage
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexTradeHistory, values, &result.Data)
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexTradeHistory, values, &result)
|
||||
if err != nil {
|
||||
return AuthenticatedTradeHistoryAll{}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
var nodata []interface{}
|
||||
err = json.Unmarshal(result, &nodata)
|
||||
if err == nil {
|
||||
return AuthenticatedTradeHistoryAll{}, nil
|
||||
}
|
||||
|
||||
var mainResult AuthenticatedTradeHistoryAll
|
||||
return mainResult, json.Unmarshal(result, &mainResult.Data)
|
||||
}
|
||||
|
||||
// PlaceOrder places a new order on the exchange
|
||||
@@ -856,6 +864,7 @@ func (p *Poloniex) SendHTTPRequest(path string, result interface{}) error {
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
p.Verbose)
|
||||
}
|
||||
|
||||
@@ -869,13 +878,9 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
headers["Key"] = p.APIKey
|
||||
|
||||
if p.Nonce.Get() == 0 {
|
||||
p.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
p.Nonce.Inc()
|
||||
}
|
||||
n := p.Requester.GetNonce(true).String()
|
||||
|
||||
values.Set("nonce", p.Nonce.String())
|
||||
values.Set("nonce", n)
|
||||
values.Set("command", endpoint)
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA512,
|
||||
@@ -892,6 +897,7 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values
|
||||
bytes.NewBufferString(values.Encode()),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
p.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,25 +19,27 @@ const (
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
}
|
||||
var isSetup bool
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Poloniex Setup() init error")
|
||||
if !isSetup {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Poloniex Setup() init error")
|
||||
}
|
||||
poloniexConfig.AuthenticatedAPISupport = true
|
||||
poloniexConfig.APIKey = apiKey
|
||||
poloniexConfig.APISecret = apiSecret
|
||||
p.SetDefaults()
|
||||
p.Setup(&poloniexConfig)
|
||||
isSetup = true
|
||||
}
|
||||
poloniexConfig.AuthenticatedAPISupport = true
|
||||
poloniexConfig.APIKey = apiKey
|
||||
poloniexConfig.APISecret = apiSecret
|
||||
|
||||
p.Setup(&poloniexConfig)
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetTicker()
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetTicker() error")
|
||||
@@ -45,6 +47,7 @@ func TestGetTicker(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetVolume(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetVolume()
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetVolume() error")
|
||||
@@ -52,6 +55,7 @@ func TestGetVolume(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetOrderbook("BTC_XMR", 50)
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetOrderbook() error", err)
|
||||
@@ -59,6 +63,7 @@ func TestGetOrderbook(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetTradeHistory("BTC_XMR", "", "")
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetTradeHistory() error", err)
|
||||
@@ -66,6 +71,7 @@ func TestGetTradeHistory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetChartData(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetChartData("BTC_XMR", "1405699200", "1405699400", "300")
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetChartData() error", err)
|
||||
@@ -73,6 +79,7 @@ func TestGetChartData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetCurrencies()
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetCurrencies() error", err)
|
||||
@@ -80,6 +87,7 @@ func TestGetCurrencies(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetLoanOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetLoanOrders("BTC")
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetLoanOrders() error", err)
|
||||
@@ -101,6 +109,7 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
p.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
@@ -115,7 +124,7 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
@@ -135,14 +144,6 @@ func TestGetFee(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee IsMaker
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.IsMaker = true
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee Negative purchase price
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
@@ -195,7 +196,8 @@ func TestGetFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.NoFiatWithdrawalsText
|
||||
|
||||
withdrawPermissions := p.FormatWithdrawPermissions()
|
||||
@@ -206,7 +208,7 @@ func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
@@ -222,7 +224,7 @@ func TestGetActiveOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
@@ -248,7 +250,7 @@ func areTestAPIKeysSet() bool {
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
@@ -276,7 +278,7 @@ func TestSubmitOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
@@ -303,7 +305,7 @@ func TestCancelExchangeOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
@@ -334,6 +336,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.ModifyOrder(&exchange.ModifyOrder{OrderID: "1337", Price: 1337})
|
||||
if err == nil {
|
||||
t.Error("Test Failed - ModifyOrder() error")
|
||||
@@ -341,7 +344,7 @@ func TestModifyOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
var withdrawCryptoRequest = exchange.WithdrawRequest{
|
||||
Amount: 100,
|
||||
@@ -364,7 +367,7 @@ func TestWithdraw(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
@@ -380,7 +383,7 @@ func TestWithdrawFiat(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
p.SetDefaults()
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
@@ -396,6 +399,9 @@ func TestWithdrawInternationalBank(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() {
|
||||
_, err := p.GetDepositAddress(currency.DASH, "")
|
||||
if err != nil {
|
||||
|
||||
@@ -163,8 +163,8 @@ type OpenOrdersResponse struct {
|
||||
Data []Order
|
||||
}
|
||||
|
||||
// AuthentictedTradeHistory holds client trade history information
|
||||
type AuthentictedTradeHistory struct {
|
||||
// AuthenticatedTradeHistory holds client trade history information
|
||||
type AuthenticatedTradeHistory struct {
|
||||
GlobalTradeID int64 `json:"globalTradeID"`
|
||||
TradeID int64 `json:"tradeID,string"`
|
||||
Date string `json:"date"`
|
||||
@@ -179,12 +179,12 @@ type AuthentictedTradeHistory struct {
|
||||
|
||||
// AuthenticatedTradeHistoryAll holds the full client trade history
|
||||
type AuthenticatedTradeHistoryAll struct {
|
||||
Data map[string][]AuthentictedTradeHistory
|
||||
Data map[string][]AuthenticatedTradeHistory
|
||||
}
|
||||
|
||||
// AuthenticatedTradeHistoryResponse is a response type for trade history
|
||||
type AuthenticatedTradeHistoryResponse struct {
|
||||
Data []AuthentictedTradeHistory
|
||||
Data []AuthenticatedTradeHistory
|
||||
}
|
||||
|
||||
// ResultingTrades holds resultant trade information
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/nonce"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
@@ -36,7 +37,10 @@ type Requester struct {
|
||||
timeoutRetryAttempts int
|
||||
m sync.Mutex
|
||||
Jobs chan Job
|
||||
disengage chan struct{}
|
||||
WorkerStarted bool
|
||||
Nonce nonce.Nonce
|
||||
fifoLock sync.Mutex
|
||||
}
|
||||
|
||||
// RateLimit struct
|
||||
@@ -214,6 +218,7 @@ func New(name string, authLimit, unauthLimit *RateLimit, httpRequester *http.Cli
|
||||
AuthLimit: authLimit,
|
||||
Name: name,
|
||||
Jobs: make(chan Job, maxRequestJobs),
|
||||
disengage: make(chan struct{}, 1),
|
||||
timeoutRetryAttempts: defaultTimeoutRetryAttempts,
|
||||
}
|
||||
}
|
||||
@@ -391,29 +396,39 @@ func (r *Requester) worker() {
|
||||
}
|
||||
|
||||
// SendPayload handles sending HTTP/HTTPS requests
|
||||
func (r *Requester) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, verbose bool) error {
|
||||
func (r *Requester) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, nonceEnabled, verbose bool) error {
|
||||
if !nonceEnabled {
|
||||
r.lock()
|
||||
}
|
||||
|
||||
if r == nil || r.Name == "" {
|
||||
r.unlock()
|
||||
return errors.New("not initiliased, SetDefaults() called before making request?")
|
||||
}
|
||||
|
||||
if !IsValidMethod(method) {
|
||||
r.unlock()
|
||||
return fmt.Errorf("incorrect method supplied %s: supported %s", method, supportedMethods)
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
r.unlock()
|
||||
return errors.New("invalid path")
|
||||
}
|
||||
|
||||
req, err := r.checkRequest(method, path, body, headers)
|
||||
if err != nil {
|
||||
r.unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
if !r.RequiresRateLimiter() {
|
||||
r.unlock()
|
||||
return r.DoRequest(req, path, body, result, authRequest, verbose)
|
||||
}
|
||||
|
||||
if len(r.Jobs) == maxRequestJobs {
|
||||
r.unlock()
|
||||
return errors.New("max request jobs reached")
|
||||
}
|
||||
|
||||
@@ -443,6 +458,7 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string,
|
||||
log.Debugf("%s request. Attaching new job.", r.Name)
|
||||
}
|
||||
r.Jobs <- newJob
|
||||
r.unlock()
|
||||
|
||||
if verbose {
|
||||
log.Debugf("%s request. Waiting for job to complete.", r.Name)
|
||||
@@ -455,6 +471,34 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string,
|
||||
return resp.Error
|
||||
}
|
||||
|
||||
// GetNonce returns a nonce for requests. This locks and enforces concurrent
|
||||
// nonce FIFO on the buffered job channel
|
||||
func (r *Requester) GetNonce(isNano bool) nonce.Value {
|
||||
r.lock()
|
||||
if r.Nonce.Get() == 0 {
|
||||
if isNano {
|
||||
r.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
r.Nonce.Set(time.Now().Unix())
|
||||
}
|
||||
return r.Nonce.Get()
|
||||
}
|
||||
r.Nonce.Inc()
|
||||
return r.Nonce.Get()
|
||||
}
|
||||
|
||||
// GetNonceMilli returns a nonce for requests. This locks and enforces concurrent
|
||||
// nonce FIFO on the buffered job channel this is for millisecond
|
||||
func (r *Requester) GetNonceMilli() nonce.Value {
|
||||
r.lock()
|
||||
if r.Nonce.Get() == 0 {
|
||||
r.Nonce.Set(time.Now().UnixNano() / int64(time.Millisecond))
|
||||
return r.Nonce.Get()
|
||||
}
|
||||
r.Nonce.Inc()
|
||||
return r.Nonce.Get()
|
||||
}
|
||||
|
||||
// SetProxy sets a proxy address to the client transport
|
||||
func (r *Requester) SetProxy(p *url.URL) error {
|
||||
if p.String() == "" {
|
||||
@@ -467,3 +511,33 @@ func (r *Requester) SetProxy(p *url.URL) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// lock locks and sets up an issue timer, if something errors out of scope it
|
||||
// automatically unlocks
|
||||
func (r *Requester) lock() {
|
||||
if r.disengage == nil {
|
||||
r.disengage = make(chan struct{}, 1)
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
r.fifoLock.Lock()
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
timer := time.NewTimer(50 * time.Millisecond)
|
||||
wg.Done()
|
||||
select {
|
||||
case <-timer.C:
|
||||
log.Errorf("Unlocking due to possible error for %s", r.Name)
|
||||
r.fifoLock.Unlock()
|
||||
|
||||
case <-r.disengage:
|
||||
return
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// unlock unlocks mtx and shuts down a timer
|
||||
func (r *Requester) unlock() {
|
||||
r.disengage <- struct{}{}
|
||||
r.fifoLock.Unlock()
|
||||
}
|
||||
|
||||
@@ -199,8 +199,8 @@ func TestCheckRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDoRequest(t *testing.T) {
|
||||
var test *Requester
|
||||
err := test.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true)
|
||||
var test = new(Requester)
|
||||
err := test.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true)
|
||||
if err == nil {
|
||||
t.Fatal("not iniitalised")
|
||||
}
|
||||
@@ -211,17 +211,17 @@ func TestDoRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
r.Name = "bitfinex"
|
||||
err = r.SendPayload("BLAH", "https://www.google.com", nil, nil, nil, false, true)
|
||||
err = r.SendPayload("BLAH", "https://www.google.com", nil, nil, nil, false, false, true)
|
||||
if err == nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "", nil, nil, nil, false, true)
|
||||
err = r.SendPayload(http.MethodGet, "", nil, nil, nil, false, false, true)
|
||||
if err == nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -233,7 +233,7 @@ func TestDoRequest(t *testing.T) {
|
||||
r.SetRateLimit(false, time.Second, 0)
|
||||
r.SetRateLimit(true, time.Second, 0)
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func TestDoRequest(t *testing.T) {
|
||||
t.Fatal("unexepcted values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, true)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -261,27 +261,27 @@ func TestDoRequest(t *testing.T) {
|
||||
t.Fatal("unexepcted values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, true, true)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, true, false, true)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, true)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["content-type"] = "content/text"
|
||||
err = r.SendPayload(http.MethodPost, "https://bitfinex.com", headers, nil, result, false, true)
|
||||
err = r.SendPayload(http.MethodPost, "https://bitfinex.com", headers, nil, result, false, false, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r.StartCycle()
|
||||
r.UnauthLimit.SetRequests(100)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func TestDoRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
r.HTTPClient.Timeout = 1 * time.Second
|
||||
err = r.SendPayload(http.MethodPost, "https://httpstat.us/200?sleep=20000", nil, nil, nil, false, true)
|
||||
err = r.SendPayload(http.MethodPost, "https://httpstat.us/200?sleep=20000", nil, nil, nil, false, false, true)
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -322,3 +322,11 @@ func TestDoRequest(t *testing.T) {
|
||||
t.Error("failed to set proxy")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRequestLockMech(b *testing.B) {
|
||||
var r = new(Requester)
|
||||
var meep interface{}
|
||||
for n := 0; n < b.N; n++ {
|
||||
r.SendPayload(http.MethodGet, "127.0.0.1", nil, nil, &meep, false, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,6 +336,7 @@ func (y *Yobit) SendHTTPRequest(path string, result interface{}) error {
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
y.Verbose)
|
||||
}
|
||||
|
||||
@@ -350,12 +351,9 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res
|
||||
params = url.Values{}
|
||||
}
|
||||
|
||||
if y.Nonce.Get() == 0 {
|
||||
y.Nonce.Set(time.Now().Unix())
|
||||
} else {
|
||||
y.Nonce.Inc()
|
||||
}
|
||||
params.Set("nonce", y.Nonce.String())
|
||||
n := y.Requester.GetNonce(false).String()
|
||||
|
||||
params.Set("nonce", n)
|
||||
params.Set("method", path)
|
||||
|
||||
encoded := params.Encode()
|
||||
@@ -381,6 +379,7 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res
|
||||
strings.NewReader(encoded),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
y.Verbose)
|
||||
}
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ func (z *ZB) GetCryptoAddress(currency currency.Code) (UserAddress, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (z *ZB) SendHTTPRequest(path string, result interface{}) error {
|
||||
return z.SendPayload(http.MethodGet, path, nil, nil, result, false, z.Verbose)
|
||||
return z.SendPayload(http.MethodGet, path, nil, nil, result, false, false, z.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the zb API
|
||||
@@ -397,6 +397,7 @@ func (z *ZB) SendAuthenticatedHTTPRequest(httpMethod string, params url.Values,
|
||||
strings.NewReader(""),
|
||||
&intermediary,
|
||||
true,
|
||||
false,
|
||||
z.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -346,7 +346,7 @@ func (z *ZB) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]exc
|
||||
Amount: order.TotalAmount,
|
||||
Exchange: z.Name,
|
||||
OrderDate: orderDate,
|
||||
Price: float64(order.Price),
|
||||
Price: order.Price,
|
||||
OrderSide: orderSide,
|
||||
CurrencyPair: symbol,
|
||||
})
|
||||
@@ -403,7 +403,7 @@ func (z *ZB) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]exc
|
||||
Amount: order.TotalAmount,
|
||||
Exchange: z.Name,
|
||||
OrderDate: orderDate,
|
||||
Price: float64(order.Price),
|
||||
Price: order.Price,
|
||||
OrderSide: orderSide,
|
||||
CurrencyPair: symbol,
|
||||
})
|
||||
|
||||
14
testdata/configtest.json
vendored
14
testdata/configtest.json
vendored
@@ -1319,5 +1319,19 @@
|
||||
"supportedExchanges": "ANX,Kraken"
|
||||
}
|
||||
],
|
||||
"connectionMonitor": {
|
||||
"preferredDNSList": [
|
||||
"8.8.8.8",
|
||||
"8.8.4.4",
|
||||
"1.1.1.1",
|
||||
"1.0.0.1"
|
||||
],
|
||||
"preferredDomainList": [
|
||||
"www.google.com",
|
||||
"www.cloudflare.com",
|
||||
"www.facebook.com"
|
||||
],
|
||||
"checkInterval": 1000000000
|
||||
},
|
||||
"fiatDispayCurrency": ""
|
||||
}
|
||||
Reference in New Issue
Block a user