websocket: Remove GenerateMessageID (#2008)

* Exchanges: Remove example BespokeGenerateMessageID

* Okx: Replace conn.RequestIDGenerator with MesssageID

Continued overall direction to remove the closed-loop of e => conn => e
roundtrip for message ids

* Exchanges: Add MessageSequence

This method removes the either/or nature of message id generation.
We don't tie the message ids to connections, or to anything.
Consumers just call whichever they want, or even combine them as they
want.
Anything more complicated will need a separate installation anyway

* GateIO: Split usage of MessageID and MessageSequence

* Binance: Switch to UUID message IDs

* Kraken: Switch to e.MessageSequence

* Kucoin: Switch to MessageID

* HitBTC: Switch to UUIDv7 for ws message ID

* Bybit: Switch to UUIDv7 for ws message ID

* Bitfinex: Switch to UUIDv7 and MessageSequence

Tested CID - It accepts 53 bits only for an int, so MessageSequence
makes sense. Can't use MessageID

* Websocket: Remove now unused MessageID function

Moved all MessageID usage into funcs and onto base methods, to remove
the closed loop of message IDs

* Docs: Update guidance for message signatures
This commit is contained in:
Gareth Kirwan
2025-10-24 07:14:24 +07:00
committed by GitHub
parent 0f70cfd8b6
commit bda9bbec66
33 changed files with 137 additions and 224 deletions

View File

@@ -2768,7 +2768,6 @@ func TestGetSettlementCurrency(t *testing.T) {
type FixtureConnection struct{ websocket.Connection }
func (d *FixtureConnection) GenerateMessageID(bool) int64 { return 1337 }
func (d *FixtureConnection) SendMessageReturnResponse(context.Context, request.EndpointLimit, any, any) ([]byte, error) {
return []byte(`{"time":1726121320,"time_ms":1726121320745,"id":1,"conn_id":"f903779a148987ca","trace_id":"d8ee37cd14347e4ed298d44e69aedaa7","channel":"spot.tickers","event":"subscribe","payload":["BRETT_USDT"],"result":{"status":"success"},"requestId":"d8ee37cd14347e4ed298d44e69aedaa7"}`), nil
}
@@ -2778,12 +2777,12 @@ func TestHandleSubscriptions(t *testing.T) {
subs := subscription.List{{Channel: subscription.OrderbookChannel}}
err := e.handleSubscription(t.Context(), &FixtureConnection{}, subscribeEvent, subs, func(context.Context, websocket.Connection, string, subscription.List) ([]WsInput, error) {
err := e.handleSubscription(t.Context(), &FixtureConnection{}, subscribeEvent, subs, func(context.Context, string, subscription.List) ([]WsInput, error) {
return []WsInput{{}}, nil
})
require.NoError(t, err)
err = e.handleSubscription(t.Context(), &FixtureConnection{}, unsubscribeEvent, subs, func(context.Context, websocket.Connection, string, subscription.List) ([]WsInput, error) {
err = e.handleSubscription(t.Context(), &FixtureConnection{}, unsubscribeEvent, subs, func(context.Context, string, subscription.List) ([]WsInput, error) {
return []WsInput{{}}, nil
})
require.NoError(t, err)

View File

@@ -124,7 +124,7 @@ func (e *Exchange) websocketLogin(ctx context.Context, conn websocket.Connection
signature := hex.EncodeToString(mac.Sum(nil))
payload := WebsocketPayload{
RequestID: strconv.FormatInt(conn.GenerateMessageID(false), 10),
RequestID: e.MessageID(),
APIKey: creds.Key,
Signature: signature,
Timestamp: strconv.FormatInt(tn, 10),
@@ -640,7 +640,7 @@ func (e *Exchange) manageSubs(ctx context.Context, event string, conn websocket.
for _, s := range subs {
if err := func() error {
msg, err := e.manageSubReq(ctx, event, conn, s)
msg, err := e.manageSubReq(ctx, event, s)
if err != nil {
return err
}
@@ -667,9 +667,9 @@ func (e *Exchange) manageSubs(ctx context.Context, event string, conn websocket.
}
// manageSubReq constructs the subscription management message for a subscription
func (e *Exchange) manageSubReq(ctx context.Context, event string, conn websocket.Connection, s *subscription.Subscription) (*WsInput, error) {
func (e *Exchange) manageSubReq(ctx context.Context, event string, s *subscription.Subscription) (*WsInput, error) {
req := &WsInput{
ID: conn.GenerateMessageID(false),
ID: e.MessageSequence(),
Event: event,
Channel: channelName(s),
Time: time.Now().Unix(),
@@ -886,11 +886,11 @@ const subTplText = `
`
// GeneratePayload returns the payload for a websocket message
type GeneratePayload func(ctx context.Context, conn websocket.Connection, event string, channelsToSubscribe subscription.List) ([]WsInput, error)
type GeneratePayload func(ctx context.Context, event string, channelsToSubscribe subscription.List) ([]WsInput, error)
// handleSubscription sends a websocket message to receive data from the channel
func (e *Exchange) handleSubscription(ctx context.Context, conn websocket.Connection, event string, channelsToSubscribe subscription.List, generatePayload GeneratePayload) error {
payloads, err := generatePayload(ctx, conn, event, channelsToSubscribe)
payloads, err := generatePayload(ctx, event, channelsToSubscribe)
if err != nil {
return err
}
@@ -941,7 +941,7 @@ func (e *Exchange) SendWebsocketRequest(ctx context.Context, epl request.Endpoin
Channel: channel,
Event: "api",
Payload: WebsocketPayload{
RequestID: strconv.FormatInt(conn.GenerateMessageID(false), 10),
RequestID: e.MessageID(),
RequestParam: paramPayload,
Timestamp: strconv.FormatInt(tn, 10),
},

View File

@@ -111,7 +111,7 @@ func (e *Exchange) DeliveryFuturesUnsubscribe(ctx context.Context, conn websocke
return e.handleSubscription(ctx, conn, unsubscribeEvent, channelsToUnsubscribe, e.generateDeliveryFuturesPayload)
}
func (e *Exchange) generateDeliveryFuturesPayload(ctx context.Context, conn websocket.Connection, event string, channelsToSubscribe subscription.List) ([]WsInput, error) {
func (e *Exchange) generateDeliveryFuturesPayload(ctx context.Context, event string, channelsToSubscribe subscription.List) ([]WsInput, error) {
if len(channelsToSubscribe) == 0 {
return nil, errors.New("cannot generate payload, no channels supplied")
}
@@ -194,7 +194,7 @@ func (e *Exchange) generateDeliveryFuturesPayload(ctx context.Context, conn webs
}
}
outbound = append(outbound, WsInput{
ID: conn.GenerateMessageID(false),
ID: e.MessageSequence(),
Event: event,
Channel: channelsToSubscribe[i].Channel,
Payload: params,

View File

@@ -194,7 +194,7 @@ func (e *Exchange) WsHandleFuturesData(ctx context.Context, conn websocket.Conne
}
}
func (e *Exchange) generateFuturesPayload(ctx context.Context, conn websocket.Connection, event string, channelsToSubscribe subscription.List) ([]WsInput, error) {
func (e *Exchange) generateFuturesPayload(ctx context.Context, event string, channelsToSubscribe subscription.List) ([]WsInput, error) {
if len(channelsToSubscribe) == 0 {
return nil, errors.New("cannot generate payload, no channels supplied")
}
@@ -280,7 +280,7 @@ func (e *Exchange) generateFuturesPayload(ctx context.Context, conn websocket.Co
}
}
outbound = append(outbound, WsInput{
ID: conn.GenerateMessageID(false),
ID: e.MessageSequence(),
Event: event,
Channel: channelsToSubscribe[i].Channel,
Payload: params,

View File

@@ -160,7 +160,7 @@ getEnabledPairs:
return subscriptions, nil
}
func (e *Exchange) generateOptionsPayload(ctx context.Context, conn websocket.Connection, event string, channelsToSubscribe subscription.List) ([]WsInput, error) {
func (e *Exchange) generateOptionsPayload(ctx context.Context, event string, channelsToSubscribe subscription.List) ([]WsInput, error) {
if len(channelsToSubscribe) == 0 {
return nil, errors.New("cannot generate payload, no channels supplied")
}
@@ -262,7 +262,7 @@ func (e *Exchange) generateOptionsPayload(ctx context.Context, conn websocket.Co
params...)
}
payloads[i] = WsInput{
ID: conn.GenerateMessageID(false),
ID: e.MessageSequence(),
Event: event,
Channel: channelsToSubscribe[i].Channel,
Payload: params,

View File

@@ -219,7 +219,6 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
Connector: e.WsConnectSpot,
Authenticate: e.authenticateSpot,
MessageFilter: asset.Spot,
RequestIDGenerator: e.messageIDSeq.IncrementAndGet,
})
if err != nil {
return err
@@ -237,10 +236,9 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
GenerateSubscriptions: func() (subscription.List, error) {
return e.GenerateFuturesDefaultSubscriptions(asset.USDTMarginedFutures)
},
Connector: e.WsFuturesConnect,
Authenticate: e.authenticateFutures,
MessageFilter: asset.USDTMarginedFutures,
RequestIDGenerator: e.messageIDSeq.IncrementAndGet,
Connector: e.WsFuturesConnect,
Authenticate: e.authenticateFutures,
MessageFilter: asset.USDTMarginedFutures,
})
if err != nil {
return err
@@ -259,9 +257,8 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
GenerateSubscriptions: func() (subscription.List, error) {
return e.GenerateFuturesDefaultSubscriptions(asset.CoinMarginedFutures)
},
Connector: e.WsFuturesConnect,
MessageFilter: asset.CoinMarginedFutures,
RequestIDGenerator: e.messageIDSeq.IncrementAndGet,
Connector: e.WsFuturesConnect,
MessageFilter: asset.CoinMarginedFutures,
})
if err != nil {
return err
@@ -281,7 +278,6 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
GenerateSubscriptions: e.GenerateDeliveryFuturesDefaultSubscriptions,
Connector: e.WsDeliveryFuturesConnect,
MessageFilter: asset.DeliveryFutures,
RequestIDGenerator: e.messageIDSeq.IncrementAndGet,
})
if err != nil {
return err
@@ -298,7 +294,6 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
GenerateSubscriptions: e.GenerateOptionsDefaultSubscriptions,
Connector: e.WsOptionsConnect,
MessageFilter: asset.Options,
RequestIDGenerator: e.messageIDSeq.IncrementAndGet,
})
}