config.go raw
1 package main
2
3 import (
4 "encoding/json"
5 "os"
6 "strings"
7 "time"
8
9 "go-simpler.org/env"
10 "next.orly.dev/pkg/lol/chk"
11 "next.orly.dev/pkg/lol/log"
12
13 "next.orly.dev/pkg/nostr/encoders/filter"
14 )
15
16 // Config holds the negentropy sync service configuration.
17 type Config struct {
18 // Listen is the gRPC server listen address
19 Listen string `env:"ORLY_SYNC_NEGENTROPY_LISTEN" default:"127.0.0.1:50064" usage:"gRPC server listen address"`
20
21 // LogLevel is the logging level
22 LogLevel string `env:"ORLY_SYNC_NEGENTROPY_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"`
23
24 // Database configuration
25 DBType string `env:"ORLY_SYNC_NEGENTROPY_DB_TYPE" default:"grpc" usage:"database type: grpc or badger"`
26 GRPCDBServer string `env:"ORLY_SYNC_NEGENTROPY_DB_SERVER" default:"127.0.0.1:50051" usage:"gRPC database server address"`
27 DataDir string `env:"ORLY_DATA_DIR" usage:"database data directory (for badger mode)"`
28
29 // Negentropy configuration
30 PeersRaw string `env:"ORLY_SYNC_NEGENTROPY_PEERS" usage:"comma-separated peer relay WebSocket URLs"`
31 SyncInterval time.Duration `env:"ORLY_SYNC_NEGENTROPY_INTERVAL" default:"60s" usage:"background sync interval"`
32 FrameSize int `env:"ORLY_SYNC_NEGENTROPY_FRAME_SIZE" default:"4096" usage:"negentropy frame size"`
33 IDSize int `env:"ORLY_SYNC_NEGENTROPY_ID_SIZE" default:"16" usage:"negentropy ID truncation size"`
34
35 // Filter configuration - JSON encoded nostr filter
36 // Example: {"kinds":[1,6,7],"authors":["abc123..."]}
37 FilterJSON string `env:"ORLY_SYNC_NEGENTROPY_FILTER" usage:"JSON-encoded nostr filter for selective sync"`
38
39 // Client session configuration
40 ClientSessionTimeout time.Duration `env:"ORLY_SYNC_NEGENTROPY_SESSION_TIMEOUT" default:"5m" usage:"client session timeout"`
41
42 // Parsed peers
43 Peers []string
44
45 // Parsed filter
46 Filter *filter.F
47 }
48
49 // loadConfig loads configuration from environment variables.
50 func loadConfig() *Config {
51 cfg := &Config{}
52 if err := env.Load(cfg, nil); chk.E(err) {
53 log.E.F("failed to load config: %v", err)
54 os.Exit(1)
55 }
56
57 // Parse peers from comma-separated string
58 if cfg.PeersRaw != "" {
59 cfg.Peers = strings.Split(cfg.PeersRaw, ",")
60 for i, p := range cfg.Peers {
61 cfg.Peers[i] = strings.TrimSpace(p)
62 }
63 }
64
65 // Parse filter from JSON if provided
66 if cfg.FilterJSON != "" {
67 cfg.Filter = &filter.F{}
68 if err := json.Unmarshal([]byte(cfg.FilterJSON), cfg.Filter); err != nil {
69 log.E.F("failed to parse filter JSON: %v", err)
70 os.Exit(1)
71 }
72 log.I.F("using sync filter: %s", cfg.FilterJSON)
73 }
74
75 return cfg
76 }
77