feat: Go 重写后端,替换 Python FastAPI
用 Go (Gin + GORM + SQLite) 重写整个后端: - 单二进制部署,不依赖 Python/pip/SDK - net/http 原生客户端,无 Cloudflare TLS 指纹问题 - 多阶段 Dockerfile:Node 构建前端 + Go 构建后端 + Alpine 运行 - 内存占用从 ~95MB 降至 ~3MB - 完整保留所有 API 路由、JWT 认证、API Key 权限、审计日志
This commit is contained in:
74
config/config.go
Normal file
74
config/config.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
AdminUsername string
|
||||
AdminPassword string
|
||||
SecretKey string
|
||||
JWTExpireMinutes int
|
||||
DatabaseURL string
|
||||
Port string
|
||||
}
|
||||
|
||||
var Cfg Config
|
||||
|
||||
func Load() {
|
||||
// Load .env file from multiple locations (ignore errors if not found)
|
||||
_ = godotenv.Load()
|
||||
_ = godotenv.Load("backend/.env")
|
||||
|
||||
dbURL := getEnv("DATABASE_URL", "data/airwallex.db")
|
||||
// Strip sqlite:/// prefix if present (Python SQLAlchemy format)
|
||||
for _, prefix := range []string{"sqlite:///./", "sqlite:///", "sqlite://"} {
|
||||
if len(dbURL) > len(prefix) && dbURL[:len(prefix)] == prefix {
|
||||
dbURL = dbURL[len(prefix):]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Cfg = Config{
|
||||
AdminUsername: getEnv("ADMIN_USERNAME", "admin"),
|
||||
AdminPassword: getEnv("ADMIN_PASSWORD", "admin123"),
|
||||
SecretKey: getEnv("SECRET_KEY", generateRandomKey(32)),
|
||||
JWTExpireMinutes: getEnvInt("JWT_EXPIRE_MINUTES", 480),
|
||||
DatabaseURL: dbURL,
|
||||
Port: getEnv("PORT", "8000"),
|
||||
}
|
||||
}
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
return val
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func getEnvInt(key string, fallback int) int {
|
||||
val, ok := os.LookupEnv(key)
|
||||
if !ok {
|
||||
return fallback
|
||||
}
|
||||
n, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Printf("warning: invalid integer for %s: %s, using default %d", key, val, fallback)
|
||||
return fallback
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func generateRandomKey(length int) string {
|
||||
b := make([]byte, length)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
log.Fatalf("failed to generate random key: %v", err)
|
||||
}
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
Reference in New Issue
Block a user