package main import ( "fmt" "gopkg.in/yaml.v3" "os" ) type Config struct { Links []Link `yaml:"links"` Monitor []Monitor `yaml:"monitor"` Exec []Item `yaml:"exec"` } func loadConfig(path string) (*Config, error) { f, err := os.Open(path) if err != nil { return nil, err } defer f.Close() var cfg Config dec := yaml.NewDecoder(f) dec.KnownFields(true) if err := dec.Decode(&cfg); err != nil { return nil, fmt.Errorf("parse %s: %w", path, err) } seen := map[string]bool{} // item names are global keys (monVals, RunScript) for _, l := range cfg.Links { if seen[l.Name] { return nil, fmt.Errorf("duplicate name %q", l.Name) } seen[l.Name] = true } for _, m := range cfg.Monitor { if seen[m.Name] { return nil, fmt.Errorf("duplicate name %q", m.Name) } seen[m.Name] = true } for _, it := range cfg.Exec { if seen[it.Name] { return nil, fmt.Errorf("duplicate name %q", it.Name) } seen[it.Name] = true } for _, it := range cfg.Monitor { if it.Refresh <= 0 { return nil, fmt.Errorf("monitor %q: refresh must be > 0", it.Name) } if it.Percentages < 0 || it.Percentages > 8 { return nil, fmt.Errorf("monitor %q: percentages must be 1..8", it.Name) } } for _, it := range cfg.Exec { if len(it.ArgTypes) != it.Args { return nil, fmt.Errorf("exec %q: arg_types must have args entries", it.Name) } for _, t := range it.ArgTypes { if t != "text" && t != "number" { return nil, fmt.Errorf("exec %q: arg type must be text|number", it.Name) } } } return &cfg, nil }