From 989e53c9584aeb530eca3e790d452ef2350ef409 Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Sat, 2 May 2026 04:02:49 -0400 Subject: [PATCH] fix(monitor/collectors/coinbase): parse Coinbase's Go-style time format in heartbeat current_time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coinbase Advanced Trade WS leaks Go's time.Time.String() format in heartbeat events (e.g. "2026-05-02 07:55:50.784... +0000 UTC m=+102632...") which is not RFC 3339 — UnmarshalJSON into time.Time fails and the entire envelope errors. Decode current_time as a string and parse it with a fallback that handles both RFC 3339 and the Go-string variant (with the m=+monotonic suffix stripped). --- .../internal/collectors/coinbase/client.go | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/backend/internal/collectors/coinbase/client.go b/PROJECTS/advanced/monitor-the-situation-dashboard/backend/internal/collectors/coinbase/client.go index 20350da0..5e5e2009 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/backend/internal/collectors/coinbase/client.go +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/backend/internal/collectors/coinbase/client.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "fmt" + "strings" "time" "github.com/coder/websocket" @@ -137,7 +138,23 @@ type rawEnvelope struct { type rawEnvelopeEv struct { Type string `json:"type"` Tickers []TickerEntry `json:"tickers,omitempty"` - CurrentTime time.Time `json:"current_time,omitempty"` + CurrentTime string `json:"current_time,omitempty"` +} + +func parseCoinbaseTime(s string) time.Time { + if s == "" { + return time.Time{} + } + if t, err := time.Parse(time.RFC3339Nano, s); err == nil { + return t + } + if idx := strings.Index(s, " m=+"); idx > 0 { + s = s[:idx] + } + if t, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", s); err == nil { + return t + } + return time.Time{} } var ErrFrameMalformed = errors.New("coinbase: malformed frame") @@ -169,7 +186,7 @@ func decodeFrame(msg []byte) (Frame, error) { case channelHeartbeats: frame.Kind = FrameTypeHeartbeats if len(env.Events) > 0 { - frame.HeartbeatTime = env.Events[0].CurrentTime + frame.HeartbeatTime = parseCoinbaseTime(env.Events[0].CurrentTime) } return frame, nil