mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 15:10:03 +00:00
* Renames func. Creates new func to setup pinghander either via gorilla style or our own
* Cleans up all ping pong handlers.......
* Clears up issues, makes naming a bit better
* Adds tests
* Adds ping support to binance
* Cleans up ping pongs and adds a comment
* Cleans up waitgroup stuff.
* DISCREETLY cleans up woeful function
* Fixes Kraken ping message type. Removes unnecessary test property. Adds `if err == websocket.ErrCloseSent {` to ping func
* +1 for +v
192 lines
5.5 KiB
Go
192 lines
5.5 KiB
Go
package btse
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
|
|
log "github.com/thrasher-corp/gocryptotrader/logger"
|
|
)
|
|
|
|
const (
|
|
btseWebsocket = "wss://ws.btse.com/spotWS"
|
|
btseWebsocketTimer = 57 * time.Second
|
|
)
|
|
|
|
// WsConnect connects the websocket client
|
|
func (b *BTSE) WsConnect() error {
|
|
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
|
|
return errors.New(wshandler.WebsocketNotEnabled)
|
|
}
|
|
var dialer websocket.Dialer
|
|
err := b.WebsocketConn.Dial(&dialer, http.Header{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
b.WebsocketConn.SetupPingHandler(wshandler.WebsocketPingHandler{
|
|
MessageType: websocket.PingMessage,
|
|
Delay: btseWebsocketTimer,
|
|
})
|
|
go b.WsHandleData()
|
|
b.GenerateDefaultSubscriptions()
|
|
|
|
return nil
|
|
}
|
|
|
|
// WsHandleData handles read data from websocket connection
|
|
func (b *BTSE) WsHandleData() {
|
|
b.Websocket.Wg.Add(1)
|
|
|
|
defer func() {
|
|
b.Websocket.Wg.Done()
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-b.Websocket.ShutdownC:
|
|
return
|
|
|
|
default:
|
|
resp, err := b.WebsocketConn.ReadMessage()
|
|
if err != nil {
|
|
b.Websocket.ReadMessageErrors <- err
|
|
return
|
|
}
|
|
b.Websocket.TrafficAlert <- struct{}{}
|
|
|
|
type Result map[string]interface{}
|
|
result := Result{}
|
|
err = json.Unmarshal(resp.Raw, &result)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
switch {
|
|
case strings.Contains(result["topic"].(string), "tradeHistory"):
|
|
var tradeHistory wsTradeHistory
|
|
err = json.Unmarshal(resp.Raw, &tradeHistory)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
for x := range tradeHistory.Data {
|
|
side := order.Buy.String()
|
|
if tradeHistory.Data[x].Gain == -1 {
|
|
side = order.Sell.String()
|
|
}
|
|
b.Websocket.DataHandler <- wshandler.TradeData{
|
|
Timestamp: time.Unix(0, tradeHistory.Data[x].TransactionTime*int64(time.Millisecond)),
|
|
CurrencyPair: currency.NewPairFromString(strings.Replace(tradeHistory.Topic, "tradeHistory:", "", 1)),
|
|
AssetType: asset.Spot,
|
|
Exchange: b.Name,
|
|
Price: tradeHistory.Data[x].Price,
|
|
Amount: tradeHistory.Data[x].Amount,
|
|
Side: side,
|
|
}
|
|
}
|
|
case strings.Contains(result["topic"].(string), "orderBookApi"):
|
|
var t wsOrderBook
|
|
err = json.Unmarshal(resp.Raw, &t)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
var newOB orderbook.Base
|
|
var price, amount float64
|
|
for i := range t.Data.SellQuote {
|
|
p := strings.Replace(t.Data.SellQuote[i].Price, ",", "", -1)
|
|
price, err = strconv.ParseFloat(p, 64)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
a := strings.Replace(t.Data.SellQuote[i].Size, ",", "", -1)
|
|
amount, err = strconv.ParseFloat(a, 64)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
newOB.Asks = append(newOB.Asks, orderbook.Item{
|
|
Price: price,
|
|
Amount: amount,
|
|
})
|
|
}
|
|
for j := range t.Data.BuyQuote {
|
|
p := strings.Replace(t.Data.BuyQuote[j].Price, ",", "", -1)
|
|
price, err = strconv.ParseFloat(p, 64)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
a := strings.Replace(t.Data.BuyQuote[j].Size, ",", "", -1)
|
|
amount, err = strconv.ParseFloat(a, 64)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
newOB.Bids = append(newOB.Bids, orderbook.Item{
|
|
Price: price,
|
|
Amount: amount,
|
|
})
|
|
}
|
|
newOB.AssetType = asset.Spot
|
|
newOB.Pair = currency.NewPairFromString(t.Topic[strings.Index(t.Topic, ":")+1 : strings.Index(t.Topic, "_")])
|
|
newOB.ExchangeName = b.Name
|
|
err = b.Websocket.Orderbook.LoadSnapshot(&newOB)
|
|
if err != nil {
|
|
b.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
b.Websocket.DataHandler <- wshandler.WebsocketOrderbookUpdate{Pair: newOB.Pair,
|
|
Asset: asset.Spot,
|
|
Exchange: b.Name}
|
|
default:
|
|
log.Warnf(log.ExchangeSys,
|
|
"%s: unhandled websocket response: %s", b.Name, resp.Raw)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
|
|
func (b *BTSE) GenerateDefaultSubscriptions() {
|
|
var channels = []string{"orderBookApi:%s_0", "tradeHistory:%s"}
|
|
pairs := b.GetEnabledPairs(asset.Spot)
|
|
var subscriptions []wshandler.WebsocketChannelSubscription
|
|
for i := range channels {
|
|
for j := range pairs {
|
|
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
|
|
Channel: fmt.Sprintf(channels[i], pairs[j]),
|
|
Currency: pairs[j],
|
|
})
|
|
}
|
|
}
|
|
b.Websocket.SubscribeToChannels(subscriptions)
|
|
}
|
|
|
|
// Subscribe sends a websocket message to receive data from the channel
|
|
func (b *BTSE) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
|
|
var sub wsSub
|
|
sub.Operation = "subscribe"
|
|
sub.Arguments = []string{channelToSubscribe.Channel}
|
|
return b.WebsocketConn.SendJSONMessage(sub)
|
|
}
|
|
|
|
// Unsubscribe sends a websocket message to stop receiving data from the channel
|
|
func (b *BTSE) Unsubscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
|
|
var unSub wsSub
|
|
unSub.Operation = "unsubscribe"
|
|
unSub.Arguments = []string{channelToSubscribe.Channel}
|
|
return b.WebsocketConn.SendJSONMessage(unSub)
|
|
}
|