refactor: Flatten directory structure
Move project files from uzdb/ subdirectory to root directory for cleaner project structure.
Changes:
- Move frontend/ to root
- Move internal/ to root
- Move build/ to root
- Move all config files (go.mod, wails.json, etc.) to root
- Remove redundant uzdb/ subdirectory nesting
Project structure is now:
├── frontend/ # React application
├── internal/ # Go backend
├── build/ # Wails build assets
├── doc/ # Design documentation
├── main.go # Entry point
└── ...
🤖 Generated with Qoder
This commit is contained in:
261
internal/config/config.go
Normal file
261
internal/config/config.go
Normal file
@@ -0,0 +1,261 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// Environment represents the application environment type
|
||||
type Environment string
|
||||
|
||||
const (
|
||||
// EnvDevelopment represents development environment
|
||||
EnvDevelopment Environment = "development"
|
||||
// EnvProduction represents production environment
|
||||
EnvProduction Environment = "production"
|
||||
)
|
||||
|
||||
// Config holds all configuration for the application
|
||||
type Config struct {
|
||||
// App settings
|
||||
AppName string `json:"app_name"`
|
||||
Version string `json:"version"`
|
||||
Environment Environment `json:"environment"`
|
||||
|
||||
// Database settings (SQLite for app data)
|
||||
Database DatabaseConfig `json:"database"`
|
||||
|
||||
// Encryption settings
|
||||
Encryption EncryptionConfig `json:"encryption"`
|
||||
|
||||
// Logger settings
|
||||
Logger LoggerConfig `json:"logger"`
|
||||
|
||||
// API settings (for debug HTTP server)
|
||||
API APIConfig `json:"api"`
|
||||
|
||||
// File paths
|
||||
DataDir string `json:"-"`
|
||||
}
|
||||
|
||||
// DatabaseConfig holds database configuration
|
||||
type DatabaseConfig struct {
|
||||
// SQLite database file path for app data
|
||||
SQLitePath string `json:"sqlite_path"`
|
||||
// Max open connections
|
||||
MaxOpenConns int `json:"max_open_conns"`
|
||||
// Max idle connections
|
||||
MaxIdleConns int `json:"max_idle_conns"`
|
||||
// Connection max lifetime in minutes
|
||||
MaxLifetime int `json:"max_lifetime"`
|
||||
}
|
||||
|
||||
// EncryptionConfig holds encryption configuration
|
||||
type EncryptionConfig struct {
|
||||
// Key for encrypting sensitive data (passwords, etc.)
|
||||
// In production, this should be loaded from secure storage
|
||||
Key string `json:"-"`
|
||||
// KeyFile path to load encryption key from
|
||||
KeyFile string `json:"key_file"`
|
||||
}
|
||||
|
||||
// LoggerConfig holds logger configuration
|
||||
type LoggerConfig struct {
|
||||
// Log level: debug, info, warn, error
|
||||
Level string `json:"level"`
|
||||
// Log format: json, console
|
||||
Format string `json:"format"`
|
||||
// Output file path (empty for stdout)
|
||||
OutputPath string `json:"output_path"`
|
||||
}
|
||||
|
||||
// APIConfig holds HTTP API configuration
|
||||
type APIConfig struct {
|
||||
// Enable HTTP API server (for debugging)
|
||||
Enabled bool `json:"enabled"`
|
||||
// Port for HTTP API server
|
||||
Port string `json:"port"`
|
||||
}
|
||||
|
||||
var (
|
||||
instance *Config
|
||||
once sync.Once
|
||||
logger *zap.Logger
|
||||
)
|
||||
|
||||
// Get returns the singleton config instance
|
||||
func Get() *Config {
|
||||
return instance
|
||||
}
|
||||
|
||||
// GetLogger returns the zap logger
|
||||
func GetLogger() *zap.Logger {
|
||||
return logger
|
||||
}
|
||||
|
||||
// Init initializes the configuration
|
||||
// If config file doesn't exist, creates default config
|
||||
func Init(dataDir string) (*Config, error) {
|
||||
var err error
|
||||
once.Do(func() {
|
||||
instance = &Config{
|
||||
DataDir: dataDir,
|
||||
}
|
||||
err = instance.load(dataDir)
|
||||
})
|
||||
return instance, err
|
||||
}
|
||||
|
||||
// load loads configuration from file or creates default
|
||||
func (c *Config) load(dataDir string) error {
|
||||
configPath := filepath.Join(dataDir, "config.json")
|
||||
|
||||
// Try to load existing config
|
||||
if _, err := os.Stat(configPath); err == nil {
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Create default config
|
||||
c.setDefaults()
|
||||
if err := c.save(configPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Override with environment variables
|
||||
c.loadEnv()
|
||||
|
||||
// Initialize logger
|
||||
if err := c.initLogger(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("configuration loaded",
|
||||
zap.String("environment", string(c.Environment)),
|
||||
zap.String("data_dir", c.DataDir),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setDefaults sets default configuration values
|
||||
func (c *Config) setDefaults() {
|
||||
c.AppName = "uzdb"
|
||||
c.Version = "1.0.0"
|
||||
c.Environment = EnvDevelopment
|
||||
|
||||
c.Database = DatabaseConfig{
|
||||
SQLitePath: filepath.Join(c.DataDir, "uzdb.db"),
|
||||
MaxOpenConns: 25,
|
||||
MaxIdleConns: 5,
|
||||
MaxLifetime: 5,
|
||||
}
|
||||
|
||||
c.Encryption = EncryptionConfig{
|
||||
Key: "", // Will be generated if empty
|
||||
KeyFile: filepath.Join(c.DataDir, "encryption.key"),
|
||||
}
|
||||
|
||||
c.Logger = LoggerConfig{
|
||||
Level: "debug",
|
||||
Format: "console",
|
||||
OutputPath: "",
|
||||
}
|
||||
|
||||
c.API = APIConfig{
|
||||
Enabled: true,
|
||||
Port: "8080",
|
||||
}
|
||||
}
|
||||
|
||||
// loadEnv loads configuration from environment variables
|
||||
func (c *Config) loadEnv() {
|
||||
if env := os.Getenv("UZDB_ENV"); env != "" {
|
||||
c.Environment = Environment(env)
|
||||
}
|
||||
|
||||
if port := os.Getenv("UZDB_API_PORT"); port != "" {
|
||||
c.API.Port = port
|
||||
}
|
||||
|
||||
if logLevel := os.Getenv("UZDB_LOG_LEVEL"); logLevel != "" {
|
||||
c.Logger.Level = logLevel
|
||||
}
|
||||
|
||||
if dbPath := os.Getenv("UZDB_DB_PATH"); dbPath != "" {
|
||||
c.Database.SQLitePath = dbPath
|
||||
}
|
||||
}
|
||||
|
||||
// save saves configuration to file
|
||||
func (c *Config) save(path string) error {
|
||||
data, err := json.MarshalIndent(c, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0600)
|
||||
}
|
||||
|
||||
// initLogger initializes the zap logger
|
||||
func (c *Config) initLogger() error {
|
||||
var cfg zap.Config
|
||||
|
||||
switch c.Logger.Format {
|
||||
case "json":
|
||||
cfg = zap.NewProductionConfig()
|
||||
default:
|
||||
cfg = zap.NewDevelopmentConfig()
|
||||
}
|
||||
|
||||
// Set log level
|
||||
level, parseErr := zapcore.ParseLevel(c.Logger.Level)
|
||||
if parseErr != nil {
|
||||
level = zapcore.InfoLevel
|
||||
}
|
||||
cfg.Level.SetLevel(level)
|
||||
|
||||
// Configure output
|
||||
if c.Logger.OutputPath != "" {
|
||||
cfg.OutputPaths = []string{c.Logger.OutputPath}
|
||||
cfg.ErrorOutputPaths = []string{c.Logger.OutputPath}
|
||||
}
|
||||
|
||||
var buildErr error
|
||||
logger, buildErr = cfg.Build(
|
||||
zap.AddCaller(),
|
||||
zap.AddStacktrace(zapcore.ErrorLevel),
|
||||
)
|
||||
if buildErr != nil {
|
||||
return buildErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsDevelopment returns true if running in development mode
|
||||
func (c *Config) IsDevelopment() bool {
|
||||
return c.Environment == EnvDevelopment
|
||||
}
|
||||
|
||||
// IsProduction returns true if running in production mode
|
||||
func (c *Config) IsProduction() bool {
|
||||
return c.Environment == EnvProduction
|
||||
}
|
||||
|
||||
// Sync flushes any buffered log entries
|
||||
func Sync() error {
|
||||
if logger != nil {
|
||||
return logger.Sync()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user