stream: force subscription store check as stop gap for wrapper side implementation (#1717)

* Add check for subscription store insertion and validation with tests

* bybit: fix subscriptions

* deribit: fix subscriptions

* linter: fix

* glorious/nits: add test for updateChannelSubscriptions RM GetChannelDifference method as its only used locally and Diff method can be accessed directly

* glorious/nits: add to store in the loop; add correct formatting to template for edge case perps with settlement

* spelling: fix

* glorious/nit: silly billy

* gk: nits

* gk/nits: split PartitionByPresence into Contained and Missing

* gk/nits: formatPerpetualPairWithSettlement -> formatChannelPair

* stream/websocket: stop full websocket disconnect on Connect when encountering subscription specific error paths

* stream/websocket: rm nil assignment

* glorious: nits

* gk: niterinos

* Update exchanges/stream/websocket_test.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* Update exchanges/stream/websocket_test.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* Update exchanges/stream/websocket_test.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* thrasher: nits

---------

Co-authored-by: shazbert <ryan.oharareid@thrasher.io>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Ryan O'Hara-Reid
2025-02-24 15:25:49 +11:00
committed by GitHub
parent ef0f398455
commit 3a80cd2871
8 changed files with 376 additions and 181 deletions

View File

@@ -4094,3 +4094,14 @@ func TestGetCurrencyTradeURL(t *testing.T) {
require.NoError(t, err)
assert.NotEmpty(t, resp)
}
func TestFormatChannelPair(t *testing.T) {
t.Parallel()
pair := currency.NewPair(currency.BTC, currency.NewCode("USDC-PERPETUAL"))
pair.Delimiter = "-"
assert.Equal(t, "BTC_USDC-PERPETUAL", formatChannelPair(pair))
pair = currency.NewPair(currency.BTC, currency.NewCode("PERPETUAL"))
pair.Delimiter = "-"
assert.Equal(t, "BTC-PERPETUAL", formatChannelPair(pair))
}

View File

@@ -779,6 +779,7 @@ func (d *Deribit) GetSubscriptionTemplate(_ *subscription.Subscription) (*templa
"channelName": channelName,
"interval": channelInterval,
"isSymbolChannel": isSymbolChannel,
"fmt": formatChannelPair,
}).
Parse(subTplText)
}
@@ -805,18 +806,19 @@ func (d *Deribit) handleSubscription(method string, subs subscription.List) erro
if err != nil || len(subs) == 0 {
return err
}
r := WsSubscriptionInput{
JSONRPCVersion: rpcVersion,
ID: d.Websocket.Conn.GenerateMessageID(false),
Method: method,
Params: map[string][]string{
"channels": subs.QualifiedChannels(),
},
Params: map[string][]string{"channels": subs.QualifiedChannels()},
}
data, err := d.Websocket.Conn.SendMessageReturnResponse(context.TODO(), request.Unset, r.ID, r)
if err != nil {
return err
}
var response wsSubscriptionResponse
err = json.Unmarshal(data, &response)
if err != nil {
@@ -827,15 +829,25 @@ func (d *Deribit) handleSubscription(method string, subs subscription.List) erro
subAck[c] = true
}
if len(subAck) != len(subs) {
err = common.ErrUnknownError
err = stream.ErrSubscriptionFailure
}
for _, s := range subs {
if _, ok := subAck[s.QualifiedChannel]; ok {
err = common.AppendError(err, d.Websocket.AddSuccessfulSubscriptions(d.Websocket.Conn, s))
delete(subAck, s.QualifiedChannel)
if !strings.Contains(method, "unsubscribe") {
err = common.AppendError(err, d.Websocket.AddSuccessfulSubscriptions(d.Websocket.Conn, s))
} else {
err = common.AppendError(err, d.Websocket.RemoveSubscriptions(d.Websocket.Conn, s))
}
} else {
err = common.AppendError(err, errors.New(s.String()))
err = common.AppendError(err, errors.New(s.String()+" failed to "+method))
}
}
for key := range subAck {
err = common.AppendError(err, fmt.Errorf("unexpected channel `%s` in result", key))
}
return err
}
@@ -899,11 +911,18 @@ func isSymbolChannel(s *subscription.Subscription) bool {
return false
}
func formatChannelPair(pair currency.Pair) string {
if str := pair.Quote.String(); strings.Contains(str, "PERPETUAL") && strings.Contains(str, "-") {
pair.Delimiter = "_"
}
return pair.String()
}
const subTplText = `
{{- if isSymbolChannel $.S -}}
{{- range $asset, $pairs := $.AssetPairs }}
{{- range $p := $pairs }}
{{- channelName $.S -}} . {{- $p }}
{{- channelName $.S -}} . {{- fmt $p }}
{{- with $i := interval $.S -}} . {{- $i }}{{ end }}
{{- $.PairSeparator }}
{{- end }}