package holy import ( "encoding/json" "errors" "os" "tg-holy-bot/internal/log" "github.com/hjson/hjson-go" ) // ReadConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге // нет. func ReadConfig() error { locations, err := defaultConfigFileLocations() if err != nil { return err } for _, location := range locations { fileInfo, err := os.Stat(location) // Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём. if err != nil { continue } // Конфиг-файл длинноват для конфига, попробуем следующего кандидата. if fileInfo.Size() > ConfigFileSize { log.Warnf("Config file %s is too long for config, skipping", location) continue } buf, err := os.ReadFile(location) // Не удалось прочитать, попробуем следующего кандидата. if err != nil { log.Warnf("Skip reading config file %s: %s", location, err) continue } // Исходя из документации, hjson какбы умеет парсить "кривой" json, но парсит его в map-ку. // Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку // сериализуем в json, а потом json преврщааем в стркутурку. Не очень эффективно, но оно и не часто требуется. var ( sampleConfig *MyConfig tmp map[string]any ) err = hjson.Unmarshal(buf, &tmp) // Не удалось распарсить - попробуем следующего кандидата. if err != nil { log.Warnf("Skip parsing config file %s: %s", location, err) continue } tmpjson, err := json.Marshal(tmp) // Не удалось преобразовать map-ку в json. if err != nil { log.Warnf("Skip parsing config file %s: %s", location, err) continue } if err := json.Unmarshal(tmpjson, &sampleConfig); err != nil { log.Warnf("Skip parsing config file %s: %s", location, err) continue } if sampleConfig.Token == "" { return errors.New("Config option token is empty. Refusing to start") //nolint: staticcheck // Looks like golangci-lint ignoring settings about fucking ST1005 check. We want readable errors despite what wants author of linter or assholes from go dev team. } if sampleConfig.ChannelID == 0 { return errors.New("Config option channel_id is empty. Refusing to start") //nolint: staticcheck // Looks like golangci-lint ignoring settings about fucking ST1005 check. We want readable errors despite what wants author of linter or assholes from go dev team. } if sampleConfig.Loglevel == "" { sampleConfig.Loglevel = Loglevel log.Warnf("Config option loglevel not set, fallback to %s", sampleConfig.Loglevel) } if sampleConfig.Log == "" { log.Warn("Config option log is not set, fallback to stderr") } if sampleConfig.When == "" { sampleConfig.When = "CRON_TZ=Europe/Moscow 01 00 * * *" log.Warnf("Config option when is not set, fallback to %s", sampleConfig.When) } if len(sampleConfig.UserAgents) != 31 { return errors.New("Amount of user_agent strings in config must be exactly 31! Refusing to start") //nolint: staticcheck // Looks like golangci-lint ignoring settings about fucking ST1005 check. We want readable errors despite what wants author of linter or assholes from go dev team. } log.Infof("Using %s as config file", location) Config = sampleConfig return nil } return errors.New("Config was not loaded! Refusing to start") //nolint: staticcheck // Looks like golangci-lint ignoring settings about fucking ST1005 check. We want readable errors despite what wants author of linter or assholes from go dev team. } /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */