timeout relay connections at 2s.

This commit is contained in:
fiatjaf
2026-07-21 18:51:41 -03:00
parent a9df9c6a21
commit aac995714b
5 changed files with 142 additions and 68 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"strings"
"time"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/nip45"
@@ -63,11 +64,19 @@ var count = &cli.Command{
hll = hyperloglog.New(offset)
}
for _, relayUrl := range relayUrls {
relay, err := sys.Pool.EnsureRelay(relayUrl)
if err != nil {
fmt.Fprintf(os.Stderr, "%s%s: ", strings.Repeat(" ", biggerUrlSize-len(relayUrl)), relayUrl)
fmt.Fprintf(os.Stderr, "error: %s\n", err)
continue
nm := nostr.NormalizeURL(relayUrl)
relay, ok := sys.Pool.Relays.Load(nm)
if !ok || relay == nil || !relay.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
var err error
relay, err = nostr.RelayConnect(ct, relayUrl, sys.Pool.RelayOptions)
cancel()
if err != nil {
fmt.Fprintf(os.Stderr, "%s%s: ", strings.Repeat(" ", biggerUrlSize-len(relayUrl)), relayUrl)
fmt.Fprintf(os.Stderr, "error: %s\n", err)
continue
}
sys.Pool.Relays.Store(nm, relay)
}
count, hllRegisters, err := relay.Count(ctx, filter, nostr.SubscriptionOptions{

View File

@@ -543,9 +543,19 @@ func publishFlow(ctx context.Context, c *cli.Command, kr nostr.Signer, evt nostr
defer cancel()
if !relay.IsConnected() {
if new_, err := sys.Pool.EnsureRelay(relay.URL); err == nil {
relays[i] = new_
relay = new_
nm := nostr.NormalizeURL(relay.URL)
if r, ok := sys.Pool.Relays.Load(nm); ok && r != nil && r.IsConnected() {
relays[i] = r
relay = r
} else {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
new_, err := nostr.RelayConnect(ct, relay.URL, sys.Pool.RelayOptions)
cancel()
if err == nil {
sys.Pool.Relays.Store(nm, new_)
relays[i] = new_
relay = new_
}
}
}

View File

@@ -243,9 +243,17 @@ var group = &cli.Command{
return err
}
r, err := sys.Pool.EnsureRelay(relay)
if err != nil {
return err
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
var err error
r, err = nostr.RelayConnect(ct, relay, sys.Pool.RelayOptions)
cancel()
if err != nil {
return err
}
sys.Pool.Relays.Store(nm, r)
}
sub, err := r.Subscribe(ctx, nostr.Filter{
@@ -316,11 +324,19 @@ var group = &cli.Command{
return fmt.Errorf("failed to sign message: %w", err)
}
if r, err := sys.Pool.EnsureRelay(relay); err != nil {
return err
} else {
return r.Publish(ctx, msg)
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
var err error
r, err = nostr.RelayConnect(ct, relay, sys.Pool.RelayOptions)
cancel()
if err != nil {
return err
}
sys.Pool.Relays.Store(nm, r)
}
return r.Publish(ctx, msg)
},
},
},
@@ -474,9 +490,17 @@ write your forum post
return fmt.Errorf("failed to sign forum topic event: %w", err)
}
r, err := sys.Pool.EnsureRelay(relay)
if err != nil {
return err
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
var err error
r, err = nostr.RelayConnect(ct, relay, sys.Pool.RelayOptions)
cancel()
if err != nil {
return err
}
sys.Pool.Relays.Store(nm, r)
}
return r.Publish(ctx, evt)
@@ -581,9 +605,17 @@ write your forum post
return fmt.Errorf("failed to sign forum comment event: %w", err)
}
r, err := sys.Pool.EnsureRelay(relay)
if err != nil {
return err
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
var err error
r, err = nostr.RelayConnect(ct, relay, sys.Pool.RelayOptions)
cancel()
if err != nil {
return err
}
sys.Pool.Relays.Store(nm, r)
}
return r.Publish(ctx, evt)
@@ -906,9 +938,17 @@ func publishModerationEvent(ctx context.Context, c *cli.Command, kind nostr.Kind
stdout(evt.String())
r, err := sys.Pool.EnsureRelay(relay)
if err != nil {
return err
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), 2*time.Second)
var err error
r, err = nostr.RelayConnect(ct, relay, sys.Pool.RelayOptions)
cancel()
if err != nil {
return err
}
sys.Pool.Relays.Store(nm, r)
}
return r.Publish(ctx, evt)

View File

@@ -268,63 +268,75 @@ func connectToSingleRelay(
colorizepreamble func(c func(string, ...any) string),
logthis func(s string, args ...any),
) *nostr.Relay {
if relay, err := sys.Pool.EnsureRelay(url); err == nil {
if c.Bool("force-pre-auth") {
if colorizepreamble != nil {
colorizepreamble(color.YellowString)
}
logthis("waiting for auth challenge... ")
time.Sleep(time.Millisecond * 200)
nm := nostr.NormalizeURL(url)
for range 5 {
if err := relay.Auth(ctx, func(ctx context.Context, authEvent *nostr.Event) error {
challengeTag := authEvent.Tags.Find("challenge")
if challengeTag == nil || len(challengeTag) < 2 || challengeTag[1] == "" {
return fmt.Errorf("auth not received yet *****") // what a giant hack
}
return authSigner(ctx, c, logthis, authEvent)
}); err == nil {
// auth succeeded
goto preauthSuccess
} else {
// auth failed
if strings.HasSuffix(err.Error(), "auth not received yet *****") {
// it failed because we didn't receive the challenge yet, so keep waiting
time.Sleep(time.Second)
continue
} else {
// it failed for some other reason, so skip this relay
if colorizepreamble != nil {
colorizepreamble(colors.errorf)
}
logthis(err.Error())
return nil
}
}
}
relay, ok := sys.Pool.Relays.Load(nm)
if !ok || relay == nil || !relay.IsConnected() {
connectCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
var err error
if relay, err = nostr.RelayConnect(connectCtx, url, sys.Pool.RelayOptions); err != nil {
if colorizepreamble != nil {
colorizepreamble(colors.errorf)
}
logthis("failed to get an AUTH challenge in enough time.")
logthis(clampError(err, len(url)+12))
return nil
}
preauthSuccess:
sys.Pool.Relays.Store(nm, relay)
go func(r *nostr.Relay, relayURL string) {
<-r.Context().Done()
if current, ok := sys.Pool.Relays.Load(relayURL); ok && current == r {
sys.Pool.Relays.Delete(relayURL)
}
}(relay, nm)
}
if c.Bool("force-pre-auth") {
if colorizepreamble != nil {
colorizepreamble(colors.successf)
colorizepreamble(color.YellowString)
}
logthis("waiting for auth challenge... ")
time.Sleep(time.Millisecond * 200)
for range 5 {
if err := relay.Auth(ctx, func(ctx context.Context, authEvent *nostr.Event) error {
challengeTag := authEvent.Tags.Find("challenge")
if challengeTag == nil || len(challengeTag) < 2 || challengeTag[1] == "" {
return fmt.Errorf("auth not received yet *****") // what a giant hack
}
return authSigner(ctx, c, logthis, authEvent)
}); err == nil {
// auth succeeded
goto preauthSuccess
} else {
// auth failed
if strings.HasSuffix(err.Error(), "auth not received yet *****") {
time.Sleep(time.Second)
continue
} else {
if colorizepreamble != nil {
colorizepreamble(colors.errorf)
}
logthis(err.Error())
return nil
}
}
}
logthis("ok.")
return relay
} else {
if colorizepreamble != nil {
colorizepreamble(colors.errorf)
}
// if we're here that means we've failed to connect, this may be a huge message
// but we're likely to only be interested in the lowest level error (although we can leave space)
logthis(clampError(err, len(url)+12))
logthis("failed to get an AUTH challenge in enough time.")
return nil
}
preauthSuccess:
if colorizepreamble != nil {
colorizepreamble(colors.successf)
}
logthis("ok.")
return relay
}
func clearLines(lineCount int) {

View File

@@ -996,10 +996,13 @@ func (r *NostrRoot) publishNote(path string) {
}
for _, url := range relays {
relay, err := r.sys.Pool.EnsureRelay(url)
connectCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
relay, err := nostr.RelayConnect(connectCtx, url, r.sys.Pool.RelayOptions)
cancel()
if err != nil {
continue
}
r.sys.Pool.Relays.Store(nostr.NormalizeURL(url), relay)
relay.Publish(ctx, *evt)
}