exchanges/websocket: Implement subscription configuration (#1394)

* Websockets: Move Subscription to its own package

This allows the small type to be imported from both `config` and from
`stream` without an import cycle, so we don't have to repeat ourselves

* Subs: Renamed Currency to Pair

This was being mis-used through much of the code, and since we're
already touching everything, we might as well fix it

* Websockets: Add Subscription configuration

* Binance: Add subscription configuration

* Kucoin: Subscription configuration

* Simplify GenerateDefaultSubs
* Improve TestGenSubs coverage
* Test Candle Sub generation
* Support Candle intervals
* Full responsibility for formatting Channel name on GenerateDefaultSubs
  OR consumer of Subscribe
* Simplify generatePayloads as a result
* Fix test coverage of asset types in processMarketSnapshot

* Exchanges: Abstract ParallelChanOp

* Tests: Generic ws mock instances

* Kucoin: Fix intermittent conflict in test currs

Use isolated test instance for `TestGetOpenInterest`.

`TestGetOpenInterest` would occassionally change pairs before
GenerateDefault Subs.
This commit is contained in:
Gareth Kirwan
2024-01-24 05:54:07 +01:00
committed by GitHub
parent 301551ac20
commit e007f69f7c
67 changed files with 3705 additions and 3167 deletions

View File

@@ -31,33 +31,6 @@ type Response struct {
Raw []byte
}
// DefaultChannelKey is the fallback key for AddSuccessfulSubscriptions
type DefaultChannelKey struct {
Channel string
Currency currency.Pair
Asset asset.Item
}
// ChannelState tracks the status of a subscription channel
type ChannelState uint8
const (
ChannelStateUnknown ChannelState = iota // ChannelStateUnknown means subscription state is not registered, but doesn't imply Inactive
ChannelSubscribing // ChannelSubscribing means channel is in the process of subscribing
ChannelSubscribed // ChannelSubscribed means the channel has finished a successful and acknowledged subscription
ChannelUnsubscribing // ChannelUnsubscribing means the channel has started to unsubscribe, but not yet confirmed
)
// ChannelSubscription container for streaming subscription channels
type ChannelSubscription struct {
Key any
Channel string
Currency currency.Pair
Asset asset.Item
Params map[string]interface{}
State ChannelState
}
// ConnectionSetup defines variables for an individual stream connection
type ConnectionSetup struct {
ResponseCheckTimeout time.Duration

View File

@@ -11,6 +11,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
"github.com/thrasher-corp/gocryptotrader/log"
)
@@ -30,6 +31,8 @@ var (
ErrSubscribedAlready = errors.New("duplicate subscription")
// ErrSubscriptionFailure defines an error when a subscription fails
ErrSubscriptionFailure = errors.New("subscription failure")
// ErrSubscriptionNotSupported defines an error when a subscription channel is not supported by an exchange
ErrSubscriptionNotSupported = errors.New("subscription channel not supported ")
// ErrUnsubscribeFailure defines an error when a unsubscribe fails
ErrUnsubscribeFailure = errors.New("unsubscribe failure")
// ErrChannelInStateAlready defines an error when a subscription channel is already in a new state
@@ -79,8 +82,8 @@ func New() *Websocket {
ToRoutine: make(chan interface{}, defaultJobBuffer),
TrafficAlert: make(chan struct{}),
ReadMessageErrors: make(chan error),
Subscribe: make(chan []ChannelSubscription),
Unsubscribe: make(chan []ChannelSubscription),
Subscribe: make(chan []subscription.Subscription),
Unsubscribe: make(chan []subscription.Subscription),
Match: NewMatch(),
}
}
@@ -869,9 +872,9 @@ func (w *Websocket) GetName() string {
// GetChannelDifference finds the difference between the subscribed channels
// and the new subscription list when pairs are disabled or enabled.
func (w *Websocket) GetChannelDifference(genSubs []ChannelSubscription) (sub, unsub []ChannelSubscription) {
func (w *Websocket) GetChannelDifference(genSubs []subscription.Subscription) (sub, unsub []subscription.Subscription) {
w.subscriptionMutex.RLock()
unsubMap := make(map[any]ChannelSubscription, len(w.subscriptions))
unsubMap := make(map[any]subscription.Subscription, len(w.subscriptions))
for k, c := range w.subscriptions {
unsubMap[k] = *c
}
@@ -894,7 +897,7 @@ func (w *Websocket) GetChannelDifference(genSubs []ChannelSubscription) (sub, un
}
// UnsubscribeChannels unsubscribes from a websocket channel
func (w *Websocket) UnsubscribeChannels(channels []ChannelSubscription) error {
func (w *Websocket) UnsubscribeChannels(channels []subscription.Subscription) error {
if len(channels) == 0 {
return fmt.Errorf("%s websocket: %w", w.exchangeName, errNoSubscriptionsSupplied)
}
@@ -912,16 +915,16 @@ func (w *Websocket) UnsubscribeChannels(channels []ChannelSubscription) error {
}
// ResubscribeToChannel resubscribes to channel
func (w *Websocket) ResubscribeToChannel(subscribedChannel *ChannelSubscription) error {
err := w.UnsubscribeChannels([]ChannelSubscription{*subscribedChannel})
func (w *Websocket) ResubscribeToChannel(subscribedChannel *subscription.Subscription) error {
err := w.UnsubscribeChannels([]subscription.Subscription{*subscribedChannel})
if err != nil {
return err
}
return w.SubscribeToChannels([]ChannelSubscription{*subscribedChannel})
return w.SubscribeToChannels([]subscription.Subscription{*subscribedChannel})
}
// SubscribeToChannels appends supplied channels to channelsToSubscribe
func (w *Websocket) SubscribeToChannels(channels []ChannelSubscription) error {
func (w *Websocket) SubscribeToChannels(channels []subscription.Subscription) error {
if err := w.checkSubscriptions(channels); err != nil {
return fmt.Errorf("%s websocket: %w", w.exchangeName, common.AppendError(ErrSubscriptionFailure, err))
}
@@ -933,7 +936,7 @@ func (w *Websocket) SubscribeToChannels(channels []ChannelSubscription) error {
// AddSubscription adds a subscription to the subscription lists
// Unlike AddSubscriptions this method will error if the subscription already exists
func (w *Websocket) AddSubscription(c *ChannelSubscription) error {
func (w *Websocket) AddSubscription(c *subscription.Subscription) error {
w.subscriptionMutex.Lock()
defer w.subscriptionMutex.Unlock()
if w.subscriptions == nil {
@@ -952,7 +955,7 @@ func (w *Websocket) AddSubscription(c *ChannelSubscription) error {
// SetSubscriptionState sets an existing subscription state
// returns an error if the subscription is not found, or the new state is already set
func (w *Websocket) SetSubscriptionState(c *ChannelSubscription, state ChannelState) error {
func (w *Websocket) SetSubscriptionState(c *subscription.Subscription, state subscription.State) error {
w.subscriptionMutex.Lock()
defer w.subscriptionMutex.Unlock()
if w.subscriptions == nil {
@@ -966,7 +969,7 @@ func (w *Websocket) SetSubscriptionState(c *ChannelSubscription, state ChannelSt
if state == p.State {
return ErrChannelInStateAlready
}
if state > ChannelUnsubscribing {
if state > subscription.UnsubscribingState {
return errInvalidChannelState
}
p.State = state
@@ -975,7 +978,7 @@ func (w *Websocket) SetSubscriptionState(c *ChannelSubscription, state ChannelSt
// AddSuccessfulSubscriptions adds subscriptions to the subscription lists that
// has been successfully subscribed
func (w *Websocket) AddSuccessfulSubscriptions(channels ...ChannelSubscription) {
func (w *Websocket) AddSuccessfulSubscriptions(channels ...subscription.Subscription) {
w.subscriptionMutex.Lock()
defer w.subscriptionMutex.Unlock()
if w.subscriptions == nil {
@@ -984,13 +987,13 @@ func (w *Websocket) AddSuccessfulSubscriptions(channels ...ChannelSubscription)
for _, cN := range channels {
c := cN // cN is an iteration var; Not safe to make a pointer to
key := c.EnsureKeyed()
c.State = ChannelSubscribed
c.State = subscription.SubscribedState
w.subscriptions[key] = &c
}
}
// RemoveSubscriptions removes subscriptions from the subscription list
func (w *Websocket) RemoveSubscriptions(channels ...ChannelSubscription) {
func (w *Websocket) RemoveSubscriptions(channels ...subscription.Subscription) {
w.subscriptionMutex.Lock()
defer w.subscriptionMutex.Unlock()
if w.subscriptions == nil {
@@ -1002,22 +1005,9 @@ func (w *Websocket) RemoveSubscriptions(channels ...ChannelSubscription) {
}
}
// EnsureKeyed sets the default key on a channel if it doesn't have one
// Returns key for convenience
func (c *ChannelSubscription) EnsureKeyed() any {
if c.Key == nil {
c.Key = DefaultChannelKey{
Channel: c.Channel,
Asset: c.Asset,
Currency: c.Currency,
}
}
return c.Key
}
// GetSubscription returns a pointer to a copy of the subscription at the key provided
// returns nil if no subscription is at that key or the key is nil
func (w *Websocket) GetSubscription(key any) *ChannelSubscription {
func (w *Websocket) GetSubscription(key any) *subscription.Subscription {
if key == nil || w == nil || w.subscriptions == nil {
return nil
}
@@ -1031,10 +1021,10 @@ func (w *Websocket) GetSubscription(key any) *ChannelSubscription {
}
// GetSubscriptions returns a new slice of the subscriptions
func (w *Websocket) GetSubscriptions() []ChannelSubscription {
func (w *Websocket) GetSubscriptions() []subscription.Subscription {
w.subscriptionMutex.RLock()
defer w.subscriptionMutex.RUnlock()
subs := make([]ChannelSubscription, 0, len(w.subscriptions))
subs := make([]subscription.Subscription, 0, len(w.subscriptions))
for _, c := range w.subscriptions {
subs = append(subs, *c)
}
@@ -1082,7 +1072,7 @@ func checkWebsocketURL(s string) error {
// checkSubscriptions checks subscriptions against the max subscription limit
// and if the subscription already exists.
func (w *Websocket) checkSubscriptions(subs []ChannelSubscription) error {
func (w *Websocket) checkSubscriptions(subs []subscription.Subscription) error {
if len(subs) == 0 {
return errNoSubscriptionsSupplied
}

View File

@@ -20,8 +20,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
)
const (
@@ -73,10 +73,10 @@ var defaultSetup = &WebsocketSetup{
DefaultURL: "testDefaultURL",
RunningURL: "wss://testRunningURL",
Connector: func() error { return nil },
Subscriber: func(_ []ChannelSubscription) error { return nil },
Unsubscriber: func(_ []ChannelSubscription) error { return nil },
GenerateSubscriptions: func() ([]ChannelSubscription, error) {
return []ChannelSubscription{
Subscriber: func(_ []subscription.Subscription) error { return nil },
Unsubscriber: func(_ []subscription.Subscription) error { return nil },
GenerateSubscriptions: func() ([]subscription.Subscription, error) {
return []subscription.Subscription{
{Channel: "TestSub"},
{Channel: "TestSub2", Key: "purple"},
{Channel: "TestSub3", Key: testSubKey{"mauve"}},
@@ -156,20 +156,20 @@ func TestSetup(t *testing.T) {
t.Fatalf("received: '%v' but expected: '%v'", err, errWebsocketSubscriberUnset)
}
websocketSetup.Subscriber = func([]ChannelSubscription) error { return nil }
websocketSetup.Subscriber = func([]subscription.Subscription) error { return nil }
websocketSetup.Features.Unsubscribe = true
err = w.Setup(websocketSetup)
if !errors.Is(err, errWebsocketUnsubscriberUnset) {
t.Fatalf("received: '%v' but expected: '%v'", err, errWebsocketUnsubscriberUnset)
}
websocketSetup.Unsubscriber = func([]ChannelSubscription) error { return nil }
websocketSetup.Unsubscriber = func([]subscription.Subscription) error { return nil }
err = w.Setup(websocketSetup)
if !errors.Is(err, errWebsocketSubscriptionsGeneratorUnset) {
t.Fatalf("received: '%v' but expected: '%v'", err, errWebsocketSubscriptionsGeneratorUnset)
}
websocketSetup.GenerateSubscriptions = func() ([]ChannelSubscription, error) { return nil, nil }
websocketSetup.GenerateSubscriptions = func() ([]subscription.Subscription, error) { return nil, nil }
err = w.Setup(websocketSetup)
if !errors.Is(err, errDefaultURLIsEmpty) {
t.Fatalf("received: '%v' but expected: '%v'", err, errDefaultURLIsEmpty)
@@ -504,11 +504,11 @@ func TestSubscribeUnsubscribe(t *testing.T) {
ws := *New()
assert.NoError(t, ws.Setup(defaultSetup), "WS Setup should not error")
fnSub := func(subs []ChannelSubscription) error {
fnSub := func(subs []subscription.Subscription) error {
ws.AddSuccessfulSubscriptions(subs...)
return nil
}
fnUnsub := func(unsubs []ChannelSubscription) error {
fnUnsub := func(unsubs []subscription.Subscription) error {
ws.RemoveSubscriptions(unsubs...)
return nil
}
@@ -522,7 +522,7 @@ func TestSubscribeUnsubscribe(t *testing.T) {
assert.Nil(t, ws.GetSubscription(42), "GetSubscription on empty internal map should return")
assert.NoError(t, ws.SubscribeToChannels(subs), "Basic Subscribing should not error")
assert.Len(t, ws.GetSubscriptions(), 4, "Should have 4 subscriptions")
byDefKey := ws.GetSubscription(DefaultChannelKey{Channel: "TestSub"})
byDefKey := ws.GetSubscription(subscription.DefaultKey{Channel: "TestSub"})
if assert.NotNil(t, byDefKey, "GetSubscription by default key should find a channel") {
assert.Equal(t, "TestSub", byDefKey.Channel, "GetSubscription by default key should return a pointer a copy of the right channel")
assert.NotSame(t, byDefKey, ws.subscriptions["TestSub"], "GetSubscription returns a fresh pointer")
@@ -556,18 +556,18 @@ func TestResubscribe(t *testing.T) {
err = ws.Setup(defaultSetup)
assert.NoError(t, err, "WS Setup should not error")
fnSub := func(subs []ChannelSubscription) error {
fnSub := func(subs []subscription.Subscription) error {
ws.AddSuccessfulSubscriptions(subs...)
return nil
}
fnUnsub := func(unsubs []ChannelSubscription) error {
fnUnsub := func(unsubs []subscription.Subscription) error {
ws.RemoveSubscriptions(unsubs...)
return nil
}
ws.Subscriber = fnSub
ws.Unsubscriber = fnUnsub
channel := []ChannelSubscription{{Channel: "resubTest"}}
channel := []subscription.Subscription{{Channel: "resubTest"}}
assert.ErrorIs(t, ws.ResubscribeToChannel(&channel[0]), ErrSubscriptionNotFound, "Resubscribe should error when channel isn't subscribed yet")
assert.NoError(t, ws.SubscribeToChannels(channel), "Subscribe should not error")
@@ -579,25 +579,25 @@ func TestSubscriptionState(t *testing.T) {
t.Parallel()
ws := New()
c := &ChannelSubscription{Key: 42, Channel: "Gophers", State: ChannelSubscribing}
assert.ErrorIs(t, ws.SetSubscriptionState(c, ChannelUnsubscribing), ErrSubscriptionNotFound, "Setting an imaginary sub should error")
c := &subscription.Subscription{Key: 42, Channel: "Gophers", State: subscription.SubscribingState}
assert.ErrorIs(t, ws.SetSubscriptionState(c, subscription.UnsubscribingState), ErrSubscriptionNotFound, "Setting an imaginary sub should error")
assert.NoError(t, ws.AddSubscription(c), "Adding first subscription should not error")
found := ws.GetSubscription(42)
assert.NotNil(t, found, "Should find the subscription")
assert.Equal(t, ChannelSubscribing, found.State, "Subscription should be Subscribing")
assert.Equal(t, subscription.SubscribingState, found.State, "Subscription should be Subscribing")
assert.ErrorIs(t, ws.AddSubscription(c), ErrSubscribedAlready, "Adding an already existing sub should error")
assert.ErrorIs(t, ws.SetSubscriptionState(c, ChannelSubscribing), ErrChannelInStateAlready, "Setting Same state should error")
assert.ErrorIs(t, ws.SetSubscriptionState(c, ChannelUnsubscribing+1), errInvalidChannelState, "Setting an invalid state should error")
assert.ErrorIs(t, ws.SetSubscriptionState(c, subscription.SubscribingState), ErrChannelInStateAlready, "Setting Same state should error")
assert.ErrorIs(t, ws.SetSubscriptionState(c, subscription.UnsubscribingState+1), errInvalidChannelState, "Setting an invalid state should error")
ws.AddSuccessfulSubscriptions(*c)
found = ws.GetSubscription(42)
assert.NotNil(t, found, "Should find the subscription")
assert.Equal(t, found.State, ChannelSubscribed, "Subscription should be subscribed state")
assert.Equal(t, found.State, subscription.SubscribedState, "Subscription should be subscribed state")
assert.NoError(t, ws.SetSubscriptionState(c, ChannelUnsubscribing), "Setting Unsub state should not error")
assert.NoError(t, ws.SetSubscriptionState(c, subscription.UnsubscribingState), "Setting Unsub state should not error")
found = ws.GetSubscription(42)
assert.Equal(t, found.State, ChannelUnsubscribing, "Subscription should be unsubscribing state")
assert.Equal(t, found.State, subscription.UnsubscribingState, "Subscription should be unsubscribing state")
}
// TestRemoveSubscriptions tests removing a subscription
@@ -605,7 +605,7 @@ func TestRemoveSubscriptions(t *testing.T) {
t.Parallel()
ws := New()
c := &ChannelSubscription{Key: 42, Channel: "Unite!"}
c := &subscription.Subscription{Key: 42, Channel: "Unite!"}
assert.NoError(t, ws.AddSubscription(c), "Adding first subscription should not error")
assert.NotNil(t, ws.GetSubscription(42), "Added subscription should be findable")
@@ -668,35 +668,6 @@ func TestGetSubscriptions(t *testing.T) {
assert.Equal(t, "hello3", w.GetSubscriptions()[0].Channel, "GetSubscriptions should return the correct channel details")
}
// TestEnsureKeyed logic test
func TestEnsureKeyed(t *testing.T) {
t.Parallel()
c := ChannelSubscription{
Channel: "candles",
Asset: asset.Spot,
Currency: currency.NewPair(currency.BTC, currency.USDT),
}
k1, ok := c.EnsureKeyed().(DefaultChannelKey)
if assert.True(t, ok, "EnsureKeyed should return a DefaultChannelKey") {
assert.Exactly(t, k1, c.Key, "EnsureKeyed should set the same key")
assert.Equal(t, k1.Channel, c.Channel, "DefaultChannelKey channel should be correct")
assert.Equal(t, k1.Asset, c.Asset, "DefaultChannelKey asset should be correct")
assert.Equal(t, k1.Currency, c.Currency, "DefaultChannelKey currency should be correct")
}
type platypus string
c = ChannelSubscription{
Key: platypus("Gerald"),
Channel: "orderbook",
Asset: asset.Margin,
Currency: currency.NewPair(currency.ETH, currency.USDC),
}
k2, ok := c.EnsureKeyed().(platypus)
if assert.True(t, ok, "EnsureKeyed should return a platypus") {
assert.Exactly(t, k2, c.Key, "EnsureKeyed should set the same key")
assert.EqualValues(t, "Gerald", k2, "key should have the correct value")
}
}
// TestSetCanUseAuthenticatedEndpoints logic test
func TestSetCanUseAuthenticatedEndpoints(t *testing.T) {
t.Parallel()
@@ -1076,7 +1047,7 @@ func TestGetChannelDifference(t *testing.T) {
t.Parallel()
web := Websocket{}
newChans := []ChannelSubscription{
newChans := []subscription.Subscription{
{
Channel: "Test1",
},
@@ -1093,7 +1064,7 @@ func TestGetChannelDifference(t *testing.T) {
web.AddSuccessfulSubscriptions(subs...)
flushedSubs := []ChannelSubscription{
flushedSubs := []subscription.Subscription{
{
Channel: "Test2",
},
@@ -1103,7 +1074,7 @@ func TestGetChannelDifference(t *testing.T) {
assert.Len(t, subs, 0, "Should get the correct number of subs")
assert.Len(t, unsubs, 2, "Should get the correct number of unsubs")
flushedSubs = []ChannelSubscription{
flushedSubs = []subscription.Subscription{
{
Channel: "Test2",
},
@@ -1126,23 +1097,23 @@ func TestGetChannelDifference(t *testing.T) {
// GenSubs defines a theoretical exchange with pair management
type GenSubs struct {
EnabledPairs currency.Pairs
subscribos []ChannelSubscription
unsubscribos []ChannelSubscription
subscribos []subscription.Subscription
unsubscribos []subscription.Subscription
}
// generateSubs default subs created from the enabled pairs list
func (g *GenSubs) generateSubs() ([]ChannelSubscription, error) {
superduperchannelsubs := make([]ChannelSubscription, len(g.EnabledPairs))
func (g *GenSubs) generateSubs() ([]subscription.Subscription, error) {
superduperchannelsubs := make([]subscription.Subscription, len(g.EnabledPairs))
for i := range g.EnabledPairs {
superduperchannelsubs[i] = ChannelSubscription{
Channel: "TEST:" + strconv.FormatInt(int64(i), 10),
Currency: g.EnabledPairs[i],
superduperchannelsubs[i] = subscription.Subscription{
Channel: "TEST:" + strconv.FormatInt(int64(i), 10),
Pair: g.EnabledPairs[i],
}
}
return superduperchannelsubs, nil
}
func (g *GenSubs) SUBME(subs []ChannelSubscription) error {
func (g *GenSubs) SUBME(subs []subscription.Subscription) error {
if len(subs) == 0 {
return errors.New("WOW")
}
@@ -1150,7 +1121,7 @@ func (g *GenSubs) SUBME(subs []ChannelSubscription) error {
return nil
}
func (g *GenSubs) UNSUBME(unsubs []ChannelSubscription) error {
func (g *GenSubs) UNSUBME(unsubs []subscription.Subscription) error {
if len(unsubs) == 0 {
return errors.New("WOW")
}
@@ -1197,19 +1168,19 @@ func TestFlushChannels(t *testing.T) {
// this to an unconnected state
}
problemFunc := func() ([]ChannelSubscription, error) {
problemFunc := func() ([]subscription.Subscription, error) {
return nil, errors.New("problems")
}
noSub := func() ([]ChannelSubscription, error) {
noSub := func() ([]subscription.Subscription, error) {
return nil, nil
}
// Disable pair and flush system
newgen.EnabledPairs = []currency.Pair{
currency.NewPair(currency.BTC, currency.AUD)}
web.GenerateSubs = func() ([]ChannelSubscription, error) {
return []ChannelSubscription{{Channel: "test"}}, nil
web.GenerateSubs = func() ([]subscription.Subscription, error) {
return []subscription.Subscription{{Channel: "test"}}, nil
}
err = web.FlushChannels()
if err != nil {
@@ -1256,14 +1227,14 @@ func TestFlushChannels(t *testing.T) {
web.subscriptionMutex.Lock()
web.subscriptions = subscriptionMap{
41: {
Key: 41,
Channel: "match channel",
Currency: currency.NewPair(currency.BTC, currency.AUD),
Key: 41,
Channel: "match channel",
Pair: currency.NewPair(currency.BTC, currency.AUD),
},
42: {
Key: 42,
Channel: "unsub channel",
Currency: currency.NewPair(currency.THETA, currency.USDT),
Key: 42,
Channel: "unsub channel",
Pair: currency.NewPair(currency.THETA, currency.USDT),
},
}
web.subscriptionMutex.Unlock()
@@ -1309,10 +1280,10 @@ func TestEnable(t *testing.T) {
connector: connect,
Wg: new(sync.WaitGroup),
ShutdownC: make(chan struct{}),
GenerateSubs: func() ([]ChannelSubscription, error) {
return []ChannelSubscription{{Channel: "test"}}, nil
GenerateSubs: func() ([]subscription.Subscription, error) {
return []subscription.Subscription{{Channel: "test"}}, nil
},
Subscriber: func(cs []ChannelSubscription) error { return nil },
Subscriber: func(cs []subscription.Subscription) error { return nil },
}
err := web.Enable()
@@ -1466,7 +1437,7 @@ func TestCheckSubscriptions(t *testing.T) {
ws.MaxSubscriptionsPerConnection = 1
err = ws.checkSubscriptions([]ChannelSubscription{{}, {}})
err = ws.checkSubscriptions([]subscription.Subscription{{}, {}})
if !errors.Is(err, errSubscriptionsExceedsLimit) {
t.Fatalf("received: %v, but expected: %v", err, errSubscriptionsExceedsLimit)
}
@@ -1474,12 +1445,12 @@ func TestCheckSubscriptions(t *testing.T) {
ws.MaxSubscriptionsPerConnection = 2
ws.subscriptions = subscriptionMap{42: {Key: 42, Channel: "test"}}
err = ws.checkSubscriptions([]ChannelSubscription{{Key: 42, Channel: "test"}})
err = ws.checkSubscriptions([]subscription.Subscription{{Key: 42, Channel: "test"}})
if !errors.Is(err, errChannelAlreadySubscribed) {
t.Fatalf("received: %v, but expected: %v", err, errChannelAlreadySubscribed)
}
err = ws.checkSubscriptions([]ChannelSubscription{{}})
err = ws.checkSubscriptions([]subscription.Subscription{{}})
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/fill"
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
"github.com/thrasher-corp/gocryptotrader/exchanges/stream/buffer"
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
)
@@ -22,7 +23,7 @@ const (
UnhandledMessage = " - Unhandled websocket message: "
)
type subscriptionMap map[any]*ChannelSubscription
type subscriptionMap map[any]*subscription.Subscription
// Websocket defines a return type for websocket connections via the interface
// wrapper for routine processing
@@ -50,18 +51,18 @@ type Websocket struct {
subscriptionMutex sync.RWMutex
subscriptions subscriptionMap
Subscribe chan []ChannelSubscription
Unsubscribe chan []ChannelSubscription
Subscribe chan []subscription.Subscription
Unsubscribe chan []subscription.Subscription
// Subscriber function for package defined websocket subscriber
// functionality
Subscriber func([]ChannelSubscription) error
Subscriber func([]subscription.Subscription) error
// Unsubscriber function for packaged defined websocket unsubscriber
// functionality
Unsubscriber func([]ChannelSubscription) error
Unsubscriber func([]subscription.Subscription) error
// GenerateSubs function for package defined websocket generate
// subscriptions functionality
GenerateSubs func() ([]ChannelSubscription, error)
GenerateSubs func() ([]subscription.Subscription, error)
DataHandler chan interface{}
ToRoutine chan interface{}
@@ -108,9 +109,9 @@ type WebsocketSetup struct {
RunningURL string
RunningURLAuth string
Connector func() error
Subscriber func([]ChannelSubscription) error
Unsubscriber func([]ChannelSubscription) error
GenerateSubscriptions func() ([]ChannelSubscription, error)
Subscriber func([]subscription.Subscription) error
Unsubscriber func([]subscription.Subscription) error
GenerateSubscriptions func() ([]subscription.Subscription, error)
Features *protocol.Features
// Local orderbook buffer config values