config.go raw

   1  package main
   2  
   3  import (
   4  	"os"
   5  	"path/filepath"
   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  
  14  // Config holds the ACL server configuration.
  15  type Config struct {
  16  	// Listen is the gRPC server listen address
  17  	Listen string `env:"ORLY_ACL_LISTEN" default:"127.0.0.1:50052" usage:"gRPC server listen address"`
  18  
  19  	// ACLMode is the active ACL mode (none, follows, managed, curating)
  20  	ACLMode string `env:"ORLY_ACL_MODE" default:"none" usage:"ACL mode: none, follows, managed, curating"`
  21  
  22  	// LogLevel is the logging level
  23  	LogLevel string `env:"ORLY_ACL_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"`
  24  
  25  	// Database configuration
  26  	DBType       string `env:"ORLY_ACL_DB_TYPE" default:"badger" usage:"database type: badger or grpc"`
  27  	GRPCDBServer string `env:"ORLY_ACL_GRPC_DB_SERVER" usage:"gRPC database server address (when DB_TYPE=grpc)"`
  28  	DataDir      string `env:"ORLY_DATA_DIR" usage:"database data directory (when DB_TYPE=badger)"`
  29  
  30  	// Badger configuration (when DB_TYPE=badger)
  31  	BlockCacheMB       int           `env:"ORLY_DB_BLOCK_CACHE_MB" default:"1024" usage:"block cache size in MB"`
  32  	IndexCacheMB       int           `env:"ORLY_DB_INDEX_CACHE_MB" default:"512" usage:"index cache size in MB"`
  33  	ZSTDLevel          int           `env:"ORLY_DB_ZSTD_LEVEL" default:"3" usage:"ZSTD compression level"`
  34  	QueryCacheSizeMB   int           `env:"ORLY_DB_QUERY_CACHE_SIZE_MB" default:"256" usage:"query cache size in MB"`
  35  	QueryCacheMaxAge   time.Duration `env:"ORLY_DB_QUERY_CACHE_MAX_AGE" default:"5m" usage:"query cache max age"`
  36  	QueryCacheDisabled bool          `env:"ORLY_DB_QUERY_CACHE_DISABLED" default:"false" usage:"disable query cache"`
  37  	SerialCachePubkeys int           `env:"ORLY_SERIAL_CACHE_PUBKEYS" default:"100000" usage:"serial cache pubkeys capacity"`
  38  	SerialCacheEventIds int          `env:"ORLY_SERIAL_CACHE_EVENT_IDS" default:"500000" usage:"serial cache event IDs capacity"`
  39  
  40  	// ACL configuration
  41  	Owners          string        `env:"ORLY_OWNERS" usage:"comma-separated list of owner npubs"`
  42  	Admins          string        `env:"ORLY_ADMINS" usage:"comma-separated list of admin npubs"`
  43  	BootstrapRelays string        `env:"ORLY_BOOTSTRAP_RELAYS" usage:"comma-separated list of bootstrap relays"`
  44  	RelayAddresses  string        `env:"ORLY_RELAY_ADDRESSES" usage:"comma-separated list of relay addresses (self)"`
  45  
  46  	// Follows ACL configuration
  47  	FollowListFrequency   time.Duration `env:"ORLY_FOLLOW_LIST_FREQUENCY" default:"1h" usage:"follow list sync frequency"`
  48  	FollowsThrottleEnabled bool         `env:"ORLY_FOLLOWS_THROTTLE_ENABLED" default:"false" usage:"enable progressive throttle for non-followed users"`
  49  	FollowsThrottlePerEvent time.Duration `env:"ORLY_FOLLOWS_THROTTLE_PER_EVENT" default:"25ms" usage:"throttle delay increment per event"`
  50  	FollowsThrottleMaxDelay time.Duration `env:"ORLY_FOLLOWS_THROTTLE_MAX_DELAY" default:"60s" usage:"maximum throttle delay"`
  51  }
  52  
  53  // loadConfig loads configuration from environment variables.
  54  func loadConfig() *Config {
  55  	cfg := &Config{}
  56  	if err := env.Load(cfg, nil); chk.E(err) {
  57  		log.E.F("failed to load config: %v", err)
  58  		os.Exit(1)
  59  	}
  60  
  61  	// Set default data directory if not specified
  62  	if cfg.DataDir == "" {
  63  		home, err := os.UserHomeDir()
  64  		if chk.E(err) {
  65  			log.E.F("failed to get home directory: %v", err)
  66  			os.Exit(1)
  67  		}
  68  		cfg.DataDir = filepath.Join(home, ".local", "share", "ORLY")
  69  	}
  70  
  71  	// Ensure data directory exists (for badger mode)
  72  	if cfg.DBType == "badger" {
  73  		if err := os.MkdirAll(cfg.DataDir, 0700); chk.E(err) {
  74  			log.E.F("failed to create data directory %s: %v", cfg.DataDir, err)
  75  			os.Exit(1)
  76  		}
  77  	}
  78  
  79  	return cfg
  80  }
  81  
  82  // GetOwners returns the list of owner pubkeys
  83  func (c *Config) GetOwners() []string {
  84  	if c.Owners == "" {
  85  		return nil
  86  	}
  87  	return strings.Split(c.Owners, ",")
  88  }
  89  
  90  // GetAdmins returns the list of admin pubkeys
  91  func (c *Config) GetAdmins() []string {
  92  	if c.Admins == "" {
  93  		return nil
  94  	}
  95  	return strings.Split(c.Admins, ",")
  96  }
  97  
  98  // GetBootstrapRelays returns the list of bootstrap relays
  99  func (c *Config) GetBootstrapRelays() []string {
 100  	if c.BootstrapRelays == "" {
 101  		return nil
 102  	}
 103  	return strings.Split(c.BootstrapRelays, ",")
 104  }
 105  
 106  // GetRelayAddresses returns the list of relay addresses (self)
 107  func (c *Config) GetRelayAddresses() []string {
 108  	if c.RelayAddresses == "" {
 109  		return nil
 110  	}
 111  	return strings.Split(c.RelayAddresses, ",")
 112  }
 113