fix: Bitget WS keepalive — send text ping, not WebSocket PingMessage
Bitget v2 WS requires a text message "ping" every 30s, not a WebSocket PingMessage control frame (opcode 0x9). Using the wrong ping type caused a silent failure: connection stays up and subscription succeeds, but NO ticker data is pushed — zero errors, zero reconnection logs. Changes: - connector.go: Add TextPing bool flag, send text 'ping' when set - bitget.go: Set TextPing=true, handle text 'pong', add debug logging - scanner.go: Expand to 179 overlapping Bitget+HL coins
This commit is contained in:
+43
-15
@@ -47,30 +47,58 @@ func (b *BitgetWS) Run(updateFn func(coin string, price, bid, ask float64)) erro
|
||||
|
||||
b.Conn = NewPriceConnector(url, "Bitget", 120*time.Second, 30*time.Second)
|
||||
b.Conn.PingInterval = 25 * time.Second // Bitget requires ping within 30s
|
||||
b.Conn.TextPing = true // Bitget v2 expects text "ping" message
|
||||
|
||||
b.Conn.OnConnect = func() {
|
||||
log.Printf("[Bitget WS] Connected, subscribing")
|
||||
log.Printf("[Bitget WS] Connected, subscribing (%d symbols)", len(b.Tracked))
|
||||
|
||||
args := make([]map[string]string, 0, len(b.Tracked))
|
||||
for _, sym := range b.Tracked {
|
||||
args = append(args, map[string]string{
|
||||
"instType": "USDT-FUTURES",
|
||||
"channel": "ticker",
|
||||
"instId": sym,
|
||||
})
|
||||
}
|
||||
sub := map[string]interface{}{
|
||||
"op": "subscribe",
|
||||
"args": args,
|
||||
}
|
||||
if err := b.Conn.SendJSON(sub); err != nil {
|
||||
log.Printf("[Bitget WS] Subscribe error: %v", err)
|
||||
// Batch subscriptions — Bitget WS has a limit per message
|
||||
batchSize := 20
|
||||
for i := 0; i < len(b.Tracked); i += batchSize {
|
||||
end := i + batchSize
|
||||
if end > len(b.Tracked) {
|
||||
end = len(b.Tracked)
|
||||
}
|
||||
batch := b.Tracked[i:end]
|
||||
args := make([]map[string]string, len(batch))
|
||||
for j, sym := range batch {
|
||||
args[j] = map[string]string{
|
||||
"instType": "USDT-FUTURES",
|
||||
"channel": "ticker",
|
||||
"instId": sym,
|
||||
}
|
||||
}
|
||||
sub := map[string]interface{}{
|
||||
"op": "subscribe",
|
||||
"args": args,
|
||||
}
|
||||
if err := b.Conn.SendJSON(sub); err != nil {
|
||||
log.Printf("[Bitget WS] Subscribe error (batch %d): %v", i/batchSize, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.Conn.OnMessage = func(msg []byte) {
|
||||
// Handle Bitget text "pong" response
|
||||
if string(msg) == "pong" {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for Bitget subscription confirmation or error response
|
||||
var generic map[string]interface{}
|
||||
if err := json.Unmarshal(msg, &generic); err == nil {
|
||||
if evt, _ := generic["event"].(string); evt == "error" {
|
||||
log.Printf("[Bitget WS] Subscribe error response: %s", string(msg))
|
||||
return
|
||||
} else if evt == "subscribe" {
|
||||
log.Printf("[Bitget WS] Subscribe confirmed: %s", string(msg))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var ticker bitgetTickerMsg
|
||||
if err := json.Unmarshal(msg, &ticker); err != nil {
|
||||
log.Printf("[Bitget WS] Unrecognized message: %s", string(msg))
|
||||
return
|
||||
}
|
||||
if len(ticker.Data) == 0 || ticker.Data[0].LastPr == "" {
|
||||
|
||||
+13
-2
@@ -16,6 +16,10 @@ type PriceConnector struct {
|
||||
ReconnectBase time.Duration
|
||||
PingInterval time.Duration // 0 = no client-side pings
|
||||
|
||||
// TextPing: if true, sends text message "ping" instead of WebSocket PingMessage frame.
|
||||
// Used by Bitget v2 WS which expects a JSON/text "ping" string.
|
||||
TextPing bool
|
||||
|
||||
OnConnect func()
|
||||
OnMessage func([]byte)
|
||||
OnError func(error)
|
||||
@@ -91,8 +95,15 @@ func (pc *PriceConnector) Run() error {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if err := c.WriteMessage(websocket.PingMessage, nil); err != nil {
|
||||
return
|
||||
if pc.TextPing {
|
||||
// Bitget v2 expects a TEXT message "ping", not WebSocket PingMessage frame
|
||||
if err := c.WriteMessage(websocket.TextMessage, []byte("ping")); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err := c.WriteMessage(websocket.PingMessage, nil); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
case <-pingStop:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user