瀏覽代碼

refactor: update configuration handling and validation across services

lblt 2 周之前
父節點
當前提交
dc04d985a4

+ 9 - 6
examples/main.go

@@ -4,7 +4,6 @@ import (
 	"net/http"
 	"time"
 
-	"git.linuxforward.com/byom/byom-golang-lib/pkg/config"
 	"git.linuxforward.com/byom/byom-golang-lib/pkg/database"
 	"git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
 	"git.linuxforward.com/byom/byom-golang-lib/pkg/logger"
@@ -16,7 +15,7 @@ import (
 
 func main() {
 	// Initialize logger
-	log, err := logger.NewLogger(&config.Log{
+	log, err := logger.NewLogger(&logger.Config{
 		Level:   "info",
 		Format:  "text",
 		NoColor: false,
@@ -26,8 +25,11 @@ func main() {
 	}
 
 	// Initialize SQLite
-	db, err := database.NewSQLiteDB(database.SQLiteConfig{
-		Path: "app.db",
+	db, err := database.NewSQLiteDB(&database.Config{
+		Path:            "app.db",
+		MaxOpenConns:    1, // SQLite recommendation
+		MaxIdleConns:    1,
+		ConnMaxLifetime: 300, // 5 minutes
 	})
 	if err != nil {
 		log.Fatal(err)
@@ -35,7 +37,7 @@ func main() {
 	defer db.Close()
 
 	// Initialize Minio
-	minioClient, err := storage.NewMinioClient(storage.MinioConfig{
+	minioClient, err := storage.NewMinioClient(&storage.Config{
 		Endpoint:        "localhost:9000",
 		AccessKeyID:     "minioadmin",
 		SecretAccessKey: "minioadmin",
@@ -47,7 +49,8 @@ func main() {
 	}
 
 	// Initialize Gin server with configuration
-	srv, err := server.NewGinServer(log, server.ServerConfig{
+	srv, err := server.NewGinServer(log, &server.Config{
+		Port:           8080,
 		AllowedOrigins: []string{"http://localhost:3000"},
 		RequestTimeout: 30 * time.Second,
 	})

+ 22 - 0
pkg/auth/config.go

@@ -0,0 +1,22 @@
+package auth
+
+import (
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
+)
+
+// Config holds the authentication configuration
+type Config struct {
+	SecretKey     string `yaml:"secret_key"`
+	TokenDuration int    `yaml:"token_duration"` // in seconds
+}
+
+// Validate implements the config.Validator interface
+func (c *Config) Validate() error {
+	if c.SecretKey == "" {
+		return errors.NewConfigError("auth.secret_key", errors.ErrInvalidInput)
+	}
+	if c.TokenDuration == 0 {
+		c.TokenDuration = 86400 // 24 hours default
+	}
+	return nil
+}

+ 2 - 2
pkg/auth/jwt.go

@@ -11,9 +11,9 @@ type JWTService struct {
 	secretKey []byte
 }
 
-func NewJWTService(secretKey string) *JWTService {
+func NewJWTService(config *Config) *JWTService {
 	return &JWTService{
-		secretKey: []byte(secretKey),
+		secretKey: []byte(config.SecretKey),
 	}
 }
 

+ 36 - 113
pkg/config/config.go

@@ -5,19 +5,24 @@ import (
 	"fmt"
 	"os"
 
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/auth"
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/database"
 	"git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
-	"github.com/sirupsen/logrus"
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/logger"
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/server"
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/storage"
 	"gopkg.in/yaml.v3"
 )
 
 type Config struct {
-	App            *App            `yaml:"app"`
-	Server         *Server         `yaml:"server"`
-	Database       *Database       `yaml:"database"`
-	Log            *Log            `yaml:"log"`
-	Storage        *Storage        `yaml:"storage"`
-	CloudComputing *CloudComputing `yaml:"cloud_computing,omitempty"`
-	SocialNetworks *SocialNetworks `yaml:"social_networks,omitempty"`
+	App            *App             `yaml:"app"`
+	Auth           *auth.Config     `yaml:"auth"`
+	Server         *server.Config   `yaml:"server"`
+	Database       *database.Config `yaml:"database"`
+	Log            *logger.Config   `yaml:"log"`
+	Storage        *storage.Config  `yaml:"storage"`
+	CloudComputing *CloudComputing  `yaml:"cloud_computing,omitempty"`
+	SocialNetworks *SocialNetworks  `yaml:"social_networks,omitempty"`
 }
 
 func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
@@ -69,111 +74,6 @@ func (c *App) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	return nil
 }
 
-type Server struct {
-	Port           int      `yaml:"port"`
-	RequestTimeout int      `yaml:"request_timeout"` // in seconds
-	AllowedOrigins []string `yaml:"allowed_origins"`
-}
-
-func (c *Server) UnmarshalYAML(unmarshal func(interface{}) error) error {
-	type plain Server
-	err := unmarshal((*plain)(c))
-	if err != nil {
-		return err
-	}
-	if c.Port == 0 {
-		c.Port = 8080
-	}
-	if c.RequestTimeout == 0 {
-		c.RequestTimeout = 30
-	}
-	return nil
-}
-
-type Database struct {
-	Path            string   `yaml:"path"`
-	MaxOpenConns    int      `yaml:"max_open_conns"`
-	MaxIdleConns    int      `yaml:"max_idle_conns"`
-	ConnMaxLifetime int      `yaml:"conn_max_lifetime"`
-	Pragmas         []string `yaml:"pragmas"`
-}
-
-func (c *Database) UnmarshalYAML(unmarshal func(interface{}) error) error {
-	type plain Database
-	err := unmarshal((*plain)(c))
-	if err != nil {
-		return err
-	}
-	if c.Path == "" {
-		return errors.NewConfigError("database.path", errors.ErrInvalidInput)
-	}
-	if c.MaxOpenConns == 0 {
-		c.MaxOpenConns = 1 // SQLite recommendation
-	}
-	if c.MaxIdleConns == 0 {
-		c.MaxIdleConns = 1
-	}
-	if c.ConnMaxLifetime == 0 {
-		c.ConnMaxLifetime = 300 // 5 minutes
-	}
-	return nil
-}
-
-type Log struct {
-	Level   string `yaml:"level"`
-	Format  string `yaml:"format"` // "json" or "text"
-	NoColor bool   `yaml:"no_color"`
-}
-
-func (c *Log) UnmarshalYAML(unmarshal func(interface{}) error) error {
-	type plain Log
-	err := unmarshal((*plain)(c))
-	if err != nil {
-		return err
-	}
-	if c.Level == "" {
-		c.Level = "info"
-	}
-	if c.Format == "" {
-		c.Format = "text"
-	}
-	// Validate log level
-	_, err = logrus.ParseLevel(c.Level)
-	if err != nil {
-		return errors.NewConfigError("log.level", err)
-	}
-	return nil
-}
-
-type Storage struct {
-	Endpoint        string `yaml:"endpoint"`
-	AccessKeyID     string `yaml:"access_key_id"`
-	SecretAccessKey string `yaml:"secret_access_key"`
-	UseSSL          bool   `yaml:"use_ssl"`
-	BucketName      string `yaml:"bucket_name"`
-}
-
-func (c *Storage) UnmarshalYAML(unmarshal func(interface{}) error) error {
-	type plain Storage
-	err := unmarshal((*plain)(c))
-	if err != nil {
-		return err
-	}
-	if c.Endpoint == "" {
-		return errors.NewConfigError("storage.endpoint", errors.ErrInvalidInput)
-	}
-	if c.AccessKeyID == "" {
-		return errors.NewConfigError("storage.access_key_id", errors.ErrInvalidInput)
-	}
-	if c.SecretAccessKey == "" {
-		return errors.NewConfigError("storage.secret_access_key", errors.ErrInvalidInput)
-	}
-	if c.BucketName == "" {
-		return errors.NewConfigError("storage.bucket_name", errors.ErrInvalidInput)
-	}
-	return nil
-}
-
 type CloudComputing struct {
 	Provider    string `yaml:"provider"`
 	Region      string `yaml:"region"`
@@ -244,5 +144,28 @@ func ReadConfig(configPath string) (*Config, error) {
 		return nil, errors.NewConfigError("parse", err)
 	}
 
+	// Validate all config sections that implement Validator interface
+	validators := []Validator{}
+
+	if config.Storage != nil {
+		validators = append(validators, config.Storage)
+	}
+	if config.Database != nil {
+		validators = append(validators, config.Database)
+	}
+	if config.Log != nil {
+		validators = append(validators, config.Log)
+	}
+	if config.Server != nil {
+		validators = append(validators, config.Server)
+	}
+	if config.Auth != nil {
+		validators = append(validators, config.Auth)
+	}
+
+	if err := ValidateAll(validators...); err != nil {
+		return nil, err
+	}
+
 	return config, nil
 }

+ 16 - 0
pkg/config/validator.go

@@ -0,0 +1,16 @@
+package config
+
+// Validator defines the interface for config validation
+type Validator interface {
+	Validate() error
+}
+
+// ValidateAll validates multiple configs at once
+func ValidateAll(configs ...Validator) error {
+	for _, cfg := range configs {
+		if err := cfg.Validate(); err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 29 - 0
pkg/database/config.go

@@ -0,0 +1,29 @@
+package database
+
+import "git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
+
+// Config holds the database configuration
+type Config struct {
+	Path            string   `yaml:"path"`
+	MaxOpenConns    int      `yaml:"max_open_conns"`
+	MaxIdleConns    int      `yaml:"max_idle_conns"`
+	ConnMaxLifetime int      `yaml:"conn_max_lifetime"`
+	Pragmas         []string `yaml:"pragmas"`
+}
+
+// Validate implements the config.Validator interface
+func (c *Config) Validate() error {
+	if c.Path == "" {
+		return errors.NewConfigError("database.path", errors.ErrInvalidInput)
+	}
+	if c.MaxOpenConns == 0 {
+		c.MaxOpenConns = 1 // SQLite recommendation
+	}
+	if c.MaxIdleConns == 0 {
+		c.MaxIdleConns = 1
+	}
+	if c.ConnMaxLifetime == 0 {
+		c.ConnMaxLifetime = 300 // 5 minutes
+	}
+	return nil
+}

+ 15 - 7
pkg/database/sqlite.go

@@ -2,16 +2,13 @@ package database
 
 import (
 	"database/sql"
+	"time"
 
 	"git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
 	_ "github.com/mattn/go-sqlite3"
 )
 
-type SQLiteConfig struct {
-	Path string
-}
-
-func NewSQLiteDB(config SQLiteConfig) (*sql.DB, error) {
+func NewSQLiteDB(config *Config) (*sql.DB, error) {
 	db, err := sql.Open("sqlite3", config.Path)
 	if err != nil {
 		return nil, errors.NewDatabaseError("open", err)
@@ -23,8 +20,19 @@ func NewSQLiteDB(config SQLiteConfig) (*sql.DB, error) {
 	}
 
 	// Set connection pool settings
-	db.SetMaxOpenConns(1) // SQLite supports only one writer at a time
-	db.SetMaxIdleConns(1)
+	db.SetMaxOpenConns(config.MaxOpenConns)
+	db.SetMaxIdleConns(config.MaxIdleConns)
+	db.SetConnMaxLifetime(time.Duration(config.ConnMaxLifetime) * time.Second)
+
+	// Apply pragmas if specified
+	if len(config.Pragmas) > 0 {
+		for _, pragma := range config.Pragmas {
+			_, err := db.Exec(pragma)
+			if err != nil {
+				return nil, errors.NewDatabaseError("pragma", err)
+			}
+		}
+	}
 
 	return db, nil
 }

+ 29 - 0
pkg/logger/config.go

@@ -0,0 +1,29 @@
+package logger
+
+import (
+	"git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
+	"github.com/sirupsen/logrus"
+)
+
+// Config holds the logger configuration
+type Config struct {
+	Level   string `yaml:"level"`
+	Format  string `yaml:"format"` // "json" or "text"
+	NoColor bool   `yaml:"no_color"`
+}
+
+// Validate implements the config.Validator interface
+func (c *Config) Validate() error {
+	if c.Level == "" {
+		c.Level = "info"
+	}
+	if c.Format == "" {
+		c.Format = "text"
+	}
+	// Validate log level
+	_, err := logrus.ParseLevel(c.Level)
+	if err != nil {
+		return errors.NewConfigError("log.level", err)
+	}
+	return nil
+}

+ 1 - 2
pkg/logger/logrus.go

@@ -3,12 +3,11 @@ package logger
 import (
 	"os"
 
-	"git.linuxforward.com/byom/byom-golang-lib/pkg/config"
 	"git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
 
-func NewLogger(config *config.Log) (*logrus.Logger, error) {
+func NewLogger(config *Config) (*logrus.Logger, error) {
 	logger := logrus.New()
 
 	// Set output

+ 29 - 0
pkg/server/config.go

@@ -0,0 +1,29 @@
+package server
+
+import "time"
+
+// Config holds the server configuration
+type Config struct {
+	Port           int           `yaml:"port"`
+	RequestTimeout time.Duration `yaml:"request_timeout"` // in seconds
+	AllowedOrigins []string      `yaml:"allowed_origins"`
+}
+
+// Validate implements the config.Validator interface
+func (c *Config) Validate() error {
+	if c.Port == 0 {
+		c.Port = 8080
+	}
+	if c.RequestTimeout == 0 {
+		c.RequestTimeout = 30 * time.Second
+	}
+	return nil
+}
+
+// ToServerConfig converts Config to ServerConfig for internal use
+func (c *Config) ToServerConfig() ServerConfig {
+	return ServerConfig{
+		AllowedOrigins: c.AllowedOrigins,
+		RequestTimeout: c.RequestTimeout,
+	}
+}

+ 2 - 2
pkg/server/gin.go

@@ -19,7 +19,7 @@ type Server struct {
 	config ServerConfig
 }
 
-func NewGinServer(logger *logrus.Logger, config ServerConfig) (*Server, error) {
+func NewGinServer(logger *logrus.Logger, config *Config) (*Server, error) {
 	if logger == nil {
 		return nil, errors.NewConfigError("server", errors.ErrInvalidInput)
 	}
@@ -33,7 +33,7 @@ func NewGinServer(logger *logrus.Logger, config ServerConfig) (*Server, error) {
 	server := &Server{
 		router: router,
 		logger: logger,
-		config: config,
+		config: config.ToServerConfig(),
 	}
 
 	// Add middleware in specific order

+ 29 - 0
pkg/storage/config.go

@@ -0,0 +1,29 @@
+package storage
+
+import "git.linuxforward.com/byom/byom-golang-lib/pkg/errors"
+
+// Config holds the storage configuration
+type Config struct {
+	Endpoint        string `yaml:"endpoint"`
+	AccessKeyID     string `yaml:"access_key_id"`
+	SecretAccessKey string `yaml:"secret_access_key"`
+	UseSSL          bool   `yaml:"use_ssl"`
+	BucketName      string `yaml:"bucket_name"`
+}
+
+// Validate implements the config.Validator interface
+func (c *Config) Validate() error {
+	if c.Endpoint == "" {
+		return errors.NewConfigError("storage.endpoint", errors.ErrInvalidInput)
+	}
+	if c.AccessKeyID == "" {
+		return errors.NewConfigError("storage.access_key_id", errors.ErrInvalidInput)
+	}
+	if c.SecretAccessKey == "" {
+		return errors.NewConfigError("storage.secret_access_key", errors.ErrInvalidInput)
+	}
+	if c.BucketName == "" {
+		return errors.NewConfigError("storage.bucket_name", errors.ErrInvalidInput)
+	}
+	return nil
+}

+ 1 - 9
pkg/storage/minio.go

@@ -9,20 +9,12 @@ import (
 	"github.com/minio/minio-go/v7/pkg/credentials"
 )
 
-type MinioConfig struct {
-	Endpoint        string
-	AccessKeyID     string
-	SecretAccessKey string
-	UseSSL          bool
-	BucketName      string
-}
-
 type MinioClient struct {
 	client     *minio.Client
 	bucketName string
 }
 
-func NewMinioClient(config MinioConfig) (*MinioClient, error) {
+func NewMinioClient(config *Config) (*MinioClient, error) {
 	if config.Endpoint == "" {
 		return nil, errors.NewStorageError("initialize", "", errors.ErrInvalidInput)
 	}