Init commit.

Add: simple project structure for `mygo.server`.

Add: README files.
This commit is contained in:
2025-06-20 16:45:01 +08:00
commit c737ff24d8
11 changed files with 534 additions and 0 deletions

View File

@ -0,0 +1,3 @@
package app
const Version = "0.0.1"

View File

@ -0,0 +1,117 @@
package config
import (
"fmt"
"strings"
"github.com/spf13/viper"
)
type ServerConfig struct {
Server struct {
Listen string `mapstructure:"listen"`
Port string `mapstructure:"port"`
} `mapstructure:"server"`
Database struct {
Type string `mapstructure:"type"`
Host string `mapstructure:"host"`
// Port int `mapstructure:"port"`
// User string `mapstructure:"user"`
} `mapstructure:"database"`
Auth struct {
JWTSecret string `mapstructure:"jwt_secret"`
} `mapstructure:"auth"`
Storage struct {
Type string `mapstructure:"type"`
Local struct {
RootDir string `mapstructure:"root_dir"`
} `mapstructure:"local"`
S3 struct {
Endpoint string `mapstructure:"endpoint"`
Bucket string `mapstructure:"bucket"`
} `mapstructure:"s3"`
} `mapstructure:"storage"`
}
func setDefaultConfig(v *viper.Viper) {
}
// Bind Environment Variables to config
func bindEnvVariables(v *viper.Viper) {
// 设置环境变量前缀
v.SetEnvPrefix("MYGO")
// 使viper能够从环境变量读取配置
v.AutomaticEnv()
// 将环境变量中的下划线转换为点如MYGO_SERVER_PORT对应server.port
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
// 明确绑定特定环境变量
// v.BindEnv("server.host", "MYGO_SERVER_HOST")
// v.BindEnv("server.port", "MYGO_SERVER_PORT")
// v.BindEnv("database.host", "MYGO_DB_HOST")
// v.BindEnv("database.port", "MYGO_DB_PORT")
// v.BindEnv("database.user", "MYGO_DB_USER")
// v.BindEnv("database.password", "MYGO_DB_PASSWORD")
}
// parseConfig unmarshals viper config into ServerConfig
func parseConfig(v *viper.Viper) (*ServerConfig, error) {
config := &ServerConfig{}
if err := v.Unmarshal(config); err != nil {
return nil, fmt.Errorf("failed to parse config: %w", err)
}
return config, nil
}
// Load config file
func loadConfigFile(v *viper.Viper, configPath string) (*ServerConfig, error) {
v.SetConfigType("yaml")
if configPath != "" {
v.SetConfigFile(configPath)
if err := v.ReadInConfig(); err != nil {
return nil, fmt.Errorf("failed to load config file %s: %w", configPath, err)
}
return parseConfig(v)
}
v.SetConfigName("config")
configPaths := []string{".", "./config"}
for _, path := range configPaths {
v.AddConfigPath(path)
}
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
return nil, nil // No config file found is not an error
}
return nil, fmt.Errorf("config file read error: %w", err)
}
return parseConfig(v)
}
// LoadConfig is the main entry point for configuration loading
func LoadConfig(configPath string) (*ServerConfig, error) {
v := viper.New()
setDefaultConfig(v)
fileConfig, err := loadConfigFile(v, configPath)
if err != nil {
return nil, err
}
if fileConfig != nil {
fmt.Printf("Loaded config from %s\n", v.ConfigFileUsed())
} else {
fmt.Println("Using default configuration (no config file found)")
}
bindEnvVariables(v)
return parseConfig(v)
}