package config import ( "fmt" "os" "path/filepath" "reflect" "strconv" "strings" "gitserver.in/patialtech/rano/config/dotenv" "gitserver.in/patialtech/rano/pkg/logger" ) const ( // projDir need to be same as project code root dir name projDir = "rano" EnvDev = "development" EnvProd = "production" EnvStage = "staging" AuthUserCtxKey = "AuthUser" ) var ( conf *Config AppEnv Env = EnvDev ) type ( Env string Config struct { WebPort int `env:"WEB_PORT"` WebURL string `env:"WEB_URL"` GraphPort int `env:"GRAPH_PORT"` GrapURL string `env:"GRAPH_URL"` DbURL string `env:"DB_URL"` } ) func init() { wd, _ := os.Getwd() // In dev env we run test and other program for diff dir locations under project root, // this makes reading env file harder. // Let's add a hack to make sure we fallback to root dir in dev env if AppEnv == EnvDev { idx := strings.Index(wd, projDir) if idx > -1 { wd = filepath.Join(wd[:idx], projDir) } } envVar, err := dotenv.Read(wd, fmt.Sprintf(".env.%s", AppEnv)) if err != nil { panic(err) } conf = &Config{} conf.loadEnv(envVar) } // Read config for Env func Read() *Config { if conf == nil { panic("config not initialized") } return conf } func (c *Config) loadEnv(vars map[string]string) { if c == nil { return } val := reflect.Indirect(reflect.ValueOf(c)) for i := 0; i < val.NumField(); i++ { f := val.Type().Field(i) tag := f.Tag.Get("env") if tag == "" { continue } v, found := vars[tag] if !found { logger.Warn("var %q not found in file .env.%s", tag, AppEnv) continue } field := val.FieldByName(f.Name) if !field.IsValid() { continue } switch f.Type.Kind() { case reflect.Int: if intV, err := strconv.ParseInt(v, 10, 64); err != nil { panic(err) } else { field.SetInt(intV) } default: field.SetString(v) } } }