Files
nl-blogs/server/config/config.go
李琦 4f4153ee0e 1. 小程序端
2. 视频优化
2026-07-30 14:11:26 +08:00

162 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package config
import (
"bytes"
"fmt"
"log"
"os"
"path/filepath"
"github.com/joho/godotenv"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
// JWTSecret is the secret key used for signing JWT tokens
var JWTSecret = "your-secret-key" // Default value, should be set via JWT_SECRET environment variable in production
// utf8BOM 用于剥离 Windows 编辑器常写入的 UTF-8 BOM否则 godotenv 会解析失败
var utf8BOM = []byte{0xEF, 0xBB, 0xBF}
// tryLoadEnv 尝试加载指定路径的 .env成功则记录日志并返回 true。
// 会先去掉 UTF-8 BOM再按 godotenv 默认语义:不覆盖已存在的 OS 环境变量。
func tryLoadEnv(path string) bool {
if path == "" {
return false
}
raw, err := os.ReadFile(path)
if err != nil {
return false
}
raw = bytes.TrimPrefix(raw, utf8BOM)
envMap, err := godotenv.Parse(bytes.NewReader(raw))
if err != nil {
log.Printf("Warning: found .env at %s but failed to parse: %v", path, err)
return false
}
applied := 0
for k, v := range envMap {
if os.Getenv(k) == "" {
_ = os.Setenv(k, v)
applied++
}
}
log.Printf("Loaded .env file from %s (%d keys applied)", path, applied)
return true
}
// collectEnvCandidates 收集候选 .env 路径可执行文件旁、cwd、cwd/server、向上 3 级
func collectEnvCandidates() []string {
seen := map[string]struct{}{}
var list []string
add := func(p string) {
abs, err := filepath.Abs(p)
if err != nil {
abs = p
}
if _, ok := seen[abs]; ok {
return
}
seen[abs] = struct{}{}
list = append(list, abs)
}
if execPath, err := os.Executable(); err == nil {
add(filepath.Join(filepath.Dir(execPath), ".env"))
} else {
log.Printf("Warning: Failed to get executable path: %v", err)
}
cwd, err := os.Getwd()
if err != nil {
log.Printf("Warning: Failed to get working directory: %v", err)
cwd = "."
}
add(filepath.Join(cwd, ".env"))
add(filepath.Join(cwd, "server", ".env")) // 从仓库根启动时
// 向上最多 3 级父目录查找 .env 与 server/.env
dir := cwd
for i := 0; i < 3; i++ {
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
add(filepath.Join(dir, ".env"))
add(filepath.Join(dir, "server", ".env"))
}
return list
}
// LoadEnvFile 依次尝试多个路径加载 .env后加载补缺不覆盖已有 OS 环境变量)
func LoadEnvFile() {
loadedPaths := []string{}
for _, p := range collectEnvCandidates() {
if tryLoadEnv(p) {
loadedPaths = append(loadedPaths, p)
}
}
if len(loadedPaths) == 0 {
log.Println("Info: no .env loaded; relying on process environment variables")
} else {
log.Printf("Env load summary: %d file(s) loaded", len(loadedPaths))
}
appID := os.Getenv("WECHAT_APP_ID")
secret := os.Getenv("WECHAT_APP_SECRET")
log.Printf(
"WeChat env: APP_ID_set=%v SECRET_set=%v",
appID != "",
secret != "",
)
}
func InitDB() {
var err error
// Try to get DSN from environment variable, otherwise use default
dsn := os.Getenv("DB_DSN")
if dsn == "" {
dsn = "root:root@tcp(127.0.0.1:3306)/nl_blog?charset=utf8mb4&parseTime=True&loc=Local"
//dsn = "root:mysql_PKC65h@tcp(127.0.0.1:3306)/nl_blog?charset=utf8mb4&parseTime=True&loc=Local"
}
// Try to get JWT secret from environment variable
if secret := os.Getenv("JWT_SECRET"); secret != "" {
JWTSecret = secret
}
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent), // 禁用 GORM 日志,使用自定义日志
// 不使用 NowFunc因为我们使用模型钩子手动处理 int64 时间戳
})
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
sqlDB, err := DB.DB()
if err != nil {
log.Fatal("Failed to get underlying sql.DB:", err)
}
if err = sqlDB.Ping(); err != nil {
log.Fatal("Failed to ping database:", err)
}
fmt.Println("Database connected successfully")
}
func CloseDB() {
if DB != nil {
sqlDB, err := DB.DB()
if err == nil {
sqlDB.Close()
}
}
}