package config import ( "bufio" "fmt" "os" "strconv" "strings" "time" ) type Config struct { AppHost string AppPort string RSCode string DepartmentID string BearerToken string DBMaxOpenConns int DBMaxIdleConns int DBConnMaxLifetime time.Duration HISDBHost string HISDBPort string HISDBDatabase string HISDBUsername string HISDBPassword string } func Load(path string) (Config, error) { if err := loadDotEnv(path); err != nil { return Config{}, err } cfg := Config{ AppHost: env("APP_HOST", "0.0.0.0"), AppPort: env("APP_PORT", "8080"), RSCode: env("CPONE_RS_CODE", ""), DepartmentID: env("CPONE_DEPARTEMEN_ID", ""), BearerToken: env("CPONE_BEARER_TOKEN", ""), DBMaxOpenConns: envInt("DB_MAX_OPEN_CONNS", 25), DBMaxIdleConns: envInt("DB_MAX_IDLE_CONNS", 25), DBConnMaxLifetime: time.Duration(envInt("DB_CONN_MAX_LIFETIME_MINUTES", 5)) * time.Minute, HISDBHost: env("CPONE_DB_HOST", "127.0.0.1"), HISDBPort: env("CPONE_DB_PORT", "3306"), HISDBDatabase: env("CPONE_DB_DATABASE", ""), HISDBUsername: env("CPONE_DB_USERNAME", ""), HISDBPassword: env("CPONE_DB_PASSWORD", ""), } if cfg.RSCode == "" { return Config{}, fmt.Errorf("CPONE_RS_CODE wajib diisi") } if cfg.DepartmentID == "" { return Config{}, fmt.Errorf("CPONE_DEPARTEMEN_ID wajib diisi") } if cfg.BearerToken == "" { return Config{}, fmt.Errorf("CPONE_BEARER_TOKEN wajib diisi") } if cfg.HISDBDatabase == "" || cfg.HISDBUsername == "" { return Config{}, fmt.Errorf("CPONE_DB_DATABASE dan CPONE_DB_USERNAME wajib diisi") } return cfg, nil } func (c Config) Addr() string { return c.AppHost + ":" + c.AppPort } func loadDotEnv(path string) error { file, err := os.Open(path) if err != nil { if os.IsNotExist(err) { return nil } return err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } key, value, ok := strings.Cut(line, "=") if !ok { continue } key = strings.TrimSpace(key) value = strings.TrimSpace(value) value = strings.Trim(value, `"'`) if key != "" { if _, alreadySet := os.LookupEnv(key); !alreadySet { _ = os.Setenv(key, value) } } } return scanner.Err() } func env(key string, fallback string) string { value := os.Getenv(key) if value == "" { return fallback } return value } func envInt(key string, fallback int) int { value := os.Getenv(key) if value == "" { return fallback } parsed, err := strconv.Atoi(value) if err != nil { return fallback } return parsed }