mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
Coinut: Fix websocket not parsing instruments, improve nonce matching and error handling (#1495)
WsConnect is calling GetInstruments, and when that fails, erroring out
and not subscribing to anything.
The response to get instruments is an object {}, which skips the
IncomingWithData check in wsReadData for arrays [].
The check in wsHandleData depended on client_ord_id, but I figure so
long as there's a nonce which matches, we can palm it off.
This results simutaneously in having to move the login handler back to
it's waiting nonce-parser, and also simplifying/deduping it.
This commit is contained in:
@@ -608,6 +608,15 @@ type WsTradeHistoryTradeData struct {
|
||||
TransactionID int64 `json:"trans_id"`
|
||||
}
|
||||
|
||||
// WsLoginReq Login request message
|
||||
type WsLoginReq struct {
|
||||
Request string `json:"request"`
|
||||
Username string `json:"username"`
|
||||
Nonce int64 `json:"nonce"`
|
||||
Hmac string `json:"hmac_sha256"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// WsLoginResponse ws response data
|
||||
type WsLoginResponse struct {
|
||||
APIKey string `json:"api_key"`
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
@@ -58,10 +59,12 @@ func (c *COINUT) WsConnect() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = c.wsAuthenticate(context.TODO())
|
||||
if err != nil {
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
log.Errorln(log.WebsocketMgr, err)
|
||||
|
||||
if c.IsWebsocketAuthenticationSupported() {
|
||||
if err = c.wsAuthenticate(context.TODO()); err != nil {
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
log.Errorln(log.WebsocketMgr, c.Name+" "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// define bi-directional communication
|
||||
@@ -75,6 +78,8 @@ func (c *COINUT) WsConnect() error {
|
||||
func (c *COINUT) wsReadData() {
|
||||
defer c.Websocket.Wg.Done()
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
for {
|
||||
resp := c.Websocket.Conn.ReadMessage()
|
||||
if resp.Raw == nil {
|
||||
@@ -100,7 +105,7 @@ func (c *COINUT) wsReadData() {
|
||||
c.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
err = c.wsHandleData(context.TODO(), individualJSON)
|
||||
err = c.wsHandleData(ctx, individualJSON)
|
||||
if err != nil {
|
||||
c.Websocket.DataHandler <- err
|
||||
}
|
||||
@@ -112,7 +117,7 @@ func (c *COINUT) wsReadData() {
|
||||
c.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
err = c.wsHandleData(context.TODO(), resp.Raw)
|
||||
err = c.wsHandleData(ctx, resp.Raw)
|
||||
if err != nil {
|
||||
c.Websocket.DataHandler <- err
|
||||
}
|
||||
@@ -120,7 +125,7 @@ func (c *COINUT) wsReadData() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *COINUT) wsHandleData(ctx context.Context, respRaw []byte) error {
|
||||
func (c *COINUT) wsHandleData(_ context.Context, respRaw []byte) error {
|
||||
if strings.HasPrefix(string(respRaw), "[") {
|
||||
var orders []wsOrderContainer
|
||||
err := json.Unmarshal(respRaw, &orders)
|
||||
@@ -142,10 +147,8 @@ func (c *COINUT) wsHandleData(ctx context.Context, respRaw []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.Contains(string(respRaw), "client_ord_id") {
|
||||
if c.Websocket.Match.IncomingWithData(incoming.Nonce, respRaw) {
|
||||
return nil
|
||||
}
|
||||
if c.Websocket.Match.IncomingWithData(incoming.Nonce, respRaw) {
|
||||
return nil
|
||||
}
|
||||
|
||||
format, err := c.GetPairFormat(asset.Spot, true)
|
||||
@@ -156,27 +159,6 @@ func (c *COINUT) wsHandleData(ctx context.Context, respRaw []byte) error {
|
||||
switch incoming.Reply {
|
||||
case "hb":
|
||||
channels["hb"] <- respRaw
|
||||
case "login":
|
||||
var login WsLoginResponse
|
||||
err := json.Unmarshal(respRaw, &login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
creds, err := c.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var endpointFailure []byte
|
||||
if login.APIKey != creds.Key {
|
||||
endpointFailure = []byte("failed to authenticate")
|
||||
}
|
||||
|
||||
if c.Websocket.Match.IncomingWithData(login.Nonce, endpointFailure) {
|
||||
return nil
|
||||
}
|
||||
|
||||
case "user_balance":
|
||||
var userBalance WsUserBalanceResponse
|
||||
err := json.Unmarshal(respRaw, &userBalance)
|
||||
@@ -662,8 +644,7 @@ func (c *COINUT) Unsubscribe(channelToUnsubscribe []subscription.Subscription) e
|
||||
Subscribe: false,
|
||||
Nonce: getNonce(),
|
||||
}
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(subscribe.Nonce,
|
||||
subscribe)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(subscribe.Nonce, subscribe)
|
||||
if err != nil {
|
||||
errs = common.AppendError(errs, err)
|
||||
continue
|
||||
@@ -695,43 +676,31 @@ func (c *COINUT) wsAuthenticate(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
timestamp := time.Now().Unix()
|
||||
nonce := getNonce()
|
||||
payload := creds.ClientID + "|" +
|
||||
strconv.FormatInt(timestamp, 10) + "|" +
|
||||
strconv.FormatInt(nonce, 10)
|
||||
|
||||
hmac, err := crypto.GetHMAC(crypto.HashSHA256,
|
||||
[]byte(payload),
|
||||
[]byte(creds.Key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
loginRequest := struct {
|
||||
Request string `json:"request"`
|
||||
Username string `json:"username"`
|
||||
Nonce int64 `json:"nonce"`
|
||||
Hmac string `json:"hmac_sha256"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}{
|
||||
r := WsLoginReq{
|
||||
Request: "login",
|
||||
Username: creds.ClientID,
|
||||
Nonce: nonce,
|
||||
Hmac: crypto.HexEncodeToString(hmac),
|
||||
Timestamp: timestamp,
|
||||
Nonce: getNonce(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(loginRequest.Nonce,
|
||||
loginRequest)
|
||||
payload := creds.ClientID + "|" + strconv.FormatInt(r.Timestamp, 10) + "|" + strconv.FormatInt(r.Nonce, 10)
|
||||
hmac, err := crypto.GetHMAC(crypto.HashSHA256, []byte(payload), []byte(creds.Key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp != nil {
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
return fmt.Errorf("%v %s", c.Name, resp)
|
||||
r.Hmac = crypto.HexEncodeToString(hmac)
|
||||
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(r.Nonce, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respKey, err := jsonparser.GetUnsafeString(resp, "api_key")
|
||||
if err != nil || respKey != creds.Key {
|
||||
return errors.New("failed to authenticate")
|
||||
}
|
||||
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -743,8 +712,7 @@ func (c *COINUT) wsGetAccountBalance() (*UserBalance, error) {
|
||||
Request: "user_balance",
|
||||
Nonce: getNonce(),
|
||||
}
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(accBalance.Nonce,
|
||||
accBalance)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(accBalance.Nonce, accBalance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -780,8 +748,7 @@ func (c *COINUT) wsSubmitOrder(o *WsSubmitOrderParameters) (*order.Detail, error
|
||||
if o.OrderID > 0 {
|
||||
orderSubmissionRequest.OrderID = o.OrderID
|
||||
}
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(orderSubmissionRequest.Nonce,
|
||||
orderSubmissionRequest)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(orderSubmissionRequest.Nonce, orderSubmissionRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -824,8 +791,7 @@ func (c *COINUT) wsSubmitOrders(orders []WsSubmitOrderParameters) ([]order.Detai
|
||||
|
||||
orderRequest.Nonce = getNonce()
|
||||
orderRequest.Request = "new_orders"
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(orderRequest.Nonce,
|
||||
orderRequest)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(orderRequest.Nonce, orderRequest)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
return nil, errs
|
||||
@@ -861,8 +827,7 @@ func (c *COINUT) wsGetOpenOrders(curr string) (*WsUserOpenOrdersResponse, error)
|
||||
openOrdersRequest.Nonce = getNonce()
|
||||
openOrdersRequest.InstrumentID = c.instrumentMap.LookupID(curr)
|
||||
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(openOrdersRequest.Nonce,
|
||||
openOrdersRequest)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(openOrdersRequest.Nonce, openOrdersRequest)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -895,8 +860,7 @@ func (c *COINUT) wsCancelOrder(cancellation *WsCancelOrderParameters) (*CancelOr
|
||||
cancellationRequest.OrderID = cancellation.OrderID
|
||||
cancellationRequest.Nonce = getNonce()
|
||||
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(cancellationRequest.Nonce,
|
||||
cancellationRequest)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(cancellationRequest.Nonce, cancellationRequest)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -937,8 +901,7 @@ func (c *COINUT) wsCancelOrders(cancellations []WsCancelOrderParameters) (*Cance
|
||||
|
||||
cancelOrderRequest.Request = "cancel_orders"
|
||||
cancelOrderRequest.Nonce = getNonce()
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(cancelOrderRequest.Nonce,
|
||||
cancelOrderRequest)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(cancelOrderRequest.Nonce, cancelOrderRequest)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
@@ -968,8 +931,7 @@ func (c *COINUT) wsGetTradeHistory(p currency.Pair, start, limit int64) (*WsTrad
|
||||
request.Start = start
|
||||
request.Limit = limit
|
||||
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(request.Nonce,
|
||||
request)
|
||||
resp, err := c.Websocket.Conn.SendMessageReturnResponse(request.Nonce, request)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user