// internal/api/global_relay_service.go package api import ( "fmt" "git.sovbit.dev/Enki/nostr-poster/internal/db" "git.sovbit.dev/Enki/nostr-poster/internal/models" "go.uber.org/zap" ) // GlobalRelayService provides functionality for managing global relays type GlobalRelayService struct { db *db.DB logger *zap.Logger } // NewGlobalRelayService creates a new GlobalRelayService func NewGlobalRelayService(db *db.DB, logger *zap.Logger) *GlobalRelayService { return &GlobalRelayService{ db: db, logger: logger, } } // GetUserGlobalRelays gets all global relays for a user func (s *GlobalRelayService) GetUserGlobalRelays(ownerPubkey string) ([]*models.Relay, error) { query := ` SELECT id, url, read, write, owner_pubkey FROM global_relays WHERE owner_pubkey = ? ORDER BY id ` var relays []*models.Relay err := s.db.Select(&relays, query, ownerPubkey) if err != nil { return nil, fmt.Errorf("failed to get global relays: %w", err) } return relays, nil } // AddGlobalRelay adds a global relay for a user func (s *GlobalRelayService) AddGlobalRelay(relay *models.Relay) error { query := ` INSERT INTO global_relays (url, read, write, owner_pubkey) VALUES (?, ?, ?, ?) ` _, err := s.db.Exec(query, relay.URL, relay.Read, relay.Write, relay.OwnerPubkey) if err != nil { return fmt.Errorf("failed to add global relay: %w", err) } return nil } // UpdateGlobalRelay updates a global relay func (s *GlobalRelayService) UpdateGlobalRelay(relay *models.Relay) error { query := ` UPDATE global_relays SET url = ?, read = ?, write = ? WHERE id = ? AND owner_pubkey = ? ` _, err := s.db.Exec(query, relay.URL, relay.Read, relay.Write, relay.ID, relay.OwnerPubkey) if err != nil { return fmt.Errorf("failed to update global relay: %w", err) } return nil } // DeleteGlobalRelay deletes a global relay func (s *GlobalRelayService) DeleteGlobalRelay(relayID int64, ownerPubkey string) error { query := ` DELETE FROM global_relays WHERE id = ? AND owner_pubkey = ? ` _, err := s.db.Exec(query, relayID, ownerPubkey) if err != nil { return fmt.Errorf("failed to delete global relay: %w", err) } return nil } // GetAllRelaysForPosting gets a combined list of bot-specific and global relays for posting func (s *GlobalRelayService) GetAllRelaysForPosting(botID int64, ownerPubkey string) ([]*models.Relay, error) { // First, get bot-specific relays query1 := ` SELECT id, bot_id, url, read, write FROM relays WHERE bot_id = ? ` var botRelays []*models.Relay err := s.db.Select(&botRelays, query1, botID) if err != nil { return nil, fmt.Errorf("failed to get bot relays: %w", err) } // Then, get global relays query2 := ` SELECT id, url, read, write, owner_pubkey FROM global_relays WHERE owner_pubkey = ? ` var globalRelays []*models.Relay err = s.db.Select(&globalRelays, query2, ownerPubkey) if err != nil { return nil, fmt.Errorf("failed to get global relays: %w", err) } // Combine both sets, avoiding duplicates // We'll consider a relay a duplicate if it has the same URL urlMap := make(map[string]bool) var combined []*models.Relay // Add bot relays first (they take precedence) for _, relay := range botRelays { urlMap[relay.URL] = true combined = append(combined, relay) } // Add global relays if they don't conflict for _, relay := range globalRelays { if !urlMap[relay.URL] { // Set the bot ID for consistency relay.BotID = botID combined = append(combined, relay) } } return combined, nil }