Files
crawler_v2/pkg/config/config.go
2025-06-11 16:26:22 +02:00

206 lines
5.1 KiB
Go

// The config package loads and validates the variables in the enviroment into a [Config]
package config
import (
"fmt"
"os"
"strconv"
"strings"
"time"
"github/pippellia-btc/crawler/pkg/pipe"
_ "github.com/joho/godotenv/autoload" // autoloading .env
"github.com/nbd-wtf/go-nostr"
)
type SystemConfig struct {
RedisAddress string
SQLiteURL string
EventsCapacity int
PubkeysCapacity int
InitPubkeys []string // only used during initialization
}
func NewSystemConfig() SystemConfig {
return SystemConfig{
RedisAddress: "localhost:6379",
SQLiteURL: "events.sqlite",
EventsCapacity: 1000,
PubkeysCapacity: 1000,
}
}
func (c SystemConfig) Print() {
fmt.Println("System:")
fmt.Printf(" RedisAddress: %s\n", c.RedisAddress)
fmt.Printf(" SQLiteURL: %s\n", c.SQLiteURL)
fmt.Printf(" EventsCapacity: %d\n", c.EventsCapacity)
fmt.Printf(" PubkeysCapacity: %d\n", c.PubkeysCapacity)
fmt.Printf(" InitPubkeys: %v\n", c.InitPubkeys)
}
// The configuration parameters for the system and the main processes
type Config struct {
SystemConfig
Firehose pipe.FirehoseConfig
Fetcher pipe.FetcherConfig
Arbiter pipe.ArbiterConfig
Engine pipe.EngineConfig
}
// New returns a config with default parameters
func New() *Config {
return &Config{
SystemConfig: NewSystemConfig(),
Firehose: pipe.NewFirehoseConfig(),
Fetcher: pipe.NewFetcherConfig(),
Arbiter: pipe.NewArbiterConfig(),
Engine: pipe.NewEngineConfig(),
}
}
func (c *Config) Print() {
c.SystemConfig.Print()
c.Firehose.Print()
c.Fetcher.Print()
c.Arbiter.Print()
c.Engine.Print()
}
// Load reads the enviroment variables and parses them into a [Config] struct
func Load() (*Config, error) {
var config = New()
var err error
for _, item := range os.Environ() {
keyVal := strings.SplitN(item, "=", 2)
key, val := keyVal[0], keyVal[1]
switch key {
case "REDIS_ADDRESS":
config.RedisAddress = val
case "SQLITE_URL":
config.SQLiteURL = val
case "EVENTS_CAPACITY":
config.EventsCapacity, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "PUBKEYS_CAPACITY":
config.PubkeysCapacity, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "INIT_PUBKEYS":
pubkeys := strings.Split(val, ",")
for _, pk := range pubkeys {
if !nostr.IsValidPublicKey(pk) {
return nil, fmt.Errorf("pubkey %s is not valid", pk)
}
}
config.InitPubkeys = pubkeys
case "FIREHOSE_OFFSET":
offset, err := strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
config.Fetcher.Interval = time.Duration(offset) * time.Second
case "RELAYS":
relays := strings.Split(val, ",")
if len(relays) == 0 {
return nil, fmt.Errorf("relay list is empty")
}
for _, relay := range relays {
if !nostr.IsValidRelayURL(relay) {
return nil, fmt.Errorf("relay \"%s\" is not a valid url", relay)
}
}
config.Firehose.Relays = relays
config.Fetcher.Relays = relays
case "FETCHER_BATCH":
config.Fetcher.Batch, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "FETCHER_INTERVAL":
interval, err := strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
config.Fetcher.Interval = time.Duration(interval) * time.Second
case "ARBITER_ACTIVATION":
config.Arbiter.Activation, err = strconv.ParseFloat(val, 64)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "ARBITER_PROMOTION":
config.Arbiter.Promotion, err = strconv.ParseFloat(val, 64)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "ARBITER_DEMOTION":
config.Arbiter.Demotion, err = strconv.ParseFloat(val, 64)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "ARBITER_PING_WAIT":
wait, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
config.Arbiter.PingWait = time.Duration(wait) * time.Second
case "ARBITER_PROMOTION_WAIT":
wait, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
config.Arbiter.PromotionWait = time.Duration(wait) * time.Second
case "ENGINE_PRINT_EVERY":
config.Engine.PrintEvery, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "ENGINE_BUILDER_CAPACITY":
config.Engine.BuilderCapacity, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "ENGINE_CACHE_CAPACITY":
config.Engine.CacheCapacity, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
case "ENGINE_ARCHIVERS":
config.Engine.Archivers, err = strconv.Atoi(val)
if err != nil {
return nil, fmt.Errorf("error parsing %v: %v", keyVal, err)
}
}
}
return config, nil
}