From 69c0981b5167c49a6df6d51f9cc95fa03e91fa65 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Sat, 23 Aug 2025 09:54:36 -0300 Subject: [PATCH] address closeMutex deadlock by canceling the relay connection context on doClose(). --- connection.go | 9 +++++++-- relay.go | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/connection.go b/connection.go index fd38b84..609ce37 100644 --- a/connection.go +++ b/connection.go @@ -5,6 +5,7 @@ import ( "context" "crypto/tls" "errors" + "fmt" "io" "net/http" "sync" @@ -19,6 +20,7 @@ var ErrDisconnected = errors.New("") // Connection represents a websocket connection to a Nostr relay. type connection struct { conn *ws.Conn + cancel context.CancelCauseFunc writeQueue chan writeRequest closed *atomic.Bool closedNotify chan struct{} @@ -32,6 +34,7 @@ type writeRequest struct { func newConnection( ctx context.Context, + cancel context.CancelCauseFunc, url string, handleMessage func(string), requestHeader http.Header, @@ -62,6 +65,7 @@ func newConnection( conn := &connection{ conn: c, + cancel: cancel, writeQueue: writeQueue, closed: &atomic.Bool{}, closedNotify: make(chan struct{}), @@ -81,8 +85,8 @@ func newConnection( err := c.Ping(ctx) cancel() if err != nil { - conn.doClose(ws.StatusAbnormalClosure, "ping took too long") debugLogf("{%s} closing!, ping failed: '%s'\n", url, err) + conn.doClose(ws.StatusAbnormalClosure, "ping took too long") return } case wr := <-writeQueue: @@ -91,11 +95,11 @@ func newConnection( err := c.Write(ctx, ws.MessageText, wr.msg) cancel() if err != nil { + debugLogf("{%s} closing!, write failed: '%s'\n", url, err) conn.doClose(ws.StatusAbnormalClosure, "write failed") if wr.answer != nil { wr.answer <- err } - debugLogf("{%s} closing!, write failed: '%s'\n", url, err) return } if wr.answer != nil { @@ -138,6 +142,7 @@ func (c *connection) doClose(code ws.StatusCode, reason string) { wasClosed := c.closed.Swap(true) if !wasClosed { c.conn.Close(code, reason) + c.cancel(fmt.Errorf("doClose(): %s", reason)) c.closeMutex.Lock() close(c.closedNotify) close(c.writeQueue) diff --git a/relay.go b/relay.go index 6b67f8c..8acf861 100644 --- a/relay.go +++ b/relay.go @@ -118,7 +118,7 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error return fmt.Errorf("invalid relay URL '%s'", r.URL) } - conn, err := newConnection(ctx, r.URL, r.handleMessage, r.requestHeader, tlsConfig) + conn, err := newConnection(ctx, r.connectionContextCancel, r.URL, r.handleMessage, r.requestHeader, tlsConfig) if err != nil { return fmt.Errorf("error opening websocket to '%s': %w", r.URL, err) }