mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
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:
@@ -127,7 +127,6 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
|
||||
Unsubscriber: e.SpotUnsubscribe,
|
||||
GenerateSubscriptions: e.GenerateDefaultSubscriptionsSpot,
|
||||
Connector: e.WsConnectSpot,
|
||||
BespokeGenerateMessageID: e.GenerateWebsocketMessageID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -143,7 +142,6 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
|
||||
Unsubscriber: e.FuturesUnsubscribe,
|
||||
GenerateSubscriptions: func() (subscription.List, error) { return e.GenerateFuturesDefaultSubscriptions(currency.USDT) },
|
||||
Connector: e.WsFuturesConnect,
|
||||
BespokeGenerateMessageID: e.GenerateWebsocketMessageID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,11 +5,9 @@ import (
|
||||
"compress/flate"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -38,10 +36,6 @@ type Connection interface {
|
||||
Dial(context.Context, *gws.Dialer, http.Header) error
|
||||
ReadMessage() Response
|
||||
SetupPingHandler(request.EndpointLimit, PingHandler)
|
||||
// GenerateMessageID generates a message ID for the individual connection. If a bespoke function is set
|
||||
// (by using SetupNewConnection) it will use that, otherwise it will use the defaultGenerateMessageID function
|
||||
// defined in websocket_connection.go.
|
||||
GenerateMessageID(highPrecision bool) int64
|
||||
// SendMessageReturnResponse will send a WS message to the connection and wait for response
|
||||
SendMessageReturnResponse(ctx context.Context, epl request.EndpointLimit, signature, request any) ([]byte, error)
|
||||
// SendMessageReturnResponses will send a WS message to the connection and wait for N responses
|
||||
@@ -94,10 +88,6 @@ type ConnectionSetup struct {
|
||||
// received from the exchange's websocket server. This function should
|
||||
// handle the incoming message and pass it to the appropriate data handler.
|
||||
Handler func(ctx context.Context, conn Connection, incoming []byte) error
|
||||
// RequestIDGenerator is a function that returns a unique message ID.
|
||||
// This is useful for when an exchange connection requires a unique or
|
||||
// structured message ID for each message sent.
|
||||
RequestIDGenerator func() int64
|
||||
// Authenticate will be called to authenticate the connection
|
||||
Authenticate func(ctx context.Context, conn Connection) error
|
||||
// MessageFilter defines the criteria used to match messages to a specific connection.
|
||||
@@ -135,7 +125,6 @@ type connection struct {
|
||||
ResponseMaxLimit time.Duration
|
||||
Traffic chan struct{}
|
||||
readMessageErrors chan error
|
||||
requestIDGenerator func() int64
|
||||
}
|
||||
|
||||
// Dial sets proxy urls and then connects to the websocket
|
||||
@@ -337,33 +326,6 @@ func (c *connection) parseBinaryResponse(resp []byte) ([]byte, error) {
|
||||
return standardMessage, reader.Close()
|
||||
}
|
||||
|
||||
// GenerateMessageID generates a message ID for the individual connection.
|
||||
// If a bespoke function is set (by using SetupNewConnection) it will use that,
|
||||
// otherwise it will use the defaultGenerateMessageID function.
|
||||
func (c *connection) GenerateMessageID(highPrec bool) int64 {
|
||||
if c.requestIDGenerator != nil {
|
||||
return c.requestIDGenerator()
|
||||
}
|
||||
return c.defaultGenerateMessageID(highPrec)
|
||||
}
|
||||
|
||||
// defaultGenerateMessageID generates the default message ID
|
||||
func (c *connection) defaultGenerateMessageID(highPrec bool) int64 {
|
||||
var minValue int64 = 1e8
|
||||
var maxValue int64 = 2e8
|
||||
if highPrec {
|
||||
maxValue = 2e12
|
||||
minValue = 1e12
|
||||
}
|
||||
// utilization of hard coded positive numbers and default crypto/rand
|
||||
// io.reader will panic on error instead of returning
|
||||
randomNumber, err := rand.Int(rand.Reader, big.NewInt(maxValue-minValue+1))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return randomNumber.Int64() + minValue
|
||||
}
|
||||
|
||||
// Shutdown shuts down and closes specific connection
|
||||
func (c *connection) Shutdown() error {
|
||||
if err := common.NilGuard(c, c.Connection); err != nil {
|
||||
|
||||
@@ -305,7 +305,7 @@ func (m *Manager) SetupNewConnection(c *ConnectionSetup) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.ResponseCheckTimeout == 0 && c.ResponseMaxLimit == 0 && c.RateLimit == nil && c.URL == "" && c.ConnectionLevelReporter == nil && c.RequestIDGenerator == nil {
|
||||
if c.ResponseCheckTimeout == 0 && c.ResponseMaxLimit == 0 && c.RateLimit == nil && c.URL == "" && c.ConnectionLevelReporter == nil {
|
||||
return fmt.Errorf("%w: %w", errConnSetup, errExchangeConfigEmpty)
|
||||
}
|
||||
|
||||
@@ -401,7 +401,6 @@ func (m *Manager) getConnectionFromSetup(c *ConnectionSetup) *connection {
|
||||
Match: match,
|
||||
RateLimit: c.RateLimit,
|
||||
Reporter: c.ConnectionLevelReporter,
|
||||
requestIDGenerator: c.RequestIDGenerator,
|
||||
RateLimitDefinitions: m.rateLimitDefinitions,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ func TestSendMessageReturnResponse(t *testing.T) {
|
||||
Subscription: testRequestData{
|
||||
Name: "ticker",
|
||||
},
|
||||
RequestID: wc.GenerateMessageID(false),
|
||||
RequestID: 12345,
|
||||
}
|
||||
|
||||
_, err = wc.SendMessageReturnResponse(t.Context(), request.Unset, req.RequestID, req)
|
||||
@@ -758,37 +758,6 @@ func TestCanUseAuthenticatedWebsocketForWrapper(t *testing.T) {
|
||||
assert.True(t, ws.CanUseAuthenticatedWebsocketForWrapper(), "CanUseAuthenticatedWebsocketForWrapper should return true")
|
||||
}
|
||||
|
||||
func TestGenerateMessageID(t *testing.T) {
|
||||
t.Parallel()
|
||||
wc := connection{}
|
||||
const spins = 1000
|
||||
ids := make([]int64, spins)
|
||||
for i := range spins {
|
||||
id := wc.GenerateMessageID(true)
|
||||
assert.NotContains(t, ids, id, "GenerateMessageID should not generate the same ID twice")
|
||||
ids[i] = id
|
||||
}
|
||||
|
||||
wc.requestIDGenerator = func() int64 { return 42 }
|
||||
assert.EqualValues(t, 42, wc.GenerateMessageID(true), "GenerateMessageID should use bespokeGenerateMessageID")
|
||||
}
|
||||
|
||||
// 7002502 166.7 ns/op 48 B/op 3 allocs/op
|
||||
func BenchmarkGenerateMessageID_High(b *testing.B) {
|
||||
wc := connection{}
|
||||
for b.Loop() {
|
||||
_ = wc.GenerateMessageID(true)
|
||||
}
|
||||
}
|
||||
|
||||
// 6536250 186.1 ns/op 48 B/op 3 allocs/op
|
||||
func BenchmarkGenerateMessageID_Low(b *testing.B) {
|
||||
wc := connection{}
|
||||
for b.Loop() {
|
||||
_ = wc.GenerateMessageID(false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckWebsocketURL(t *testing.T) {
|
||||
err := checkWebsocketURL("")
|
||||
assert.ErrorIs(t, err, errInvalidWebsocketURL, "checkWebsocketURL should error correctly on empty string")
|
||||
@@ -1135,7 +1104,7 @@ func TestLatency(t *testing.T) {
|
||||
Event: "subscribe",
|
||||
Pairs: []string{currency.NewPairWithDelimiter("XBT", "USD", "/").String()},
|
||||
Subscription: testRequestData{Name: "ticker"},
|
||||
RequestID: wc.GenerateMessageID(false),
|
||||
RequestID: 12346,
|
||||
}
|
||||
|
||||
_, err = wc.SendMessageReturnResponse(t.Context(), request.Unset, req.RequestID, req)
|
||||
|
||||
Reference in New Issue
Block a user