201 lines
5.1 KiB
Go
201 lines
5.1 KiB
Go
package main
|
||
|
||
import (
|
||
"errors"
|
||
"flag"
|
||
"fmt"
|
||
"log"
|
||
"net/http"
|
||
"time"
|
||
|
||
"goalfymax-admin/internal/api/routes"
|
||
"goalfymax-admin/internal/config"
|
||
"goalfymax-admin/internal/jobs"
|
||
"goalfymax-admin/internal/models"
|
||
"goalfymax-admin/internal/notifier"
|
||
"goalfymax-admin/internal/services"
|
||
"goalfymax-admin/internal/storage"
|
||
"goalfymax-admin/pkg/middleware"
|
||
"goalfymax-admin/pkg/redis"
|
||
"goalfymax-admin/pkg/utils"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
func main() {
|
||
// 解析命令行参数
|
||
var configPath string
|
||
flag.StringVar(&configPath, "config", "", "配置文件路径(可选,优先级最高)")
|
||
var env string
|
||
flag.StringVar(&env, "env", "dev", "运行环境(dev/test/prod等)")
|
||
flag.Parse()
|
||
|
||
// 加载配置
|
||
// 根据env推导配置文件路径(当未显式指定 --config 时)
|
||
if configPath == "" {
|
||
// 优先匹配 etc/config-<env>.yaml,不存在则回退 etc/config.yaml
|
||
guessed := fmt.Sprintf("etc/config-%s.yaml", env)
|
||
if err := config.LoadConfig(guessed); err != nil {
|
||
// 回退默认
|
||
if err2 := config.LoadConfig("etc/config.yaml"); err2 != nil {
|
||
log.Fatalf("加载配置失败: %v (fallback error: %v)", err, err2)
|
||
}
|
||
}
|
||
} else if err := config.LoadConfig(configPath); err != nil {
|
||
log.Fatalf("加载配置失败: %v", err)
|
||
}
|
||
|
||
cfg := config.GetConfig()
|
||
|
||
// 初始化日志
|
||
logger, err := utils.NewLogger(cfg.Log.Level, cfg.Log.Format, cfg.Log.Output)
|
||
if err != nil {
|
||
log.Fatalf("初始化日志失败: %v", err)
|
||
}
|
||
|
||
logger.Info("应用启动中...")
|
||
|
||
// 初始化通知服务
|
||
notifier.Init(cfg.Alert, env, logger)
|
||
|
||
// 初始化数据库
|
||
if err := storage.InitDatabase(logger); err != nil {
|
||
logger.Fatal("初始化数据库失败", zap.Error(err))
|
||
}
|
||
|
||
// 自动迁移数据库
|
||
if err := storage.AutoMigrate(); err != nil {
|
||
logger.Fatal("数据库迁移失败", zap.Error(err))
|
||
}
|
||
|
||
// 初始化PostgreSQL(用于 MCP 配置)
|
||
if err := storage.InitPostgres(logger); err != nil {
|
||
logger.Warn("PostgreSQL初始化失败,MCP配置将不可用", zap.Error(err))
|
||
} else {
|
||
logger.Info("PostgreSQL初始化完成")
|
||
}
|
||
|
||
logger.Info("数据库初始化完成")
|
||
|
||
// 初始化Redis客户端
|
||
redisClient, err := redis.NewClient(cfg.Redis)
|
||
if err != nil {
|
||
logger.Warn("Redis初始化失败,余额查询功能将不可用", zap.Error(err))
|
||
redisClient = nil // 设置为nil,服务会优雅处理
|
||
} else {
|
||
logger.Info("Redis初始化完成")
|
||
defer redisClient.Close()
|
||
}
|
||
|
||
// 创建服务实例
|
||
ssoAdminService := services.NewSSOAdminService()
|
||
userService := services.NewUserService(
|
||
storage.NewUserStorage(),
|
||
storage.NewRBACStorage(),
|
||
storage.NewGoalfyMaxUserStorage(),
|
||
utils.NewJWTManager("your-jwt-secret"),
|
||
logger,
|
||
ssoAdminService,
|
||
)
|
||
roleService := services.NewRoleService(
|
||
storage.NewRoleStorage(),
|
||
logger,
|
||
)
|
||
pageService := services.NewPageService(
|
||
storage.NewPageStorage(),
|
||
logger,
|
||
)
|
||
|
||
// 创建网关客户端和配额服务
|
||
gatewayClient := services.NewGatewayClient(
|
||
cfg.Gateway.BaseURL,
|
||
time.Duration(cfg.Gateway.Timeout)*time.Second,
|
||
logger,
|
||
)
|
||
quotaService := services.NewQuotaService(gatewayClient, logger)
|
||
|
||
// 创建SSO客户端和SSO服务
|
||
ssoConfig := &models.SSOConfig{
|
||
SSOServerURL: cfg.SSO.SSOServerURL,
|
||
ClientID: cfg.SSO.ClientID,
|
||
ClientSecret: cfg.SSO.ClientSecret,
|
||
RedirectURI: cfg.SSO.RedirectURI,
|
||
Scope: cfg.SSO.Scope,
|
||
ResourceAud: cfg.SSO.ResourceAud,
|
||
Timeout: cfg.SSO.Timeout,
|
||
}
|
||
// 创建RBAC服务
|
||
rbacService := services.NewRBACService(
|
||
storage.NewRBACStorage(),
|
||
storage.NewUserStorage(),
|
||
logger,
|
||
)
|
||
|
||
ssoClient := middleware.NewSSOClient(ssoConfig, logger)
|
||
ssoService := services.NewSSOService(
|
||
ssoClient,
|
||
storage.NewPKCEStateStorage(),
|
||
storage.NewLoginInfoStorage(),
|
||
rbacService,
|
||
logger,
|
||
)
|
||
|
||
// 创建用户等级配置服务
|
||
userLevelConfigService := services.NewUserLevelConfigService(
|
||
storage.NewUserLevelConfigStorage(),
|
||
logger,
|
||
)
|
||
|
||
// 创建系统配置服务
|
||
systemConfigService := services.NewSystemConfigService(
|
||
storage.NewSystemConfigStorage(),
|
||
logger,
|
||
)
|
||
|
||
// 设置路由
|
||
router := routes.SetupRoutes(
|
||
userService,
|
||
roleService,
|
||
pageService,
|
||
quotaService,
|
||
ssoService,
|
||
rbacService,
|
||
userLevelConfigService,
|
||
systemConfigService,
|
||
redisClient,
|
||
logger,
|
||
cfg,
|
||
)
|
||
|
||
// 启动定时任务
|
||
jobs.StartMcpUsageBalanceScheduler(cfg.Jobs.McpUsageBalance, logger)
|
||
jobs.StartModelTokenBalanceScheduler(cfg.Jobs.ModelTokenBalance, logger)
|
||
|
||
// 启动HTTP服务器
|
||
startHTTPServer(cfg, router, logger)
|
||
}
|
||
|
||
// startHTTPServer 启动HTTP服务器
|
||
func startHTTPServer(cfg *config.Config, router *gin.Engine, logger *utils.Logger) {
|
||
// 构建服务器地址
|
||
addr := fmt.Sprintf("%s:%d", cfg.Server.Addr, cfg.Server.Port)
|
||
|
||
// 启动服务器
|
||
server := &http.Server{
|
||
Addr: addr,
|
||
Handler: router,
|
||
ReadTimeout: 15 * time.Second,
|
||
WriteTimeout: 15 * time.Second,
|
||
IdleTimeout: 60 * time.Second,
|
||
}
|
||
|
||
logger.Info("HTTP服务器启动", zap.String("addr", addr))
|
||
logger.Info("应用启动完成")
|
||
|
||
// 启动服务器
|
||
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||
logger.Fatal("HTTP服务器启动失败", zap.Error(err))
|
||
}
|
||
}
|