Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@ ARCHIVE_REACTIONS="FALSE" # optional, reactions take up a lot of space and compu
MAX_AGE_DAYS=365

# comma delimited list of pubkeys who follow bots and ruin the WoT
IGNORE_FOLLOWS_LIST=""
IGNORE_FOLLOWS_LIST=""

# optional, comma separated list of seed relay WSS URLs (defaults to built-in list if not set)
# SEED_RELAYS="wss://nos.lol,wss://relay.damus.io,wss://relay.primal.net"

# optional, comma separated list of Nostr event kind numbers to archive and clean up
# defaults to: 30023,5,3,4,10000,7,10002,6,9734,9735,1 (standard social kinds)
# example for live streaming: ARCHIVE_KINDS="0,1,3,5,6,7,30023,30311,34235,9735"
# ARCHIVE_KINDS=""
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ MINIMUM_FOLLOWERS=3 #how many followers before they're allowed in the WoT
ARCHIVAL_SYNC="FALSE" # set to TRUE to archive every note from every person in the WoT (not recommended)
ARCHIVE_REACTIONS="FALSE" # set to TRUE to archive every reaction from every person in the WoT (not recommended)
IGNORE_FOLLOWS_LIST="" # comma separated list of pubkeys who follow too many bots and ruin the WoT
SEED_RELAYS="" # optional, comma separated WSS URLs for seed relays (uses built-in defaults if empty)
ARCHIVE_KINDS="" # optional, comma separated event kind numbers to archive (uses defaults if empty)
```

### 4. Build the project
Expand Down
159 changes: 89 additions & 70 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,38 @@ type Config struct {
MaxTrustNetwork int
MaxRelays int
MaxOneHopNetwork int
SeedRelays []string
ArchiveKinds []int
}

var defaultSeedRelays = []string{
"wss://nos.lol",
"wss://nostr.mom",
"wss://purplepag.es",
"wss://purplerelay.com",
"wss://relay.damus.io",
"wss://relay.nostr.band",
"wss://relay.snort.social",
"wss://relayable.org",
"wss://relay.primal.net",
"wss://relay.nostr.bg",
"wss://no.str.cr",
"wss://nostr21.com",
"wss://nostrue.com",
"wss://relay.siamstr.com",
}

var defaultArchiveKinds = []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
}

var pool *nostr.SimplePool
Expand Down Expand Up @@ -174,22 +206,7 @@ func main() {
return false, ""
})

seedRelays = []string{
"wss://nos.lol",
"wss://nostr.mom",
"wss://purplepag.es",
"wss://purplerelay.com",
"wss://relay.damus.io",
"wss://relay.nostr.band",
"wss://relay.snort.social",
"wss://relayable.org",
"wss://relay.primal.net",
"wss://relay.nostr.bg",
"wss://no.str.cr",
"wss://nostr21.com",
"wss://nostrue.com",
"wss://relay.siamstr.com",
}
seedRelays = config.SeedRelays

go refreshTrustNetwork(ctx, relay)
go monitorMemoryUsage() // Add memory monitoring
Expand Down Expand Up @@ -224,12 +241,16 @@ func main() {
}
})

log.Println("🎉 relay running on port :3334")
port := os.Getenv("PORT")
if port == "" {
port = "3334"
}
log.Printf("🎉 relay running on port :%s", port)
log.Println("🔍 debug endpoints available at:")
log.Println(" http://localhost:3334/debug/pprof/ (CPU/memory profiling)")
log.Println(" http://localhost:3334/debug/stats (application stats)")
log.Println(" http://localhost:3334/debug/goroutines (goroutine info)")
err := http.ListenAndServe(":3334", relay)
log.Printf(" http://localhost:%s/debug/pprof/ (CPU/memory profiling)", port)
log.Printf(" http://localhost:%s/debug/stats (application stats)", port)
log.Printf(" http://localhost:%s/debug/goroutines (goroutine info)", port)
err := http.ListenAndServe(":"+port, relay)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -292,6 +313,45 @@ func LoadConfig() Config {
maxRelays, _ := strconv.Atoi(os.Getenv("MAX_RELAYS"))
maxOneHopNetwork, _ := strconv.Atoi(os.Getenv("MAX_ONE_HOP_NETWORK"))

// Parse configurable seed relays, fall back to defaults
parsedSeedRelays := defaultSeedRelays
if sr := os.Getenv("SEED_RELAYS"); sr != "" {
parsedSeedRelays = splitAndTrim(sr)
log.Printf("🌱 using %d custom seed relays", len(parsedSeedRelays))
} else {
log.Printf("🌱 using %d default seed relays", len(parsedSeedRelays))
}

// Parse configurable archive kinds, fall back to defaults
archiveReactions := getEnv("ARCHIVE_REACTIONS") == "TRUE"
parsedArchiveKinds := make([]int, len(defaultArchiveKinds))
copy(parsedArchiveKinds, defaultArchiveKinds)
if ak := os.Getenv("ARCHIVE_KINDS"); ak != "" {
kindStrs := splitAndTrim(ak)
parsedArchiveKinds = []int{}
for _, ks := range kindStrs {
if k, err := strconv.Atoi(ks); err == nil {
parsedArchiveKinds = append(parsedArchiveKinds, k)
} else {
log.Printf("⚠️ ignoring invalid ARCHIVE_KINDS value: %s", ks)
}
}
log.Printf("📦 using %d custom archive kinds", len(parsedArchiveKinds))
}
// Add reaction kind if ARCHIVE_REACTIONS is enabled and not already present
if archiveReactions {
hasReaction := false
for _, k := range parsedArchiveKinds {
if k == nostr.KindReaction {
hasReaction = true
break
}
}
if !hasReaction {
parsedArchiveKinds = append(parsedArchiveKinds, nostr.KindReaction)
}
}

config := Config{
RelayName: getEnv("RELAY_NAME"),
RelayPubkey: getEnv("RELAY_PUBKEY"),
Expand All @@ -306,11 +366,13 @@ func LoadConfig() Config {
MinimumFollowers: minimumFollowers,
ArchivalSync: getEnv("ARCHIVAL_SYNC") == "TRUE",
MaxAgeDays: maxAgeDays,
ArchiveReactions: getEnv("ARCHIVE_REACTIONS") == "TRUE",
ArchiveReactions: archiveReactions,
IgnoredPubkeys: ignoredPubkeys,
MaxTrustNetwork: maxTrustNetwork,
MaxRelays: maxRelays,
MaxOneHopNetwork: maxOneHopNetwork,
SeedRelays: parsedSeedRelays,
ArchiveKinds: parsedArchiveKinds,
}

return config
Expand Down Expand Up @@ -584,42 +646,11 @@ func archiveTrustedNotes(ctx context.Context, relay *khatru.Relay) {
if config.ArchivalSync {
go refreshProfiles(ctx)

var filters []nostr.Filter
since := nostr.Now()
if config.ArchiveReactions {
filters = []nostr.Filter{{
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindReaction,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
Since: &since,
}}
} else {
filters = []nostr.Filter{{
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
Since: &since,
}}
}
filters := []nostr.Filter{{
Kinds: config.ArchiveKinds,
Since: &since,
}}

log.Println("📦 archiving trusted notes...")

Expand Down Expand Up @@ -707,19 +738,7 @@ func deleteOldNotes(relay *khatru.Relay) error {

filter := nostr.Filter{
Until: &oldAge,
Kinds: []int{
nostr.KindArticle,
nostr.KindDeletion,
nostr.KindFollowList,
nostr.KindEncryptedDirectMessage,
nostr.KindMuteList,
nostr.KindReaction,
nostr.KindRelayListMetadata,
nostr.KindRepost,
nostr.KindZapRequest,
nostr.KindZap,
nostr.KindTextNote,
},
Kinds: config.ArchiveKinds,
Limit: 1000, // Process in batches to avoid memory issues
}

Expand Down
Loading