nip46: switch_relays on the client side.

This commit is contained in:
fiatjaf
2026-01-20 20:45:07 -03:00
parent 10318a3443
commit de4eff64d1
2 changed files with 38 additions and 18 deletions

View File

@@ -16,11 +16,12 @@ import (
) )
type BunkerClient struct { type BunkerClient struct {
Relays []string
serial atomic.Uint64 serial atomic.Uint64
clientSecretKey [32]byte clientSecretKey [32]byte
pool *nostr.Pool pool *nostr.Pool
target nostr.PubKey target nostr.PubKey
relays []string
conversationKey [32]byte // nip44 conversationKey [32]byte // nip44
listeners *xsync.MapOf[string, chan Response] listeners *xsync.MapOf[string, chan Response]
idPrefix string idPrefix string
@@ -116,23 +117,27 @@ func NewBunker(
clientPublicKey := nostr.GetPublicKey(clientSecretKey) clientPublicKey := nostr.GetPublicKey(clientSecretKey)
conversationKey, _ := nip44.GenerateConversationKey(targetPublicKey, clientSecretKey) conversationKey, _ := nip44.GenerateConversationKey(targetPublicKey, clientSecretKey)
now := nostr.Now()
bunker := &BunkerClient{ bunker := &BunkerClient{
pool: pool, pool: pool,
clientSecretKey: clientSecretKey, clientSecretKey: clientSecretKey,
target: targetPublicKey, target: targetPublicKey,
relays: relays, Relays: relays,
conversationKey: conversationKey, conversationKey: conversationKey,
listeners: xsync.NewMapOf[string, chan Response](), listeners: xsync.NewMapOf[string, chan Response](),
onAuth: onAuth, onAuth: onAuth,
idPrefix: "nl-" + strconv.Itoa(rand.Intn(65536)), idPrefix: "nl-" + strconv.Itoa(rand.Intn(65536)),
} }
cancellableCtx, cancel := context.WithCancel(ctx)
_ = cancel
go func() { go func() {
events := pool.SubscribeMany(ctx, relays, nostr.Filter{ events := pool.SubscribeMany(cancellableCtx, relays, nostr.Filter{
Tags: nostr.TagMap{"p": []string{clientPublicKey.Hex()}}, Tags: nostr.TagMap{"p": []string{clientPublicKey.Hex()}},
Kinds: []nostr.Kind{nostr.KindNostrConnect}, Kinds: []nostr.Kind{nostr.KindNostrConnect},
Since: nostr.Now(), Since: now,
LimitZero: true, LimitZero: true,
}, nostr.SubscriptionOptions{ }, nostr.SubscriptionOptions{
Label: "bunker46client", Label: "bunker46client",
@@ -167,6 +172,14 @@ func NewBunker(
} }
}() }()
// attempt switch_relays once every 10 times
if now%10 == 0 {
if newRelays, _ := bunker.SwitchRelays(ctx); newRelays != nil {
cancel()
bunker = NewBunker(ctx, clientSecretKey, targetPublicKey, newRelays, pool, func(string) {})
}
}
return bunker return bunker
} }
@@ -178,6 +191,15 @@ func (bunker *BunkerClient) Ping(ctx context.Context) error {
return nil return nil
} }
func (bunker *BunkerClient) SwitchRelays(ctx context.Context) ([]string, error) {
var res []string
_, err := bunker.RPC(ctx, "switch_relays", res)
if err != nil {
return nil, err
}
return res, nil
}
func (bunker *BunkerClient) GetPublicKey(ctx context.Context) (nostr.PubKey, error) { func (bunker *BunkerClient) GetPublicKey(ctx context.Context) (nostr.PubKey, error) {
if bunker.getPublicKeyResponse != nostr.ZeroPK { if bunker.getPublicKeyResponse != nostr.ZeroPK {
return bunker.getPublicKeyResponse, nil return bunker.getPublicKeyResponse, nil
@@ -283,7 +305,7 @@ func (bunker *BunkerClient) RPC(ctx context.Context, method string, params []str
relayConnectionWorked := make(chan struct{}) relayConnectionWorked := make(chan struct{})
bunkerConnectionWorked := make(chan struct{}) bunkerConnectionWorked := make(chan struct{})
for _, url := range bunker.relays { for _, url := range bunker.Relays {
go func(url string) { go func(url string) {
relay, err := bunker.pool.EnsureRelay(url) relay, err := bunker.pool.EnsureRelay(url)
if err == nil { if err == nil {

View File

@@ -5,14 +5,11 @@ import (
"crypto/rand" "crypto/rand"
"errors" "errors"
"fmt" "fmt"
mrand "math/rand"
"net/url" "net/url"
"strconv"
"strings" "strings"
"fiatjaf.com/nostr" "fiatjaf.com/nostr"
"fiatjaf.com/nostr/nip44" "fiatjaf.com/nostr/nip44"
"github.com/puzpuzpuz/xsync/v3"
) )
var NoConnectionReceived = errors.New("relay connections ended without a bunker connection established") var NoConnectionReceived = errors.New("relay connections ended without a bunker connection established")
@@ -112,16 +109,17 @@ func NewBunkerFromNostrConnect(
if req.Result != "" { if req.Result != "" {
if req.Result == secret { if req.Result == secret {
// secret validation passed - connection established // secret validation passed - connection established
return &BunkerClient{ cancellableCtx, cancel := context.WithCancel(ctx)
pool: pool, _ = cancel
clientSecretKey: clientSecretKey, bunker := NewBunker(cancellableCtx, clientSecretKey, targetPublicKey, relayURLs, pool, func(string) {})
target: targetPublicKey,
relays: relayURLs, // attempt switch_relays
conversationKey: conversationKey, if newRelays, _ := bunker.SwitchRelays(ctx); newRelays != nil {
listeners: xsync.NewMapOf[string, chan Response](), cancel()
onAuth: func(string) {}, bunker = NewBunker(ctx, clientSecretKey, targetPublicKey, newRelays, pool, func(string) {})
idPrefix: "nl-" + strconv.Itoa(mrand.Intn(65536)), }
}, nil
return bunker, nil
} }
} }
} }