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