diff --git a/go.mod b/go.mod index 4f3ab9d..5c27bbe 100644 --- a/go.mod +++ b/go.mod @@ -269,4 +269,4 @@ require ( ) retract v1.0.3 -replace git.mleku.dev/mleku/nostr => ./docker-build-context/nostr +replace git.mleku.dev/mleku/nostr => ../nostr diff --git a/pkg/spider/spider.go b/pkg/spider/spider.go index e4e6696..781f0ad 100644 --- a/pkg/spider/spider.go +++ b/pkg/spider/spider.go @@ -55,10 +55,10 @@ type Spider struct { mode string // Configuration - adminRelays []string - followList [][]byte + adminRelays []string + followList [][]byte relayIdentityPubkey string // Our relay's identity pubkey (hex) - selfURLs map[string]bool // URLs discovered to be ourselves (for fast lookups) + selfURLs map[string]bool // URLs discovered to be ourselves (for fast lookups) // State management mu sync.RWMutex @@ -235,6 +235,10 @@ func (s *Spider) mainLoop() { log.I.F("spider: main loop started, checking every %v", MainLoopInterval) + // Do an immediate check on startup + log.I.F("spider: performing initial connection check") + s.updateConnections() + for { select { case <-s.ctx.Done(): @@ -243,7 +247,7 @@ func (s *Spider) mainLoop() { log.I.F("spider: follow list updated, refreshing connections") s.updateConnections() case <-ticker.C: - log.D.F("spider: periodic check triggered") + log.I.F("spider: periodic check triggered") s.updateConnections() } } @@ -251,44 +255,105 @@ func (s *Spider) mainLoop() { // updateConnections updates relay connections based on current admin relays and follow lists func (s *Spider) updateConnections() { - s.mu.Lock() - defer s.mu.Unlock() + s.mu.RLock() + running := s.running + s.mu.RUnlock() - if !s.running { + if !running { return } // Get current admin relays and follow list - adminRelays := s.getAdminRelays() - followList := s.getFollowList() + if s.getAdminRelays == nil { + log.W.F("spider: getAdminRelays callback is nil") + return + } + if s.getFollowList == nil { + log.W.F("spider: getFollowList callback is nil") + return + } + + // Call callbacks with panic recovery + var adminRelays []string + var followList [][]byte + func() { + defer func() { + if r := recover(); r != nil { + log.E.F("spider: panic in getAdminRelays callback: %v", r) + adminRelays = nil + } + }() + adminRelays = s.getAdminRelays() + }() + func() { + defer func() { + if r := recover(); r != nil { + log.E.F("spider: panic in getFollowList callback: %v", r) + followList = nil + } + }() + followList = s.getFollowList() + }() + + log.I.F("spider: updateConnections - admin relays: %d, follow list: %d", len(adminRelays), len(followList)) + if len(adminRelays) > 0 { + log.I.F("spider: admin relays: %v", adminRelays) + } else { + log.I.F("spider: admin relays callback returned empty/nil - checking bootstrap relay configuration") + } + if len(followList) > 0 { + log.D.F("spider: follow list has %d pubkeys", len(followList)) + } else { + log.I.F("spider: follow list callback returned empty/nil - check if admin follow lists have been fetched") + } if len(adminRelays) == 0 || len(followList) == 0 { - log.D.F("spider: no admin relays (%d) or follow list (%d) available", + log.I.F("spider: no admin relays (%d) or follow list (%d) available - cannot create connections", len(adminRelays), len(followList)) + if len(adminRelays) == 0 { + log.I.F("spider: admin relays callback returned empty list - check if bootstrap relays are configured") + } + if len(followList) == 0 { + log.I.F("spider: follow list callback returned empty list - check if admin follow lists have been fetched") + } return } // Update connections for current admin relays (filtering out self) + // Note: We release the mutex before the loop because isSelfRelay() needs to acquire it + log.I.F("spider: processing %d admin relays (will filter out self-relays)", len(adminRelays)) currentRelays := make(map[string]bool) - for _, url := range adminRelays { + for i, url := range adminRelays { + log.I.F("spider: checking relay %d/%d: %s", i+1, len(adminRelays), url) // Check if this relay URL is ourselves - if s.isSelfRelay(url) { - log.D.F("spider: skipping self-relay: %s", url) + isSelf := s.isSelfRelay(url) + log.D.F("spider: isSelfRelay(%s) = %v", url, isSelf) + if isSelf { + log.I.F("spider: skipping self-relay: %s", url) continue } currentRelays[url] = true - if conn, exists := s.connections[url]; exists { + // Acquire lock to check and modify connections + s.mu.Lock() + conn, exists := s.connections[url] + s.mu.Unlock() + + if exists { // Update existing connection + log.I.F("spider: updating existing connection to %s", url) conn.updateSubscriptions(followList) } else { // Create new connection + log.I.F("spider: creating new connection to %s", url) s.createConnection(url, followList) } } + log.I.F("spider: processed %d relays, created/updated %d connections", len(adminRelays), len(currentRelays)) // Remove connections for relays no longer in admin list + s.mu.Lock() for url, conn := range s.connections { if !currentRelays[url] { log.I.F("spider: removing connection to %s (no longer in admin relays)", url) @@ -296,6 +361,7 @@ func (s *Spider) updateConnections() { delete(s.connections, url) } } + s.mu.Unlock() } // createConnection creates a new relay connection @@ -312,7 +378,10 @@ func (s *Spider) createConnection(url string, followList [][]byte) { reconnectDelay: ReconnectDelay, } + // Acquire lock to add connection + s.mu.Lock() s.connections[url] = conn + s.mu.Unlock() // Start connection in goroutine go conn.manage(followList)