package parser import ( "errors" "fmt" "net/url" "os" "time" "github.com/aykhans/dodo/pkg/config" "github.com/aykhans/dodo/pkg/types" "github.com/aykhans/dodo/pkg/utils" ) var _ IParser = ConfigENVParser{} type ConfigENVParser struct { envPrefix string } func NewConfigENVParser(envPrefix string) *ConfigENVParser { return &ConfigENVParser{envPrefix} } // Parse parses env arguments into a Config object. // It can return the following errors: // - types.FieldParseErrors func (parser ConfigENVParser) Parse() (*config.Config, error) { var ( config = &config.Config{} fieldParseErrors []types.FieldParseError ) if configFile := parser.getEnv("CONFIG_FILE"); configFile != "" { configFileParsed, err := types.ParseConfigFile(configFile) _ = utils.HandleErrorOrDie(err, utils.OnSentinelError(types.ErrConfigFileExtensionNotFound, func(err error) error { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("CONFIG_FILE"), configFile, errors.New("file extension not found"), ), ) return nil }), utils.OnCustomError(func(err types.RemoteConfigFileParseError) error { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("CONFIG_FILE"), configFile, fmt.Errorf("parse error: %w", err), ), ) return nil }), utils.OnCustomError(func(err types.UnknownConfigFileTypeError) error { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("CONFIG_FILE"), configFile, fmt.Errorf("file type '%s' not supported (supported types: %s)", err.Type, types.ConfigFileTypeYAML), ), ) return nil }), ) if err == nil { config.Files = append(config.Files, *configFileParsed) } } if yes := parser.getEnv("YES"); yes != "" { yesParsed, err := utils.ParseString[bool](yes) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("YES"), yes, errors.New("invalid value for boolean, expected 'true' or 'false'"), ), ) } else { config.Yes = &yesParsed } } if skipVerify := parser.getEnv("SKIP_VERIFY"); skipVerify != "" { skipVerifyParsed, err := utils.ParseString[bool](skipVerify) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("SKIP_VERIFY"), skipVerify, errors.New("invalid value for boolean, expected 'true' or 'false'"), ), ) } else { config.SkipVerify = &skipVerifyParsed } } if method := parser.getEnv("METHOD"); method != "" { config.Method = &method } if urlEnv := parser.getEnv("URL"); urlEnv != "" { urlEnvParsed, err := url.Parse(urlEnv) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError(parser.getFullEnvName("URL"), urlEnv, err), ) } else { config.URL = urlEnvParsed } } if dodos := parser.getEnv("DODOS"); dodos != "" { dodosParsed, err := utils.ParseString[uint](dodos) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("DODOS"), dodos, errors.New("invalid value for unsigned integer"), ), ) } else { config.DodosCount = &dodosParsed } } if requests := parser.getEnv("REQUESTS"); requests != "" { requestsParsed, err := utils.ParseString[uint](requests) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("REQUESTS"), requests, errors.New("invalid value for unsigned integer"), ), ) } else { config.RequestCount = &requestsParsed } } if duration := parser.getEnv("DURATION"); duration != "" { durationParsed, err := utils.ParseString[time.Duration](duration) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("DURATION"), duration, errors.New("invalid value duration, expected a duration string (e.g., '10s', '1h30m')"), ), ) } else { config.Duration = &durationParsed } } if timeout := parser.getEnv("TIMEOUT"); timeout != "" { timeoutParsed, err := utils.ParseString[time.Duration](timeout) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("TIMEOUT"), timeout, errors.New("invalid value duration, expected a duration string (e.g., '10s', '1h30m')"), ), ) } else { config.Timeout = &timeoutParsed } } if param := parser.getEnv("PARAM"); param != "" { config.Params.Parse(param) } if header := parser.getEnv("HEADER"); header != "" { config.Headers.Parse(header) } if cookie := parser.getEnv("COOKIE"); cookie != "" { config.Cookies.Parse(cookie) } if body := parser.getEnv("BODY"); body != "" { config.Bodies.Parse(body) } if proxy := parser.getEnv("PROXY"); proxy != "" { err := config.Proxies.Parse(proxy) if err != nil { fieldParseErrors = append( fieldParseErrors, *types.NewFieldParseError( parser.getFullEnvName("PROXY"), proxy, err, ), ) } } if len(fieldParseErrors) > 0 { return nil, types.NewFieldParseErrors(fieldParseErrors) } return config, nil } func (parser ConfigENVParser) getFullEnvName(envName string) string { if parser.envPrefix == "" { return envName } return parser.envPrefix + "_" + envName } func (parser ConfigENVParser) getEnv(envName string) string { return os.Getenv(parser.getFullEnvName(envName)) }