Compare commits

...

3 Commits

Author SHA1 Message Date
fiatjaf
1403c7d2cd fetch: use more outbox relays. 2026-07-21 20:42:52 -03:00
fiatjaf
6855722ba5 make the relay connection timeout configurable. 2026-07-21 20:41:45 -03:00
fiatjaf
aac995714b timeout relay connections at 2s. 2026-07-21 18:51:41 -03:00
7 changed files with 159 additions and 69 deletions

View File

@@ -63,12 +63,20 @@ var count = &cli.Command{
hll = hyperloglog.New(offset)
}
for _, relayUrl := range relayUrls {
relay, err := sys.Pool.EnsureRelay(relayUrl)
nm := nostr.NormalizeURL(relayUrl)
relay, ok := sys.Pool.Relays.Load(nm)
if !ok || relay == nil || !relay.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), connectTimeout)
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{
Label: "nak-count",

View File

@@ -543,11 +543,21 @@ 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 {
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(), connectTimeout)
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_
}
}
}
err := relay.Publish(ctx, evt)
if err == nil {

View File

@@ -101,7 +101,7 @@ var fetch = &cli.Command{
sys.Hints.Save(authorHint, nostr.NormalizeURL(url), hints.LastInHint, nostr.Now())
}
for _, url := range sys.FetchOutboxRelays(ctx, authorHint, 3) {
for _, url := range sys.FetchOutboxRelays(ctx, authorHint, 6) {
relays = append(relays, url)
}
}

View File

@@ -243,10 +243,18 @@ var group = &cli.Command{
return err
}
r, err := sys.Pool.EnsureRelay(relay)
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), connectTimeout)
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{
Kinds: []nostr.Kind{9},
@@ -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 {
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), connectTimeout)
var err error
r, err = nostr.RelayConnect(ct, relay, sys.Pool.RelayOptions)
cancel()
if err != nil {
return err
} else {
return r.Publish(ctx, msg)
}
sys.Pool.Relays.Store(nm, r)
}
return r.Publish(ctx, msg)
},
},
},
@@ -474,10 +490,18 @@ write your forum post
return fmt.Errorf("failed to sign forum topic event: %w", err)
}
r, err := sys.Pool.EnsureRelay(relay)
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), connectTimeout)
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,10 +605,18 @@ write your forum post
return fmt.Errorf("failed to sign forum comment event: %w", err)
}
r, err := sys.Pool.EnsureRelay(relay)
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), connectTimeout)
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,10 +938,18 @@ func publishModerationEvent(ctx context.Context, c *cli.Command, kind nostr.Kind
stdout(evt.String())
r, err := sys.Pool.EnsureRelay(relay)
nm := nostr.NormalizeURL(relay)
r, ok := sys.Pool.Relays.Load(nm)
if !ok || r == nil || !r.IsConnected() {
ct, cancel := context.WithTimeout(context.Background(), connectTimeout)
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

@@ -48,6 +48,8 @@ var (
stdout = func(args ...any) { fmt.Fprintln(color.Output, args...) }
)
var connectTimeout = 2 * time.Second
func isPiped() bool {
stat, err := os.Stdin.Stat()
if err != nil {
@@ -268,7 +270,31 @@ 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 {
nm := nostr.NormalizeURL(url)
relay, ok := sys.Pool.Relays.Load(nm)
if !ok || relay == nil || !relay.IsConnected() {
connectCtx, cancel := context.WithTimeout(context.Background(), connectTimeout)
defer cancel()
var err error
if relay, err = nostr.RelayConnect(connectCtx, url, sys.Pool.RelayOptions); err != nil {
if colorizepreamble != nil {
colorizepreamble(colors.errorf)
}
logthis(clampError(err, len(url)+12))
return nil
}
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(color.YellowString)
@@ -289,11 +315,9 @@ func connectToSingleRelay(
} 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)
}
@@ -315,16 +339,6 @@ func connectToSingleRelay(
}
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))
return nil
}
}
func clearLines(lineCount int) {

15
main.go
View File

@@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/nip42"
@@ -42,6 +43,7 @@ var defaultKeyFlags = []cli.Flag{
Name: "prompt-sec",
Usage: "prompt the user to paste a hex or nsec with which to sign the event",
Category: CATEGORY_SIGNER,
Hidden: true,
},
&SecretKeyFlag{
Name: "connect-as",
@@ -50,6 +52,7 @@ var defaultKeyFlags = []cli.Flag{
Sources: cli.EnvVars("NOSTR_CLIENT_KEY"),
Value: defaultKey(),
DefaultText: "the default key (see `nak key default`)",
Hidden: true,
},
}
@@ -128,6 +131,7 @@ var app = &cli.Command{
}
return nil
},
Hidden: true,
},
&cli.BoolFlag{
Name: "verbose",
@@ -141,6 +145,17 @@ var app = &cli.Command{
}
return nil
},
Hidden: true,
},
&cli.DurationFlag{
Name: "connect-timeout",
Usage: "timeout for connecting to relays",
Value: connectTimeout,
Action: func(ctx context.Context, c *cli.Command, d time.Duration) error {
connectTimeout = d
return nil
},
Hidden: true,
},
},
defaultKeyFlags,

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)
}