mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-29 15:10:37 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user