ws-go-server/clients/kraken.go
2025-05-18 23:54:04 +02:00

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{}
}