add config file parser

This commit is contained in:
2025-09-06 23:39:10 +04:00
parent c3292dee5f
commit 5cc13cfe7e
15 changed files with 1517 additions and 90 deletions

View File

@@ -1,11 +1,14 @@
package config
import (
"fmt"
"net/url"
"os"
"time"
"github.com/aykhans/dodo/pkg/types"
"github.com/aykhans/dodo/pkg/utils"
"github.com/jedib0t/go-pretty/v6/text"
)
const VERSION string = "1.0.0"
@@ -26,7 +29,11 @@ var Defaults = struct {
SkipVerify: false,
}
var SupportedProxySchemes []string = []string{"http", "socks5", "socks5h"}
var SupportedProxySchemes = []string{"http", "socks5", "socks5h"}
type IParser interface {
Parse() (*Config, error)
}
type Config struct {
Files []types.ConfigFile
@@ -112,3 +119,102 @@ func (config *Config) SetDefaults() {
config.Headers = append(config.Headers, types.Header{Key: "User-Agent", Value: []string{Defaults.UserAgent}})
}
}
func ReadAllConfigs() *Config {
envParser := NewConfigENVParser("DODO")
envConfig, err := envParser.Parse()
_ = utils.HandleErrorOrDie(err,
utils.OnCustomError(func(err types.FieldParseErrors) error {
printValidationErrors("ENV", err.Errors...)
fmt.Println()
os.Exit(1)
return nil
}),
)
cliParser := NewConfigCLIParser(os.Args)
cliConf, err := cliParser.Parse()
_ = utils.HandleErrorOrDie(err,
utils.OnSentinelError(types.ErrCLINoArgs, func(err error) error {
cliParser.PrintHelp()
utils.PrintErrAndExit(text.FgYellow, 1, "\nNo arguments provided.")
return nil
}),
utils.OnCustomError(func(err types.CLIUnexpectedArgsError) error {
cliParser.PrintHelp()
utils.PrintErrAndExit(text.FgYellow, 1, "\nUnexpected CLI arguments provided: %v", err.Args)
return nil
}),
utils.OnCustomError(func(err types.FieldParseErrors) error {
cliParser.PrintHelp()
fmt.Println()
printValidationErrors("CLI", err.Errors...)
os.Exit(1)
return nil
}),
)
envConfig.Merge(cliConf)
for _, configFile := range envConfig.Files {
fileConfig, err := parseConfigFile(configFile, 10)
_ = utils.HandleErrorOrDie(err,
utils.OnCustomError(func(err types.ConfigFileReadError) error {
cliParser.PrintHelp()
utils.PrintErrAndExit(text.FgYellow, 1, "\nFailed to read config file '%s': %v", configFile.Path(), err)
return nil
}),
utils.OnCustomError(func(err types.UnmarshalError) error {
utils.PrintErrAndExit(text.FgYellow, 1, "\nFailed to unmarshal config file '%s': %v", configFile.Path(), err)
return nil
}),
utils.OnCustomError(func(err types.FieldParseErrors) error {
printValidationErrors(fmt.Sprintf("CONFIG FILE '%s'", configFile.Path()), err.Errors...)
os.Exit(1)
return nil
}),
)
envConfig.Merge(fileConfig)
}
return envConfig
}
// parseConfigFile recursively parses a config file and its nested files up to maxDepth levels.
// Returns the merged configuration or an error if parsing fails.
// It can return the following errors:
// - types.ConfigFileReadError
// - types.UnmarshalError
// - types.FieldParseErrors
func parseConfigFile(configFile types.ConfigFile, maxDepth int) (*Config, error) {
configFileParser := NewConfigFileParser(configFile)
fileConfig, err := configFileParser.Parse()
if err != nil {
return nil, err
}
if maxDepth <= 0 {
return fileConfig, nil
}
for _, c := range fileConfig.Files {
innerFileConfig, err := parseConfigFile(c, maxDepth-1)
if err != nil {
return nil, err
}
fileConfig.Merge(innerFileConfig)
}
return fileConfig, nil
}
func printValidationErrors(parserName string, errors ...types.FieldParseError) {
for _, fieldErr := range errors {
if fieldErr.Value == "" {
utils.PrintErr(text.FgYellow, "[%s] Field '%s': %v", parserName, fieldErr.Field, fieldErr.Err)
}
utils.PrintErr(text.FgYellow, "[%s] Field '%s' (%s): %v", parserName, fieldErr.Field, fieldErr.Value, fieldErr.Err)
}
}