package main import ( "context" "encoding/json" "fmt" "os" "regexp" "slices" "strconv" "strings" "time" ) type Config struct { Port int Debug bool InitializeSlack bool SlackToken string SlackChannels string PostgresConn string storage Storage queue Queue driver Driver } func newConfig(ctx context.Context) (Config, error) { return newConfigFromEnv(ctx, os.Getenv) } func newConfigFromEnv(ctx context.Context, getEnv func(string) string) (Config, error) { def := Config{ Port: 8080, } var m map[string]any if b, err := json.Marshal(def); err != nil { return Config{}, err } else if err := json.Unmarshal(b, &m); err != nil { return Config{}, err } re := regexp.MustCompile(`[A-Z]`) for k, v := range m { envK := k idxes := re.FindAllIndex([]byte(envK), -1) slices.Reverse(idxes) for _, idx := range idxes { if idx[0] > 0 { envK = fmt.Sprintf("%s_%s", envK[:idx[0]], envK[idx[0]:]) } } envK = strings.ToUpper(envK) s := getEnv(envK) if s == "" { continue } switch v.(type) { case string: m[k] = s case int64, float64: n, err := strconv.ParseFloat(s, 32) if err != nil { return Config{}, err } m[k] = n case bool: got, err := strconv.ParseBool(s) if err != nil { return Config{}, err } m[k] = got } } var result Config if b, err := json.Marshal(m); err != nil { return Config{}, err } else if err := json.Unmarshal(b, &result); err != nil { return Config{}, err } result.driver = NewRAM() if result.PostgresConn != "" { ctx, can := context.WithTimeout(ctx, time.Second*10) defer can() pg, err := NewPostgres(ctx, result.PostgresConn) if err != nil { return Config{}, err } result.driver = pg } result.storage = NewStorage(result.driver) result.queue = NewQueue(result.driver) return result, nil }