initial public relay build repo
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
// Command nostermd is a minimal NIP-29 managed-group relay built on khatru,
|
||||
// plus the Nosterm capability handshake (a `features` array in its NIP-11 doc).
|
||||
//
|
||||
// It is intentionally small: it enforces group membership for chat writes,
|
||||
// auto-creates open channels on first join, and advertises itself as a
|
||||
// "nostermd" so a Nosterm client can feature-gate its UI. The relay is
|
||||
// assembled from focused internal packages (group, federation, retention,
|
||||
// relayinfo); this file is the composition root that wires them to env config
|
||||
// and the network.
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"fiatjaf.com/nostr/eventstore/boltdb"
|
||||
|
||||
"github.com/nosterm/relay/internal/federation"
|
||||
"github.com/nosterm/relay/internal/retention"
|
||||
)
|
||||
|
||||
// defaultMOTD is the built-in message-of-the-day: a "nerdworks.io" ascii banner
|
||||
// (figlet, standard font) the client shows when RELAY_MOTD is unset.
|
||||
const defaultMOTD = " _ _ _\n" +
|
||||
" _ __ ___ _ __ __| |_ _____ _ __| | _____ (_) ___\n" +
|
||||
"| '_ \\ / _ \\ '__/ _` \\ \\ /\\ / / _ \\| '__| |/ / __| | |/ _ \\\n" +
|
||||
"| | | | __/ | | (_| |\\ V V / (_) | | | <\\__ \\_| | (_) |\n" +
|
||||
"|_| |_|\\___|_| \\__,_| \\_/\\_/ \\___/|_| |_|\\_\\___(_)_|\\___/\n"
|
||||
|
||||
func main() {
|
||||
addr := envOr("RELAY_ADDR", ":3334")
|
||||
dataDir := envOr("RELAY_DATA_DIR", "./data")
|
||||
|
||||
// Embedded, pure-Go storage (no cgo → clean static Docker builds).
|
||||
if err := os.MkdirAll(dataDir, 0o755); err != nil {
|
||||
log.Fatalf("cannot create data dir: %v", err)
|
||||
}
|
||||
|
||||
// Relay identity: signs the 39000-series group metadata/roster events. A
|
||||
// stable key is required so those signatures survive restarts (see below).
|
||||
sk := loadOrGenerateKey(dataDir)
|
||||
|
||||
store := &boltdb.BoltBackend{Path: filepath.Join(dataDir, "events.bolt")}
|
||||
if err := store.Init(); err != nil {
|
||||
log.Fatalf("cannot open eventstore: %v", err)
|
||||
}
|
||||
|
||||
// Parse optional federation config up front so warnings surface at boot.
|
||||
fedCfg, fedWarnings := federation.ParseConfig(os.Getenv("RELAY_FEDERATION_PEERS"))
|
||||
for _, w := range fedWarnings {
|
||||
log.Printf("federation config: %s", w)
|
||||
}
|
||||
|
||||
app := buildRelay(relayConfig{
|
||||
secretKey: sk,
|
||||
store: store,
|
||||
name: envOr("RELAY_NAME", "Nosterm Home Relay"),
|
||||
description: envOr("RELAY_DESCRIPTION", "A Nosterm NIP-29 managed-group relay."),
|
||||
// NIP-11 contact: a NIP-05-style identifier / address for the relay operator.
|
||||
contact: envOr("RELAY_CONTACT", "relay@nosterm.com"),
|
||||
// Optional message-of-the-day shown in the client's relay server window;
|
||||
// defaults to the nerdworks.io banner when unset.
|
||||
motd: envOr("RELAY_MOTD", defaultMOTD),
|
||||
fedCfg: fedCfg,
|
||||
})
|
||||
|
||||
// Reconstruct membership/metadata from persisted events so groups survive
|
||||
// restarts (without this, every restart silently drops all group state).
|
||||
if replayed := app.groups.Rebuild(store); replayed > 0 {
|
||||
log.Printf("replayed %d group management event(s) from storage", replayed)
|
||||
}
|
||||
|
||||
// Retention: prune old chat messages so the store doesn't grow forever.
|
||||
stopRetention := retention.Start(store, retention.Config{
|
||||
MaxAge: time.Duration(envIntOr("RELAY_RETENTION_DAYS", 0)) * 24 * time.Hour,
|
||||
MaxMessages: envIntOr("RELAY_RETENTION_MAX_MESSAGES", 0),
|
||||
Interval: time.Duration(envIntOr("RELAY_RETENTION_INTERVAL_MINUTES", 60)) * time.Minute,
|
||||
})
|
||||
defer stopRetention()
|
||||
|
||||
// Start federation last, once the relay pipeline is fully wired.
|
||||
if app.federator != nil {
|
||||
app.federator.Start()
|
||||
defer app.federator.Stop()
|
||||
}
|
||||
|
||||
log.Printf("nostermd pubkey: %s", app.pubKey.Hex())
|
||||
log.Printf("listening on %s (%s; %s)", addr, app.groups.Summary(), fedCfg.Summary())
|
||||
if err := http.ListenAndServe(addr, app.handler); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user