Files
query-orchestration/internal/serviceconfig/common.go
T
Michael McGuinness 7001ca854c Merged in feature/docinitialisation (pull request #41)
Queuing Changes and Cfg Testing

* staarting

* staarting

* startedpush

* note

* save

* mocking

* removederrs

* fixtests

* cleanuperrs

* newenvsetup

* preppingtests

* queue

* mmovetocfgpassunittests

* sortoutconfig

* passinginteg

* deps

* fixtests
2025-02-03 17:30:50 +00:00

129 lines
3.2 KiB
Go

package serviceconfig
import (
"errors"
"log/slog"
"os"
"queryorchestration/internal/serviceconfig/aws"
"queryorchestration/internal/serviceconfig/database"
"queryorchestration/internal/serviceconfig/logger"
"queryorchestration/internal/serviceconfig/observability"
"queryorchestration/internal/serviceconfig/queue"
"reflect"
"github.com/caarlos0/env/v11"
"github.com/joho/godotenv"
)
// Common Types
// ------------
// Logging
// BaseConfig provides common configuration fields and functionality
// that can be embedded in service-specific configs.
type BaseConfig struct {
logger.LogConfig
observability.ObsConfig
database.DBConfig
aws.AWSConfig
queue.QueueConfig
// miscellaneous fields uncategorized
// PWD will replace the BASE_PATH env var
Pwd string `env:"PWD,required,notEmpty"`
// BASE_PATH will override the PWD env var if present
BasePath string `env:"BASE_PATH"`
}
// Interfaces
// ----------
// ConfigProvider defines the basic requirements for all configuration types.
// Implementations must provide logging capabilities and configuration display.
type ConfigProvider interface {
database.ConfigProvider
observability.ConfigProvider
logger.ConfigProvider
aws.ConfigProvider
queue.ConfigProvider
GetBasePath() string
SetDBConfig(*database.DBConfig)
}
// Configuration Methods
// -------------------
// InitializeConfig sets up a configuration instance by loading environment
// variables and initializing the logger. It expects a ConfigProvider implementation.
// Returns an error if initialization fails.
func getBaseConfig(cfg ConfigProvider) *BaseConfig {
if cfg == nil {
return nil
}
t := reflect.ValueOf(cfg).Type()
if t == reflect.TypeOf(&BaseConfig{}) {
v := reflect.ValueOf(cfg).Interface().(*BaseConfig)
return v
} else if t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct {
return nil
}
val := reflect.ValueOf(cfg).Elem()
var baseConfig *BaseConfig
for i := 0; i < val.NumField() && baseConfig == nil; i++ {
b := val.Field(i)
intType := reflect.TypeOf((*ConfigProvider)(nil)).Elem()
if b.Type().Implements(intType) {
baseConfig = getBaseConfig(b.Interface().(ConfigProvider))
} else if reflect.PointerTo(b.Type()).Implements(intType) {
baseConfig = getBaseConfig(b.Addr().Interface().(ConfigProvider))
}
}
return baseConfig
}
func InitializeConfig(cfg ConfigProvider) error {
baseConfig := getBaseConfig(cfg)
if baseConfig == nil {
return errors.New("no BaseConfig found in the provided config struct")
}
baseConfig.Logger = slog.New(slog.NewTextHandler(os.Stdout, nil))
slog.SetDefault(baseConfig.Logger)
if err := godotenv.Load(); err != nil {
slog.Warn("No .env file found or error loading it", "error", err)
}
if err := env.Parse(cfg); err != nil {
if envErr, ok := err.(env.AggregateError); ok {
slog.Error("Missing required environment variables:")
for _, e := range envErr.Errors {
slog.Error(e.Error())
}
} else {
slog.Error("Error parsing environment variables", "error", err)
}
return err
}
return nil
}
func (b *BaseConfig) GetBasePath() string {
if b.BasePath != "" {
return b.BasePath
}
return b.Pwd
}
func (b *BaseConfig) SetDBConfig(cfg *database.DBConfig) {
b.DBConfig = *cfg
}