From a54575b003ec0134c04cce1e403be7370342a6d7 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Mon, 26 Jan 2026 23:26:07 -0700 Subject: [PATCH] (FIX): Fixed up the environent, much needed. Super cool package that uses struct tags to load the environment. Still need to clean up the function in the server/server.go file. --- go.mod | 1 + go.sum | 2 + internal/app/server/server.go | 31 +++++----- internal/domain/server/server.go | 103 +++++-------------------------- 4 files changed, 33 insertions(+), 104 deletions(-) diff --git a/go.mod b/go.mod index dc94d15..2b8eca0 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/goccy/go-json v0.10.5 // indirect github.com/google/uuid v1.6.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect diff --git a/go.sum b/go.sum index dee93ff..a3a4fbc 100644 --- a/go.sum +++ b/go.sum @@ -69,6 +69,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 958d132..f78c781 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -57,6 +57,9 @@ func Init(port int) *Server { server.config.AllowCredentials = true server.Router.Use(cors.New(server.config)) + // We can use release mode since we don't need Gin's logging + gin.SetMode(gin.ReleaseMode) + return server } @@ -70,7 +73,7 @@ func (s *Server) Start() { // TODO: (1/26/2026) Abstract these functions and cleanup. This is fucking messy... still func (s *Server) Setup() *Server { // SETUP THE ENVIRONMENT CONFIGURATION - cfg, err := domain.LoadEnvironment(s.logs) + cfg, err := domain.LoadEnvironment() if err != nil { logging.LogAll(s.logs, logging.LogLevelFatal, err.Error()) panic(err.Error()) @@ -80,14 +83,7 @@ func (s *Server) Setup() *Server { panic("Environment configuration is nil, crashing.") } - // TODO: Using release on them all? Def need to clean this shitty environment up - if cfg.Environment == "dev" { - gin.SetMode(gin.ReleaseMode) - } else if cfg.Environment == "prod" { - gin.SetMode(gin.ReleaseMode) - } else { - gin.SetMode(gin.TestMode) - } + logging.LogAll(s.logs, logging.LogLevelDebug, "env: %+v\n", cfg) // SETUP GOOGLE AUTH var ( @@ -117,14 +113,16 @@ func (s *Server) Setup() *Server { s.DB = db // TODO: Implement environment here for logging file - path := "./logs.log" - fileLogger, cleanup, err := loggers.NewFileLogger(path, logging.LogLevelDebug) - if err != nil { - logging.LogAll(s.logs, logging.LogLevelWarning, "Failed to create file logger. %s\n", err.Error()) - } else { - s.logs = append(s.logs, fileLogger) - defer cleanup() + if cfg.LogFilePath != "" { + fileLogger, cleanup, err := loggers.NewFileLogger(cfg.LogFilePath, logging.LogLevelDebug) + if err != nil { + logging.LogAll(s.logs, logging.LogLevelWarning, "Failed to create file logger. %s\n", err.Error()) + } else { + logging.LogAll(s.logs, logging.LogLevelDebug, "Initialized file logger on file '%s'\n", cfg.LogFilePath) + s.logs = append(s.logs, fileLogger) + defer cleanup() + } } databaseLogger, err := loggers.NewDatabaseLogger(s.DB, "logs", logging.LogLevelInfo) @@ -155,7 +153,6 @@ func (s *Server) Setup() *Server { } // Apply middleware - // TODO: Review the recovery middleware s.Router.Use(gin.Recovery(), RecoveryMiddleware(s.logs), LoggingMiddleware(s.logs)) // Redirect index to home page: Update this as needed diff --git a/internal/domain/server/server.go b/internal/domain/server/server.go index 1f7a308..58c8c29 100644 --- a/internal/domain/server/server.go +++ b/internal/domain/server/server.go @@ -2,7 +2,6 @@ package domain import ( "fmt" - "os" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" @@ -10,21 +9,22 @@ import ( domainEngagement "github.com/haydenhargreaves/Potion/internal/domain/engagement" domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" domainUser "github.com/haydenhargreaves/Potion/internal/domain/user" - "github.com/haydenhargreaves/Potion/internal/infrastructure/logging" "github.com/joho/godotenv" + "github.com/kelseyhightower/envconfig" ) // EnvironmentConfig stores the configuration of the environment. Anything loaded from the .env // or docker environment will be stored here and can be accessed from the InjectedDependencies // struct, which this is attached to. type EnvironmentConfig struct { - GoogleClientId string - GoogleClientSecret string - JwtSecret string - DatabaseUrl string - Environment string - Domain string - FrontendDomain string + GoogleClientId string `envconfig:"GOOGLE_CLIENT_ID" required:"true"` + GoogleClientSecret string `envconfig:"GOOGLE_CLIENT_SECRET" required:"true"` + JwtSecret string `envconfig:"JWT_SECRET" required:"true"` + DatabaseUrl string `envconfig:"DATABASE_URL" required:"true"` + Domain string `envconfig:"DOMAIN" required:"true"` + FrontendDomain string `envconfig:"FRONTEND_DOMAIN" required:"true"` + Environment string `envconfig:"ENVIRONMENT" required:"true"` + LogFilePath string `envconfig:"LOG_FILE_PATH" required:"false"` } // InjectedDependencies is a collection of dependencies that are injected into the application. They @@ -52,87 +52,16 @@ func IsLoggedIn(ctx *gin.Context) bool { return id && email } -// LoadEnvironment loads the environment values from either an .env file or docker environment. In -// the event that required fields are not provided, an error will return and the caller should handle -// the missing value or panic. Toggles between 'dev', 'prod', etc are also handled by this method, -// the values can be access assuming they are the proper values based on the provided environment. -func LoadEnvironment(logs []logging.Logger) (*EnvironmentConfig, error) { - err := godotenv.Load(".env") - if err != nil { - logging.LogAll(logs, logging.LogLevelWarning, "No .env file found or error loading .env: %v. Relying on system environment variables.", err) - } +// LoadEnvironment loads the environment values from either an .env file or docker environment. +func LoadEnvironment() (*EnvironmentConfig, error) { + // NOTE: Does the error return matter? + godotenv.Load(".env") - env := os.Getenv("ENVIRONMENT") - if env == "" { - return nil, fmt.Errorf("ENVIRONMENT environment variable is required.") + cfg := &EnvironmentConfig{} + if err := envconfig.Process("", cfg); err != nil { + return nil, fmt.Errorf("Failed to load environment: %w", err) } - googleClientId := os.Getenv("GOOGLE_CLIENT_ID") - if googleClientId == "" { - return nil, fmt.Errorf("GOOGLE_CLIENT_ID environment variable is required.") - } - - googleClientSecret := os.Getenv("GOOGLE_CLIENT_SECRET") - if googleClientSecret == "" { - return nil, fmt.Errorf("GOOGLE_CLIENT_SECRET environment variable is required.") - } - - jwtSecret := os.Getenv("JWT_SECRET") - if jwtSecret == "" { - return nil, fmt.Errorf("JWT_SECRET environment variable is required.") - } - - var domain string - var frontendDomain string - if env == "dev" { - domain = os.Getenv("DOMAIN_DEV") - if domain == "" { - return nil, fmt.Errorf("DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.") - } - frontendDomain = os.Getenv("FRONTEND_DOMAIN_DEV") - if frontendDomain == "" { - return nil, fmt.Errorf("FRONTEND_DOMAIN_DEV environment variable is required when ENVIRONMENT is 'dev'.") - } - } else if env == "prod" { - domain = os.Getenv("DOMAIN_PROD") - if domain == "" { - return nil, fmt.Errorf("DOMAIN_PROD environment variable is required when ENVIRONMENT is 'prod'.") - } - frontendDomain = os.Getenv("FRONTEND_DOMAIN_PROD") - if frontendDomain == "" { - return nil, fmt.Errorf("FRONTEND_DOMAIN_PROD environment variable is required when ENVIRONMENT is 'dev'.") - } - } else { - return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.") - } - - var dbUrl string - if env == "dev" { - dbUrl = os.Getenv("DATABASE_URL_DEV") - if dbUrl == "" { - return nil, fmt.Errorf("DATABASE_URL_DEV environment variable is required when ENVIRONMENT is 'dev'.") - } - } else if env == "prod" { - dbUrl = os.Getenv("DATABASE_URL_PROD") - if dbUrl == "" { - return nil, fmt.Errorf("DATABASE_URL_PROD environment variable is required when ENVIRONMENT is 'prod'.") - } - } else { - return nil, fmt.Errorf("ENVIRONMENT environment variable is required and must be 'dev' or 'prod'.") - } - - cfg := &EnvironmentConfig{ - GoogleClientId: googleClientId, - GoogleClientSecret: googleClientSecret, - JwtSecret: jwtSecret, - DatabaseUrl: dbUrl, - Environment: env, - Domain: domain, - FrontendDomain: frontendDomain, - } - - logging.LogAll(logs, logging.LogLevelDebug, "Environment Config: %+v\n", cfg) - return cfg, nil }