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