mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-11-18 18:16:50 +01:00
relay: introduce ConnectContext for better control over network latency
A websocket dial may hand for an unreasonably long time and a nostr client has no control over this when trying to connect to a relay. Go started introducing context in networking since 2014 - see https://go.dev/blog/context - and by now many net functions have XxxContext equivalent, such as DialContext. Example usage of the change introduced by this commit: ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() r, err := nostr.RelayConnectContext(ctx, "ws://relay.example.org") The code above makes RelayConnectContext last at most 3 sec, returning an error if a connection cannot be established in the given time. This helps whenever a tight control over connection latency is required, such as distributed systems. The change is backwards-compatible except the case where RelayPool.Add sent an error over the returned channel without actually closing said channel. I believe it was a bug.
This commit is contained in:
21
relay.go
21
relay.go
@@ -1,6 +1,7 @@
|
||||
package nostr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -45,9 +46,16 @@ type Relay struct {
|
||||
statusChans s.MapOf[string, chan Status]
|
||||
}
|
||||
|
||||
// RelayConnect forwards calls to RelayConnectContext with a background context.
|
||||
func RelayConnect(url string) (*Relay, error) {
|
||||
return RelayConnectContext(context.Background(), url)
|
||||
}
|
||||
|
||||
// RelayConnectContext creates a new relay client and connects to a canonical
|
||||
// URL using Relay.ConnectContext, passing ctx as is.
|
||||
func RelayConnectContext(ctx context.Context, url string) (*Relay, error) {
|
||||
r := &Relay{URL: NormalizeURL(url)}
|
||||
err := r.Connect()
|
||||
err := r.ConnectContext(ctx)
|
||||
return r, err
|
||||
}
|
||||
|
||||
@@ -55,12 +63,21 @@ func (r *Relay) String() string {
|
||||
return r.URL
|
||||
}
|
||||
|
||||
// Connect calls ConnectContext with a background context.
|
||||
func (r *Relay) Connect() error {
|
||||
return r.ConnectContext(context.Background())
|
||||
}
|
||||
|
||||
// ConnectContext tries to establish a websocket connection to r.URL.
|
||||
// If the context expires before the connection is complete, an error is returned.
|
||||
// Once successfully connected, context expiration has no effect: call r.Close
|
||||
// to close the connection.
|
||||
func (r *Relay) ConnectContext(ctx context.Context) error {
|
||||
if r.URL == "" {
|
||||
return fmt.Errorf("invalid relay URL '%s'", r.URL)
|
||||
}
|
||||
|
||||
socket, _, err := websocket.DefaultDialer.Dial(r.URL, nil)
|
||||
socket, _, err := websocket.DefaultDialer.DialContext(ctx, r.URL, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening websocket to '%s': %w", r.URL, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user