Some checks failed
CI / Build & Test (push) Failing after 1m31s
- Add user management endpoints (list/create/get/update/delete) with pagination and search - Add dashboard stats endpoint with tenant/user/online counts and growth metrics - Add tenant resolver middleware for multi-tenant request scoping - Add i18n kernel with zh/en message files and AcceptLanguage middleware - Add WebSocket hub/handler for real-time communication - Add job scheduler kernel with cron support - Add plugin sandbox for isolated execution - Add storage kernel (local filesystem) - Add event bus kernel for pub/sub - Add cache kernel abstraction - Add database migration runner and version upgrade checker - Add rate limiting middleware with Redis backend - Add SQL migrations for rbac, audit_logs, settings, notifications, examples - Extend user repository with list/delete/count operations - Register all module routes with tenant resolver
131 lines
3.5 KiB
Go
131 lines
3.5 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
type Config struct {
|
|
Server ServerConfig `mapstructure:"server"`
|
|
Database DatabaseConfig `mapstructure:"database"`
|
|
Redis RedisConfig `mapstructure:"redis"`
|
|
JWT JWTConfig `mapstructure:"jwt"`
|
|
Log LogConfig `mapstructure:"log"`
|
|
Plugin PluginConfig `mapstructure:"plugin"`
|
|
Tenant TenantConfig `mapstructure:"tenant"`
|
|
Storage StorageConfig `mapstructure:"storage"`
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Port int `mapstructure:"port"`
|
|
Mode string `mapstructure:"mode"`
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
User string `mapstructure:"user"`
|
|
Password string `mapstructure:"password"`
|
|
DBName string `mapstructure:"dbname"`
|
|
SSLMode string `mapstructure:"sslmode"`
|
|
}
|
|
|
|
type RedisConfig struct {
|
|
Addr string `mapstructure:"addr"`
|
|
Password string `mapstructure:"password"`
|
|
DB int `mapstructure:"db"`
|
|
}
|
|
|
|
type JWTConfig struct {
|
|
Secret string `mapstructure:"secret"`
|
|
AccessExpiryMinutes int `mapstructure:"access_expiry_minutes"`
|
|
RefreshExpiryDays int `mapstructure:"refresh_expiry_days"`
|
|
Issuer string `mapstructure:"issuer"`
|
|
}
|
|
|
|
type LogConfig struct {
|
|
Level string `mapstructure:"level"`
|
|
Format string `mapstructure:"format"`
|
|
}
|
|
|
|
type PluginConfig struct {
|
|
Enabled []string `mapstructure:"enabled"`
|
|
}
|
|
|
|
type TenantConfig struct {
|
|
Mode string `mapstructure:"mode"`
|
|
DefaultID string `mapstructure:"default_id"`
|
|
}
|
|
|
|
type StorageConfig struct {
|
|
Driver string `mapstructure:"driver"`
|
|
RootDir string `mapstructure:"root_dir"`
|
|
BaseURL string `mapstructure:"base_url"`
|
|
}
|
|
|
|
func Load() (*Config, error) {
|
|
v := viper.New()
|
|
v.SetConfigName("config")
|
|
v.SetConfigType("yaml")
|
|
v.AddConfigPath("./configs/")
|
|
v.AddConfigPath(".")
|
|
|
|
v.SetEnvPrefix("MENGSTACK")
|
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
v.AutomaticEnv()
|
|
|
|
setDefaults(v)
|
|
|
|
if err := v.ReadInConfig(); err != nil {
|
|
return nil, fmt.Errorf("failed to read config: %w", err)
|
|
}
|
|
|
|
// Check env var for mode override before merging env config
|
|
env := v.GetString("server.mode")
|
|
if envOverride := os.Getenv("MENGSTACK_SERVER_MODE"); envOverride != "" {
|
|
env = envOverride
|
|
}
|
|
mergeEnvConfig(v, env)
|
|
|
|
var cfg Config
|
|
if err := v.Unmarshal(&cfg); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
|
}
|
|
|
|
return &cfg, nil
|
|
}
|
|
|
|
func setDefaults(v *viper.Viper) {
|
|
v.SetDefault("server.port", 8080)
|
|
v.SetDefault("server.mode", "debug")
|
|
v.SetDefault("database.host", "127.0.0.1")
|
|
v.SetDefault("database.port", 5432)
|
|
v.SetDefault("database.user", "postgres")
|
|
v.SetDefault("database.dbname", "mengstack")
|
|
v.SetDefault("database.sslmode", "disable")
|
|
v.SetDefault("redis.addr", "127.0.0.1:6379")
|
|
v.SetDefault("redis.db", 0)
|
|
v.SetDefault("jwt.access_expiry_minutes", 30)
|
|
v.SetDefault("jwt.refresh_expiry_days", 7)
|
|
v.SetDefault("jwt.issuer", "mengstack")
|
|
v.SetDefault("log.level", "info")
|
|
v.SetDefault("log.format", "json")
|
|
v.SetDefault("tenant.mode", "multi")
|
|
v.SetDefault("tenant.default_id", "00000000-0000-0000-0000-000000000001")
|
|
v.SetDefault("storage.driver", "local")
|
|
v.SetDefault("storage.root_dir", "./uploads")
|
|
v.SetDefault("storage.base_url", "http://localhost:8080")
|
|
}
|
|
|
|
func mergeEnvConfig(v *viper.Viper, env string) {
|
|
envFile := fmt.Sprintf("config.%s", env)
|
|
v.SetConfigName(envFile)
|
|
if err := v.MergeInConfig(); err != nil {
|
|
// environment-specific config is optional
|
|
}
|
|
v.SetConfigName("config")
|
|
}
|