package config import ( "encoding/json" "errors" "fmt" "io/fs" "os" "github.com/sirupsen/logrus" ) type ListeningMode int64 func (lm ListeningMode) String() string { mapping := map[ListeningMode]string{ ModeNet: "net", ModeUnix: "unix", } val := mapping[lm] return val } func listeningModeFromString(rawVal string) (ListeningMode, error) { mapping := map[string]ListeningMode{ "unix": ModeUnix, "net": ModeNet, } if typedVal, ok := mapping[rawVal]; !ok { return ModeNet, fmt.Errorf("invalid listening mode %s", rawVal) } else { return typedVal, nil } } const ( ModeUnix ListeningMode = iota ModeNet ) type jsonConf struct { Log struct { Level string `json:"level"` } `json:"log"` Server struct { Host string `json:"host"` Port int `json:"port"` Mode string `json:"mode"` SockPath string `json:"sock"` } `json:"server"` BootProvider struct { Iface string `json:"interface"` Port int `json:"port"` McastGroup string `json:"multicast_group"` } `json:"boot_provider"` } type AppConfig struct { LogLevel logrus.Level ServerMode ListeningMode Host string Port int SockPath string UPDMcastGroup string UDPPort int UDPIface string } func parseLevel(lvlStr string) logrus.Level { for _, lvl := range logrus.AllLevels { if lvl.String() == lvlStr { return lvl } } return logrus.InfoLevel } func (ac *AppConfig) UnmarshalJSON(data []byte) error { var jsonConf jsonConf if err := json.Unmarshal(data, &jsonConf); err != nil { return fmt.Errorf("failed to read JSON: %w", err) } ac.LogLevel = parseLevel(jsonConf.Log.Level) lm, err := listeningModeFromString(jsonConf.Server.Mode) if err != nil { return fmt.Errorf("failed to parse server listening mode: %w", err) } ac.ServerMode = lm ac.SockPath = jsonConf.Server.SockPath ac.Host = jsonConf.Server.Host ac.Port = jsonConf.Server.Port ac.UPDMcastGroup = jsonConf.BootProvider.McastGroup ac.UDPIface = jsonConf.BootProvider.Iface ac.UDPPort = jsonConf.BootProvider.Port return nil } var defaultConfig AppConfig = AppConfig{ LogLevel: logrus.InfoLevel, ServerMode: ModeNet, Host: "0.0.0.0", Port: 5000, UPDMcastGroup: "ff02::abcd:1234", UDPPort: 42, UDPIface: "eth0", } func New(filepath string) (*AppConfig, error) { content, err := os.ReadFile(filepath) if err != nil { if errors.Is(err, fs.ErrNotExist) { conf := defaultConfig return &conf, nil } return nil, fmt.Errorf("failed to read config file %q: %w", filepath, err) } var conf AppConfig if err := json.Unmarshal(content, &conf); err != nil { return nil, fmt.Errorf("failed to parse config file: %w", err) } return &conf, nil }