138 lines
2.7 KiB
Go
138 lines
2.7 KiB
Go
package clients
|
|
|
|
import (
|
|
"btclock/broker"
|
|
"btclock/models"
|
|
"btclock/modules"
|
|
"context"
|
|
"log"
|
|
|
|
"github.com/coder/websocket"
|
|
"github.com/coder/websocket/wsjson"
|
|
)
|
|
|
|
type KrakenClient struct {
|
|
ws *websocket.Conn
|
|
eventTypes []string
|
|
broker *broker.EventBroker
|
|
}
|
|
|
|
type KrakenTickerEvent struct {
|
|
Symbol string
|
|
Last float64
|
|
}
|
|
|
|
// Name implements broker.Event.
|
|
func (k KrakenTickerEvent) Name() string {
|
|
return "ticker"
|
|
}
|
|
|
|
// Payload implements broker.Event.
|
|
func (k KrakenTickerEvent) Payload() interface{} {
|
|
return map[string]interface{}{
|
|
"symbol": k.Symbol,
|
|
"last": k.Last,
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
modules.Registry.Register(NewKrakenClient())
|
|
}
|
|
|
|
func NewKrakenClient() *KrakenClient {
|
|
return &KrakenClient{
|
|
eventTypes: []string{"ticker"},
|
|
}
|
|
}
|
|
|
|
func (k *KrakenClient) Init(broker *broker.EventBroker) error {
|
|
k.broker = broker
|
|
|
|
return nil
|
|
}
|
|
|
|
func (k *KrakenClient) Start(ctx context.Context) error {
|
|
ws, _, err := websocket.Dial(ctx, "wss://ws.kraken.com/v2", nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer ws.CloseNow()
|
|
|
|
err = wsjson.Write(ctx, ws, map[string]interface{}{
|
|
"method": "subscribe",
|
|
"params": map[string]interface{}{
|
|
"channel": "ticker",
|
|
"symbol": []string{"BTC/USD", "BTC/EUR", "BTC/GBP", "BTC/JPY", "BTC/CHF", "BTC/CAD", "BTC/AUD"},
|
|
},
|
|
})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Expect subscription confirmation
|
|
var v map[string]interface{}
|
|
err = wsjson.Read(ctx, ws, &v)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
// Read messages until the connection is closed
|
|
for {
|
|
var v map[string]any
|
|
err = wsjson.Read(ctx, ws, &v)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
channel, ok := v["channel"].(string)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if channel == "ticker" {
|
|
tickerData := handleTickerMessage(v)
|
|
tickerEvent := KrakenTickerEvent{
|
|
Symbol: tickerData.Symbol,
|
|
Last: tickerData.Last,
|
|
}
|
|
k.broker.Publish("ticker", tickerEvent)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (k *KrakenClient) Stop() error {
|
|
k.ws.Close(websocket.StatusNormalClosure, "")
|
|
|
|
return nil
|
|
}
|
|
|
|
func (k *KrakenClient) ID() string {
|
|
return "kraken"
|
|
}
|
|
|
|
func handleTickerMessage(v map[string]any) models.Ticker {
|
|
data, ok := v["data"].([]interface{})
|
|
if !ok {
|
|
return models.Ticker{}
|
|
}
|
|
|
|
for _, item := range data {
|
|
if ticker, ok := item.(map[string]interface{}); ok {
|
|
symbol, symbolOk := ticker["symbol"].(string)
|
|
last, lastOk := ticker["last"].(float64)
|
|
bid, bidOk := ticker["bid"].(float64)
|
|
ask, askOk := ticker["ask"].(float64)
|
|
|
|
if symbolOk && lastOk && bidOk && askOk {
|
|
ticker := models.Ticker{
|
|
Symbol: symbol,
|
|
Last: last,
|
|
Bid: bid,
|
|
Ask: ask,
|
|
}
|
|
// fmt.Printf("%+v\n", ticker)
|
|
return ticker
|
|
}
|
|
}
|
|
}
|
|
|
|
return models.Ticker{}
|
|
}
|