From a761f3a0a9fab2b5d21a2f05dd556ed5ffabde1e Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 29 May 2024 00:53:21 +0900 Subject: [PATCH] wip --- node/pkg/fetcher/fetcher.go | 2 + node/pkg/wfetcher/app.go | 1 + node/pkg/wfetcher/binance/binance.go | 73 ++++++++++++++++++++++ node/pkg/wfetcher/binance/type.go | 25 ++++++++ node/pkg/wfetcher/binance/utils.go | 57 +++++++++++++++++ node/pkg/wfetcher/coinone/coinone.go | 90 +++++++++++++++++++++++++++ node/pkg/wfetcher/coinone/type.go | 47 ++++++++++++++ node/pkg/wfetcher/coinone/utils.go | 47 ++++++++++++++ node/pkg/wfetcher/korbit/korbit.go | 93 ++++++++++++++++++++++++++++ node/pkg/wfetcher/korbit/type.go | 57 +++++++++++++++++ node/pkg/wfetcher/korbit/utils.go | 52 ++++++++++++++++ node/pkg/wfetcher/type.go | 58 +++++++++++++++++ node/pkg/wfetcher/utils.go | 78 +++++++++++++++++++++++ node/pkg/wss/utils.go | 3 + node/script/test_websocket/main.go | 25 ++++++++ 15 files changed, 708 insertions(+) create mode 100644 node/pkg/wfetcher/app.go create mode 100644 node/pkg/wfetcher/binance/binance.go create mode 100644 node/pkg/wfetcher/binance/type.go create mode 100644 node/pkg/wfetcher/binance/utils.go create mode 100644 node/pkg/wfetcher/coinone/coinone.go create mode 100644 node/pkg/wfetcher/coinone/type.go create mode 100644 node/pkg/wfetcher/coinone/utils.go create mode 100644 node/pkg/wfetcher/korbit/korbit.go create mode 100644 node/pkg/wfetcher/korbit/type.go create mode 100644 node/pkg/wfetcher/korbit/utils.go create mode 100644 node/pkg/wfetcher/type.go create mode 100644 node/pkg/wfetcher/utils.go create mode 100644 node/script/test_websocket/main.go diff --git a/node/pkg/fetcher/fetcher.go b/node/pkg/fetcher/fetcher.go index 7315d1bdf..9850727e4 100644 --- a/node/pkg/fetcher/fetcher.go +++ b/node/pkg/fetcher/fetcher.go @@ -100,6 +100,8 @@ func (f *Fetcher) fetch(chainHelpers map[string]ChainHelper, proxies []Proxy) ([ errChan <- fetchErr return } + case *definition.Type == "websocket": + return default: errChan <- errorSentinel.ErrFetcherInvalidType } diff --git a/node/pkg/wfetcher/app.go b/node/pkg/wfetcher/app.go new file mode 100644 index 000000000..a64aed684 --- /dev/null +++ b/node/pkg/wfetcher/app.go @@ -0,0 +1 @@ +package wfetcher diff --git a/node/pkg/wfetcher/binance/binance.go b/node/pkg/wfetcher/binance/binance.go new file mode 100644 index 000000000..596465e2a --- /dev/null +++ b/node/pkg/wfetcher/binance/binance.go @@ -0,0 +1,73 @@ +package binance + +import ( + "context" + "fmt" + "strings" + "time" + + "bisonai.com/orakl/node/pkg/wfetcher" + "bisonai.com/orakl/node/pkg/wss" + "github.com/rs/zerolog/log" +) + +type BinanceFetcher wfetcher.Fetcher + +// expected to recieve feedmap with key having format "" +func New(ctx context.Context, opts ...wfetcher.FetcherOption) (*BinanceFetcher, error) { + config := &wfetcher.FetcherConfig{} + for _, opt := range opts { + opt(config) + } + + fetcher := &BinanceFetcher{} + if len(config.FeedMap) == 0 { + log.Error().Str("Player", "Binance").Msg("no feed map") + return nil, fmt.Errorf("no feed map") + } + fetcher.FeedMap = config.FeedMap + + streams := []Stream{} + for feed := range config.FeedMap { + streams = append(streams, Stream(strings.ToLower(feed)+"@miniTicker")) + } + subscription := Subscription{"SUBSCRIBE", streams, 1} + + ws, err := wss.NewWebsocketHelper(ctx, + wss.WithEndpoint(URL), + wss.WithSubscriptions([]any{subscription}), + wss.WithProxyUrl(config.Proxy)) + if err != nil { + log.Error().Str("Player", "Binance").Err(err).Msg("error in NewWebsocketHelper") + return nil, err + } + fetcher.Ws = ws + + return fetcher, nil +} + +func (b *BinanceFetcher) handleMessage(ctx context.Context, message map[string]any) error { + ticker, err := MessageToTicker(message) + if err != nil { + log.Error().Str("Player", "Binance").Err(err).Msg("error in MessageToTicker") + return err + } + + feedData, err := TickerToFeedData(ticker, b.FeedMap) + if err != nil { + log.Error().Str("Player", "Binance").Err(err).Msg("error in MiniTickerToFeedData") + return err + } + + err = wfetcher.StoreFeed(ctx, feedData, 2*time.Second) + if err != nil { + log.Error().Str("Player", "Binance").Err(err).Msg("error in StoreFeed") + return err + } + + return nil +} + +func (b *BinanceFetcher) Run(ctx context.Context) { + b.Ws.Run(ctx, b.handleMessage) +} diff --git a/node/pkg/wfetcher/binance/type.go b/node/pkg/wfetcher/binance/type.go new file mode 100644 index 000000000..5cbc08834 --- /dev/null +++ b/node/pkg/wfetcher/binance/type.go @@ -0,0 +1,25 @@ +package binance + +const ( + URL = "wss://stream.binance.com:443/ws" +) + +type Stream string + +type Subscription struct { + Method string `json:"method"` + Params []Stream `json:"params"` + Id uint32 `json:"id"` +} + +type MiniTicker struct { + EventType string `json:"e"` + EventTime int64 `json:"E"` + Symbol string `json:"s"` + Price string `json:"c"` + OpenPrice string `json:"o"` + HighPrice string `json:"h"` + LowPrice string `json:"l"` + Volume string `json:"v"` + QuoteVolume string `json:"q"` +} diff --git a/node/pkg/wfetcher/binance/utils.go b/node/pkg/wfetcher/binance/utils.go new file mode 100644 index 000000000..6979808f9 --- /dev/null +++ b/node/pkg/wfetcher/binance/utils.go @@ -0,0 +1,57 @@ +package binance + +import ( + "encoding/json" + "fmt" + "time" + + "bisonai.com/orakl/node/pkg/wfetcher" + "github.com/rs/zerolog/log" +) + +func GetSubscription(names []string) Subscription { + streams := []Stream{} + + for _, name := range names { + streams = append(streams, Stream(name+"@miniTicker")) + } + + return Subscription{ + Method: "SUBSCRIBE", + Params: streams, + Id: 1, + } +} +func MessageToTicker(msg map[string]any) (MiniTicker, error) { + var miniTicker MiniTicker + jsonData, err := json.Marshal(msg) + if err != nil { + log.Error().Str("Player", "Binance").Err(err).Msg("error in json.Marshal") + return miniTicker, err + } + + err = json.Unmarshal(jsonData, &miniTicker) + if err != nil { + log.Error().Str("Player", "Binance").Err(err).Msg("error in json.Unmarshal") + return miniTicker, err + } + return miniTicker, nil +} + +func TickerToFeedData(miniTicker MiniTicker, feedMap map[string]int32) (*wfetcher.FeedData, error) { + feedData := new(wfetcher.FeedData) + timestamp := time.Unix(miniTicker.EventTime/1000, 0) + value, err := wfetcher.PriceStringToFloat64(miniTicker.Price) + if err != nil { + return feedData, err + } + + id, exists := feedMap[miniTicker.Symbol] + if !exists { + return feedData, fmt.Errorf("feed not found") + } + feedData.FeedId = id + feedData.Value = value + feedData.Timestamp = timestamp + return feedData, nil +} diff --git a/node/pkg/wfetcher/coinone/coinone.go b/node/pkg/wfetcher/coinone/coinone.go new file mode 100644 index 000000000..90a033235 --- /dev/null +++ b/node/pkg/wfetcher/coinone/coinone.go @@ -0,0 +1,90 @@ +package coinone + +import ( + "context" + "fmt" + "strings" + "time" + + "bisonai.com/orakl/node/pkg/wfetcher" + "bisonai.com/orakl/node/pkg/wss" + "github.com/rs/zerolog/log" +) + +type CoinoneFetcher wfetcher.Fetcher + +// expected to recieve feedmap with key having format "-" +func New(ctx context.Context, opts ...wfetcher.FetcherOption) (*CoinoneFetcher, error) { + config := &wfetcher.FetcherConfig{} + for _, opt := range opts { + opt(config) + } + + fetcher := &CoinoneFetcher{} + + if len(config.FeedMap) == 0 { + log.Error().Str("Player", "Coinone").Msg("no feed map") + return nil, fmt.Errorf("no feed map") + } + fetcher.FeedMap = config.FeedMap + + subscriptions := []any{} + for feed := range config.FeedMap { + raw := strings.Split(feed, "-") + if len(raw) < 2 { + log.Error().Str("Player", "Coinone").Msg("invalid feed name") + return nil, fmt.Errorf("invalid feed name") + } + base := raw[0] + quote := raw[1] + + subscriptions = append(subscriptions, Subscription{ + RequestType: "SUBSCRIBE", + Channel: "TICKER", + Topic: Topic{ + QuoteCurrency: quote, + TargetCurrency: base, + }, + Format: "SHORT", + }) + } + ws, err := wss.NewWebsocketHelper(ctx, + wss.WithEndpoint(URL), + wss.WithSubscriptions(subscriptions), + wss.WithProxyUrl(config.Proxy)) + if err != nil { + log.Error().Str("Player", "Coinone").Err(err).Msg("error in NewWebsocketHelper") + return nil, err + } + fetcher.Ws = ws + + return fetcher, nil +} + +func (c *CoinoneFetcher) handleMessage(ctx context.Context, message map[string]any) error { + raw, err := MessageToRawResponse(message) + if err != nil { + log.Error().Str("Player", "Coinone").Err(err).Msg("error in MessageToRawResponse") + return err + } + + if raw.ResponseType != "DATA" { + return nil + } + feedData, err := DataToFeedData(raw.Data, c.FeedMap) + if err != nil { + log.Error().Str("Player", "Coinone").Err(err).Msg("error in DataToFeedData") + return err + } + + err = wfetcher.StoreFeed(ctx, &feedData, 2*time.Second) + if err != nil { + log.Error().Str("Player", "Coinone").Err(err).Msg("error in StoreFeed") + return err + } + return nil +} + +func (c *CoinoneFetcher) Run(ctx context.Context) { + c.Ws.Run(ctx, c.handleMessage) +} diff --git a/node/pkg/wfetcher/coinone/type.go b/node/pkg/wfetcher/coinone/type.go new file mode 100644 index 000000000..dec132f9f --- /dev/null +++ b/node/pkg/wfetcher/coinone/type.go @@ -0,0 +1,47 @@ +package coinone + +const ( + URL = "wss://stream.coinone.co.kr" +) + +type Topic struct { + QuoteCurrency string `json:"quote_currency"` + TargetCurrency string `json:"target_currency"` +} + +type Subscription struct { + RequestType string `json:"request_type"` + Channel string `json:"channel"` + Topic Topic `json:"topic"` + Format string `json:"format"` +} + +type Data struct { + QuoteCurrency string `json:"qc"` + TargetCurrency string `json:"tc"` + Timestamp int64 `json:"t"` + QuoteVolume string `json:"qv"` + TargetVolume string `json:"tv"` + First string `json:"fi"` + Low string `json:"lo"` + High string `json:"hi"` + Last string `json:"la"` + VolumePower string `json:"vp"` + AskBestPrice string `json:"abp"` + AskBestQty string `json:"abq"` + BidBestPrice string `json:"bbp"` + BidBestQty string `json:"bbq"` + ID string `json:"i"` + YesterdayFirst string `json:"yfi"` + YesterdayLow string `json:"ylo"` + YesterdayHigh string `json:"yhi"` + YesterdayLast string `json:"yla"` + YesterdayQuoteVolume string `json:"yqv"` + YesterdayTargetVolume string `json:"ytv"` +} + +type Raw struct { + ResponseType string `json:"r"` + Channel string `json:"c"` + Data Data `json:"d"` +} diff --git a/node/pkg/wfetcher/coinone/utils.go b/node/pkg/wfetcher/coinone/utils.go new file mode 100644 index 000000000..91bb4a69b --- /dev/null +++ b/node/pkg/wfetcher/coinone/utils.go @@ -0,0 +1,47 @@ +package coinone + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "bisonai.com/orakl/node/pkg/wfetcher" + "github.com/rs/zerolog/log" +) + +func MessageToRawResponse(msg map[string]any) (Raw, error) { + var rawResponse Raw + jsonData, err := json.Marshal(msg) + if err != nil { + log.Error().Str("Player", "Coinone").Err(err).Msg("error in json.Marshal") + return rawResponse, err + } + + err = json.Unmarshal(jsonData, &rawResponse) + if err != nil { + log.Error().Str("Player", "Coinone").Err(err).Msg("error in json.Unmarshal") + return rawResponse, err + } + return rawResponse, nil +} + +func DataToFeedData(data Data, feedMap map[string]int32) (wfetcher.FeedData, error) { + feedData := wfetcher.FeedData{} + + timestamp := time.Unix(data.Timestamp/1000, 0) + value, err := wfetcher.PriceStringToFloat64(data.Last) + + if err != nil { + return feedData, err + } + + id, exists := feedMap[strings.ToUpper(data.TargetCurrency)+"-"+strings.ToUpper(data.QuoteCurrency)] + if !exists { + return feedData, fmt.Errorf("feed not found") + } + feedData.FeedId = id + feedData.Value = value + feedData.Timestamp = timestamp + return feedData, nil +} diff --git a/node/pkg/wfetcher/korbit/korbit.go b/node/pkg/wfetcher/korbit/korbit.go new file mode 100644 index 000000000..2eaae52a3 --- /dev/null +++ b/node/pkg/wfetcher/korbit/korbit.go @@ -0,0 +1,93 @@ +package korbit + +import ( + "context" + "fmt" + "strings" + "time" + + "bisonai.com/orakl/node/pkg/wfetcher" + "bisonai.com/orakl/node/pkg/wss" + "github.com/rs/zerolog/log" +) + +type KorbitFetcher wfetcher.Fetcher + +// expected to recieve feedmap with key having format "-" +func New(ctx context.Context, opts ...wfetcher.FetcherOption) (*KorbitFetcher, error) { + config := &wfetcher.FetcherConfig{} + for _, opt := range opts { + opt(config) + } + + fetcher := &KorbitFetcher{} + + if len(config.FeedMap) == 0 { + log.Error().Str("Player", "Korbit").Msg("no feed map") + return nil, fmt.Errorf("no feed map") + } + fetcher.FeedMap = config.FeedMap + + pairListString := []string{} + for feed := range config.FeedMap { + raw := strings.Split(feed, "-") + if len(raw) < 2 { + log.Error().Str("Player", "Coinone").Msg("invalid feed name") + return nil, fmt.Errorf("invalid feed name") + } + base := raw[0] + quote := raw[1] + pairListString = append(pairListString, fmt.Sprintf("%s_%s", strings.ToLower(base), strings.ToLower(quote))) + } + + subscription := Subscription{ + AccessToken: nil, + Timestamp: time.Now().Unix(), + Event: "korbit:subscribe", + Data: Data{Channels: []string{ + "ticker:" + strings.Join(pairListString, ","), + }}, + } + + ws, err := wss.NewWebsocketHelper(ctx, + wss.WithEndpoint(URL), + wss.WithSubscriptions([]any{subscription}), + wss.WithProxyUrl(config.Proxy)) + if err != nil { + log.Error().Str("Player", "Korbit").Err(err).Msg("error in NewWebsocketHelper") + return nil, err + } + fetcher.Ws = ws + return fetcher, nil + +} + +func (k *KorbitFetcher) handleMessage(ctx context.Context, message map[string]any) error { + raw, err := MessageToRawResponse(message) + if err != nil { + log.Error().Str("Player", "Korbit").Err(err).Msg("error in MessageToRawResponse") + return err + } + + if raw.Event != "korbit:push-ticker" { + return nil + } + + feedData, err := DataToFeedData(raw.Data, k.FeedMap) + if err != nil { + log.Error().Str("Player", "Korbit").Err(err).Msg("error in DataToFeedData") + return err + } + + err = wfetcher.StoreFeed(ctx, &feedData, 2*time.Second) + if err != nil { + log.Error().Str("Player", "Korbit").Err(err).Msg("error in StoreFeed") + return err + } + + return nil +} + +func (k *KorbitFetcher) Run(ctx context.Context) { + k.Ws.Run(ctx, k.handleMessage) +} diff --git a/node/pkg/wfetcher/korbit/type.go b/node/pkg/wfetcher/korbit/type.go new file mode 100644 index 000000000..70c3b6171 --- /dev/null +++ b/node/pkg/wfetcher/korbit/type.go @@ -0,0 +1,57 @@ +package korbit + +const ( + URL = "wss://ws2.korbit.co.kr/v1/user/push" +) + +/* +{ + "accessToken": null, + "event": "korbit:push-ticker", + "timestamp" : 1389678052000, + "data": + { + "channel": "ticker", + "currency_pair": "btc_krw", + "timestamp": 1558590089274, + "last": "9198500.1235789" + "open": "9500000.3445783", + "bid": "9192500.4578344", + "ask": "9198000.32148556", + "low": "9171500.23785685", + "high": "9599000.34876458", + "volume": "1539.18571988", + "change": "-301500.234578934" + } +} +*/ + +type Raw struct { + Event string `json:"event"` + Data Ticker `json:"data"` +} + +type Ticker struct { + Channel string `json:"channel"` + CurrencyPair string `json:"currency_pair"` + Timestamp int64 `json:"timestamp"` + Last string `json:"last"` + Open string `json:"open"` + Bid string `json:"bid"` + Ask string `json:"ask"` + Low string `json:"low"` + High string `json:"high"` + Volume string `json:"volume"` + Change string `json:"change"` +} + +type Data struct { + Channels []string `json:"channels"` +} + +type Subscription struct { + AccessToken *string `json:"accessToken"` + Timestamp int64 `json:"timestamp"` + Event string `json:"event"` + Data Data `json:"data"` +} diff --git a/node/pkg/wfetcher/korbit/utils.go b/node/pkg/wfetcher/korbit/utils.go new file mode 100644 index 000000000..7a2638d0d --- /dev/null +++ b/node/pkg/wfetcher/korbit/utils.go @@ -0,0 +1,52 @@ +package korbit + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "bisonai.com/orakl/node/pkg/wfetcher" + "github.com/rs/zerolog/log" +) + +func MessageToRawResponse(msg map[string]any) (Raw, error) { + var rawResponse Raw + jsonData, err := json.Marshal(msg) + if err != nil { + log.Error().Str("Player", "Korbit").Err(err).Msg("error in json.Marshal") + return rawResponse, err + } + + err = json.Unmarshal(jsonData, &rawResponse) + if err != nil { + log.Error().Str("Player", "Korbit").Err(err).Msg("error in json.Unmarshal") + return rawResponse, err + } + return rawResponse, nil +} + +func DataToFeedData(data Ticker, feedMap map[string]int32) (wfetcher.FeedData, error) { + feedData := wfetcher.FeedData{} + + timestamp := time.Unix(data.Timestamp/1000, 0) + value, err := wfetcher.PriceStringToFloat64(data.Last) + if err != nil { + return feedData, err + } + rawPair := strings.Split(data.CurrencyPair, "_") + if len(rawPair) < 2 { + return feedData, fmt.Errorf("invalid feed name") + } + target := rawPair[0] + quote := rawPair[1] + + id, exists := feedMap[strings.ToUpper(target)+"-"+strings.ToUpper(quote)] + if !exists { + return feedData, fmt.Errorf("feed not found") + } + feedData.FeedId = id + feedData.Value = value + feedData.Timestamp = timestamp + return feedData, nil +} diff --git a/node/pkg/wfetcher/type.go b/node/pkg/wfetcher/type.go new file mode 100644 index 000000000..8b525d547 --- /dev/null +++ b/node/pkg/wfetcher/type.go @@ -0,0 +1,58 @@ +package wfetcher + +import ( + "encoding/json" + "fmt" + "time" + + "bisonai.com/orakl/node/pkg/wss" +) + +const DECIMALS = 8 + +type Feed struct { + ID int32 `db:"id"` + Name string `db:"name"` + Definition json.RawMessage `db:"definition"` + ConfigID int32 `db:"config_id"` +} + +type Definition struct { + Type *string `json:"type"` + Provider *string `json:"provider"` +} + +type FeedData struct { + FeedId int32 `db:"feed_id"` + Value float64 `db:"value"` + Timestamp time.Time `db:"timestamp"` +} + +func (f *FeedData) String() string { + return fmt.Sprintf("FeedId: %d, Value: %f, Timestamp: %s", f.FeedId, f.Value, f.Timestamp) +} + +type FetcherConfig struct { + FeedMap map[string]int32 + Proxy string +} + +type FetcherOption func(*FetcherConfig) + +func WithFeedMap(feedMap map[string]int32) FetcherOption { + return func(c *FetcherConfig) { + c.FeedMap = feedMap + } +} + +func WithProxy(proxy string) FetcherOption { + return func(c *FetcherConfig) { + c.Proxy = proxy + } +} + +type Fetcher struct { + Name string + FeedMap map[string]int32 + Ws *wss.WebsocketHelper +} diff --git a/node/pkg/wfetcher/utils.go b/node/pkg/wfetcher/utils.go new file mode 100644 index 000000000..924c051f1 --- /dev/null +++ b/node/pkg/wfetcher/utils.go @@ -0,0 +1,78 @@ +package wfetcher + +import ( + "context" + "encoding/json" + "math" + "strconv" + "strings" + "time" + + "bisonai.com/orakl/node/pkg/db" + "github.com/rs/zerolog/log" +) + +// Returns two mappings of currency pair to feed id. +// combined : map['btcusdt'] = 1 +// separated : map['btc-usdt'] = 1 +func MakeFeedMap(feeds []Feed, provider string) (map[string]int32, map[string]int32) { + feedMapCombined := make(map[string]int32) + feedMapSeparated := make(map[string]int32) + + for _, feed := range feeds { + definition := new(Definition) + err := json.Unmarshal(feed.Definition, &definition) + if err != nil { + continue + } + if definition.Type != nil && + definition.Provider != nil && + *definition.Type == "websocket" && + *definition.Provider == provider { + // expected feed name to have format "-wss--" + + raw := strings.Split(feed.Name, "-") + if len(raw) < 3 { + log.Warn().Str("Player", provider).Str("name", feed.Name).Msg("invalid name") + continue + } + base := strings.ToUpper(raw[len(raw)-2]) + quote := strings.ToUpper(raw[len(raw)-1]) + combined := base + quote + + feedMapCombined[combined] = feed.ID + feedMapSeparated[base+"-"+quote] = feed.ID + } + } + + return feedMapCombined, feedMapSeparated +} + +func StoreFeed(ctx context.Context, feedData *FeedData, expiration time.Duration) error { + err := db.SetObject(ctx, "latestFeedData:"+strconv.Itoa(int(feedData.FeedId)), feedData, expiration) + if err != nil { + return err + } + return db.LPushObject(ctx, "feedDataBuffer", []FeedData{*feedData}) +} + +func StoreFeeds(ctx context.Context, feedData []FeedData, expiration time.Duration) error { + latestData := make(map[string]any) + for _, data := range feedData { + latestData["latestFeedData:"+strconv.Itoa(int(data.FeedId))] = data + } + err := db.MSetObjectWithExp(ctx, latestData, expiration) + if err != nil { + return err + } + return db.LPushObject(ctx, "feedDataBuffer", feedData) +} + +func PriceStringToFloat64(price string) (float64, error) { + f, err := strconv.ParseFloat(price, 64) + if err != nil { + return 0, err + } + + return f * float64(math.Pow10(int(DECIMALS))), nil +} diff --git a/node/pkg/wss/utils.go b/node/pkg/wss/utils.go index d0b72770a..46ad04253 100644 --- a/node/pkg/wss/utils.go +++ b/node/pkg/wss/utils.go @@ -38,6 +38,9 @@ func WithEndpoint(endpoint string) ConnectionOption { func WithProxyUrl(proxyUrl string) ConnectionOption { return func(c *ConnectionConfig) { + if proxyUrl == "" { + return + } c.Proxy = proxyUrl } } diff --git a/node/script/test_websocket/main.go b/node/script/test_websocket/main.go new file mode 100644 index 000000000..11ed49c46 --- /dev/null +++ b/node/script/test_websocket/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "context" + "sync" + + "bisonai.com/orakl/node/pkg/wfetcher" + "bisonai.com/orakl/node/pkg/wfetcher/korbit" +) + +func main() { + ctx := context.Background() + var wg sync.WaitGroup + feedMap := make(map[string]int32) + feedMap["BTC-KRW"] = 1 + feedMap["ETH-KRW"] = 2 + + wg.Add(1) + c, err := korbit.New(ctx, wfetcher.WithFeedMap(feedMap)) + if err != nil { + panic(err) + } + c.Run(ctx) + wg.Wait() +}