package service import ( "fmt" "os" "path/filepath" "time" "git.server.ky/slackcoder/mirror/internal" "github.com/BurntSushi/toml" ) // Global parameters type GlobalConfig struct { MaxInterval *Duration `toml:"max-interval"` MinInterval *Duration `toml:"min-interval"` } type Config struct { GlobalConfig `toml:"global"` Mirrors []*Mirror `toml:"mirrors,omitempty"` } func (c *Config) String() string { return internal.MustTOML(c) } var DefaultConfig = Config{ GlobalConfig: GlobalConfig{ MaxInterval: DurationRef(24 * time.Hour), MinInterval: DurationRef(time.Hour), }, } // Read the given configuration file. func readConfigFile(fp string) (*Config, error) { var config Config f, err := os.Open(fp) if err != nil { return nil, err } defer f.Close() _, err = toml.NewDecoder(f).Decode(&config) if err != nil { return nil, fmt.Errorf("loading configuration file: %w", err) } return &config, nil } // Read all configuration in the given directory. func readConfigDir(fp string) (*Config, error) { var cfg Config confDDir, err := os.ReadDir(fp) if os.IsNotExist(err) { // No directory is an empty one. return &Config{}, nil } else if err != nil { return nil, err } for _, entry := range confDDir { if filepath.Ext(entry.Name()) != ".toml" { continue } entryCfg, err := readConfigFile(filepath.Join(fp, entry.Name())) if err != nil { return nil, err } cfg.Append(entryCfg) } return &cfg, nil } // Read all configuration in the given directory. func ReadConfig(fps ...string) (*Config, error) { var cfg Config for _, fp := range fps { stat, err := os.Stat(fp) if err != nil { return nil, err } var c *Config if stat.IsDir() { c, err = readConfigDir(fp) if err != nil { return nil, err } } else { c, err = readConfigFile(fp) } cfg.Append(c) } return &cfg, nil } // Apply the given configuration parameters. func (c *Config) Append(src *Config) { if src.MaxInterval != nil { c.MaxInterval = src.MaxInterval } if src.MinInterval != nil { c.MinInterval = src.MinInterval } c.Mirrors = append(c.Mirrors, src.Mirrors...) }