package main import ( "encoding/hex" "fmt" "os" "gopkg.in/yaml.v3" ) // Config holds all relay configuration loaded from config.yaml. type Config struct { Addr string `yaml:"addr"` DB string `yaml:"db"` RelayURL string `yaml:"relay_url"` Allowlist []string `yaml:"allowlist"` // hex-encoded pubkeys } // DefaultConfig returns sensible defaults. func DefaultConfig() Config { return Config{ Addr: ":8080", DB: "axon.db", RelayURL: "ws://localhost:8080", } } // AllowlistBytes decodes the hex pubkeys in c.Allowlist and returns them as // raw byte slices. Returns an error if any entry is not valid 64-char hex. func (c *Config) AllowlistBytes() ([][]byte, error) { out := make([][]byte, 0, len(c.Allowlist)) for _, h := range c.Allowlist { b, err := hex.DecodeString(h) if err != nil { return nil, fmt.Errorf("config: allowlist entry %q is not valid hex: %w", h, err) } if len(b) != 32 { return nil, fmt.Errorf("config: allowlist entry %q decoded to %d bytes, want 32", h, len(b)) } out = append(out, b) } return out, nil } // LoadConfig reads and parses a YAML config file. Missing fields fall back to // DefaultConfig values. func LoadConfig(path string) (Config, error) { cfg := DefaultConfig() f, err := os.Open(path) if err != nil { if os.IsNotExist(err) { // No config file — use defaults. return cfg, nil } return cfg, fmt.Errorf("config: open %q: %w", path, err) } defer f.Close() dec := yaml.NewDecoder(f) dec.KnownFields(true) if err := dec.Decode(&cfg); err != nil { return cfg, fmt.Errorf("config: decode %q: %w", path, err) } return cfg, nil }