package serverSonfig import ( "encoding/json" "fmt" "os" "doll/internal/log" hjson "github.com/hjson/hjson-go/v4" ) // MyConfig config structure prototype. type MyConfig struct { Loglevel string `json:"loglevel,omitempty"` Logfile string `json:"logfile,omitempty"` } var ( // Config contains application running config data. Config MyConfig ) // ReadConfig reads and validates config file. Setups defaults where possible if values are not provided. func ReadConfig(location string) error { //nolint:gocognit,gocyclo var ( err error configLoaded bool ) fileInfo, err := os.Stat(location) if err != nil { return fmt.Errorf("unable to read %s: %w", location, err) } // Config file seems to be too long for valid config. if fileInfo.Size() > 65535 { return fmt.Errorf("config file %s is too long for config, skipping", location) } buf, err := os.ReadFile(location) // Config file is unreadable for some reasons. if err != nil { return fmt.Errorf("Skip reading config file %s: %s", location, err) } // According to docs hjson claims to be able to pase bad json, but parses it to go map. // It is more interesting to get strict as result, so we parse data to go map, then make json out of this map and // then parse this json to struct. It is not the most effective and speedy solution but it works and this action // been performed not so often. var ( sampleConfig MyConfig tmp map[string]interface{} ) err = hjson.Unmarshal(buf, &tmp) // Unable to parse json to map, that is unfortunate. if err != nil { return fmt.Errorf("Skip parsing config file %s: %s", location, err) } tmpJSON, err := json.Marshal(tmp) // Unable to parse map to json, well, we can nothing to with that. if err != nil { return fmt.Errorf("Skip parsing config file %s: %s", location, err) } // Unable to parse json to struct, just bail it here. if err := json.Unmarshal(tmpJSON, &sampleConfig); err != nil { return fmt.Errorf("Skip parsing config file %s: %s", location, err) } // Time to validate config values here. if sampleConfig.Loglevel == "" { sampleConfig.Loglevel = "info" log.Info("loglevel not defined in config, using info") } // sampleConfig.Log = "" if not set // TODO: validate the rest values fron config. Config = sampleConfig configLoaded = true log.Infof("Using %s as config file", location) if !configLoaded { return fmt.Errorf("config was not loaded!") //nolint:goerr113,revive,stylecheck } return err //nolint:wrapcheck } /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */