aboutsummaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/config.go205
-rw-r--r--config/constants.go7
-rw-r--r--config/types.go12
3 files changed, 224 insertions, 0 deletions
diff --git a/config/config.go b/config/config.go
new file mode 100644
index 0000000..4ad3c25
--- /dev/null
+++ b/config/config.go
@@ -0,0 +1,205 @@
+package config
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "reflect"
+ "strconv"
+ "time"
+
+ "github.com/joho/godotenv"
+)
+
+var (
+ Server ServerConfig
+ GitHub GitHubConfig
+)
+
+func init() {
+ godotenv.Load()
+
+ if err := parse(&Server); err != nil {
+ log.Fatalf("failed to parse server config: %v", err)
+ }
+
+ if err := parse(&GitHub); err != nil {
+ log.Fatalf("failed to parse GitHub config: %v", err)
+ }
+}
+
+func getEnv(key, defaultVal string) string {
+ if value := os.Getenv(key); value != "" {
+ return value
+ }
+ return defaultVal
+}
+
+func getEnvBool(key string, defaultVal bool) bool {
+ if value := os.Getenv(key); value != "" {
+ if parsed, err := strconv.ParseBool(value); err == nil {
+ return parsed
+ }
+ }
+ return defaultVal
+}
+
+func getEnvDuration(key string, defaultVal time.Duration) time.Duration {
+ if value := os.Getenv(key); value != "" {
+ if parsed, err := time.ParseDuration(value); err == nil {
+ return parsed
+ }
+ }
+ return defaultVal
+}
+
+func getEnvInt64(key string, defaultVal int64) int64 {
+ if value := os.Getenv(key); value != "" {
+ if parsed, err := strconv.ParseInt(value, 10, 64); err == nil {
+ return parsed
+ }
+ }
+ return defaultVal
+}
+
+func getEnvFloat64(key string, defaultVal float64) float64 {
+ if value := os.Getenv(key); value != "" {
+ if parsed, err := strconv.ParseFloat(value, 64); err == nil {
+ return parsed
+ }
+ }
+ return defaultVal
+}
+
+func setFieldFromEnv(field reflect.Value, envKey, defaultVal string) {
+ switch field.Kind() {
+ case reflect.String:
+ field.SetString(getEnv(envKey, defaultVal))
+ case reflect.Bool:
+ defaultBool, _ := strconv.ParseBool(defaultVal)
+ field.SetBool(getEnvBool(envKey, defaultBool))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ defaultInt, _ := strconv.ParseInt(defaultVal, 10, 64)
+ field.SetInt(getEnvInt64(envKey, defaultInt))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ defaultUint, _ := strconv.ParseUint(defaultVal, 10, 64)
+ setUintField(field, envKey, defaultUint)
+ case reflect.Float32, reflect.Float64:
+ defaultFloat, _ := strconv.ParseFloat(defaultVal, 64)
+ field.SetFloat(getEnvFloat64(envKey, defaultFloat))
+ default:
+ setDurationField(field, envKey, defaultVal)
+ }
+}
+
+func setUintField(field reflect.Value, envKey string, defaultVal uint64) {
+ if value := os.Getenv(envKey); value != "" {
+ if parsed, err := strconv.ParseUint(value, 10, 64); err == nil {
+ field.SetUint(parsed)
+ return
+ }
+ }
+ field.SetUint(defaultVal)
+}
+
+func setDurationField(field reflect.Value, envKey, defaultVal string) {
+ if field.Type() == reflect.TypeOf(time.Duration(0)) {
+ defaultDuration, _ := time.ParseDuration(defaultVal)
+ field.Set(reflect.ValueOf(getEnvDuration(envKey, defaultDuration)))
+ }
+}
+
+func setFieldDefault(field reflect.Value, defaultVal string) {
+ switch field.Kind() {
+ case reflect.String:
+ field.SetString(defaultVal)
+ case reflect.Bool:
+ if defaultBool, err := strconv.ParseBool(defaultVal); err == nil {
+ field.SetBool(defaultBool)
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if defaultInt, err := strconv.ParseInt(defaultVal, 10, 64); err == nil {
+ field.SetInt(defaultInt)
+ }
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if defaultUint, err := strconv.ParseUint(defaultVal, 10, 64); err == nil {
+ field.SetUint(defaultUint)
+ }
+ case reflect.Float32, reflect.Float64:
+ if defaultFloat, err := strconv.ParseFloat(defaultVal, 64); err == nil {
+ field.SetFloat(defaultFloat)
+ }
+ default:
+ if field.Type() == reflect.TypeOf(time.Duration(0)) {
+ if defaultDuration, err := time.ParseDuration(defaultVal); err == nil {
+ field.Set(reflect.ValueOf(defaultDuration))
+ }
+ }
+ }
+}
+
+func validateConfigInput(config any) (reflect.Value, reflect.Type, error) {
+ v := reflect.ValueOf(config)
+ if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
+ return reflect.Value{}, nil, fmt.Errorf("config must be a pointer to struct")
+ }
+ elem := v.Elem()
+ return elem, elem.Type(), nil
+}
+
+func parse(config any) error {
+ elem, t, err := validateConfigInput(config)
+ if err != nil {
+ return err
+ }
+
+ for i := range elem.NumField() {
+ field := elem.Field(i)
+ fieldType := t.Field(i)
+
+ if !field.CanSet() {
+ continue
+ }
+
+ envKey := fieldType.Tag.Get("env")
+ defaultVal := fieldType.Tag.Get("default")
+
+ if envKey == "" {
+ continue
+ }
+
+ setFieldFromEnv(field, envKey, defaultVal)
+ }
+
+ return nil
+}
+
+func Defaults[T any](config *T) *T {
+ v := reflect.ValueOf(config)
+ if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
+ return config
+ }
+
+ elem := v.Elem()
+ t := elem.Type()
+ newStruct := reflect.New(t)
+ newElem := newStruct.Elem()
+
+ for i := range elem.NumField() {
+ field := newElem.Field(i)
+ fieldType := t.Field(i)
+
+ if !field.CanSet() {
+ continue
+ }
+
+ defaultVal := fieldType.Tag.Get("default")
+ if defaultVal == "" {
+ continue
+ }
+
+ setFieldDefault(field, defaultVal)
+ }
+
+ return newStruct.Interface().(*T)
+}
diff --git a/config/constants.go b/config/constants.go
new file mode 100644
index 0000000..8cb829d
--- /dev/null
+++ b/config/constants.go
@@ -0,0 +1,7 @@
+package config
+
+const (
+ PAGETITLE_HOME = "Home"
+
+ TEMPLATE_HOME = "home"
+)
diff --git a/config/types.go b/config/types.go
new file mode 100644
index 0000000..a57100f
--- /dev/null
+++ b/config/types.go
@@ -0,0 +1,12 @@
+package config
+
+type ServerConfig struct {
+ Host string `env:"SERVER_HOST" default:"0.0.0.0"`
+ Port int `env:"SERVER_PORT" default:"8080"`
+ IsDevMode bool `env:"SERVER_IS_DEV_MODE" default:"true"`
+}
+
+type GitHubConfig struct {
+ GitHubUsername string `env:"GITHUB_USERNAME"`
+ GitHubToken string `env:"GITHUB_TOKEN"`
+}