Files
gemini-banlancer/internal/app/app.go
2025-11-20 12:24:05 +08:00

143 lines
4.2 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.
// Filename: internal/app/app.go
package app
import (
"context"
"fmt"
"gemini-balancer/internal/config"
"gemini-balancer/internal/crypto"
"gemini-balancer/internal/db/migrations"
"gemini-balancer/internal/db/seeder"
"gemini-balancer/internal/scheduler"
"gemini-balancer/internal/service"
"gemini-balancer/internal/settings"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)
// App
type App struct {
Config *config.Config
Router *gin.Engine
DB *gorm.DB
Logger *logrus.Logger
CryptoService *crypto.Service
// 拥有独立生命周期的后台服务
ResourceService *service.ResourceService
APIKeyService *service.APIKeyService
DBLogWriter *service.DBLogWriterService
AnalyticsService *service.AnalyticsService
HealthCheckService *service.HealthCheckService
SettingsManager *settings.SettingsManager
GroupManager *service.GroupManager
TokenManager *service.TokenManager
Scheduler *scheduler.Scheduler
}
// NewApp
func NewApp(
cfg *config.Config,
router *gin.Engine,
db *gorm.DB,
logger *logrus.Logger,
cryptoService *crypto.Service,
resourceService *service.ResourceService,
apiKeyService *service.APIKeyService,
dbLogWriter *service.DBLogWriterService,
analyticsService *service.AnalyticsService,
healthCheckService *service.HealthCheckService,
settingsManager *settings.SettingsManager,
groupManager *service.GroupManager,
tokenManager *service.TokenManager,
scheduler *scheduler.Scheduler,
) *App {
return &App{
Config: cfg,
Router: router,
DB: db,
Logger: logger,
CryptoService: cryptoService,
ResourceService: resourceService,
APIKeyService: apiKeyService,
DBLogWriter: dbLogWriter,
AnalyticsService: analyticsService,
HealthCheckService: healthCheckService,
SettingsManager: settingsManager,
GroupManager: groupManager,
TokenManager: tokenManager,
Scheduler: scheduler,
}
}
// Run 启动流程现在由App主动编排而非被动接受
func (a *App) Run() error {
// --- 阶段一: (数据库设置) ---
a.Logger.Info("* [SYSTEM] * Preparing: Database Setup ...")
// 步骤 1: (运行基础迁移,确保表存在)
if err := migrations.RunMigrations(a.DB, a.Logger); err != nil {
return fmt.Errorf("initial database migration failed: %w", err)
}
// 步骤 2: (运行所有版本化的数据迁移)
if err := migrations.RunVersionedMigrations(a.DB, a.Config, a.Logger); err != nil {
return fmt.Errorf("failed to run versioned migrations: %w", err)
}
// 步骤 3: (数据播种)
seeder.RunSeeder(a.DB, a.CryptoService, a.Logger)
a.Logger.Info("* [SYSTEM] * All Uitls READY. ---")
// --- 阶段二: (启动后台服务) ---
a.Logger.Info("* [SYSTEM] * Starting main: Background Services ")
a.APIKeyService.Start()
a.DBLogWriter.Start()
a.AnalyticsService.Start()
a.HealthCheckService.Start()
a.Scheduler.Start()
a.Logger.Info("* [SYSTEM] * All Background Services are RUNNING. ")
// --- 阶段三: (优雅关机) ---
defer a.Scheduler.Stop()
defer a.HealthCheckService.Stop()
defer a.AnalyticsService.Stop()
defer a.APIKeyService.Stop()
defer a.DBLogWriter.Stop()
defer a.SettingsManager.Stop()
defer a.TokenManager.Stop()
// --- 阶段四: (HTTP服务器) ---
serverAddr := fmt.Sprintf("0.0.0.0:%s", a.Config.Server.Port)
srv := &http.Server{
Addr: serverAddr,
Handler: a.Router,
}
go func() {
a.Logger.Infof("* [SYSTEM] * HTTP Server Now Listening on %s ", serverAddr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
a.Logger.Fatalf("HTTP server listen error: %s\n", err)
}
}()
// --- 阶段五: (处理关机信号) ---
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
a.Logger.Info("* [SYSTEM] * Shutdown signal received. Executing strategic retreat...")
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
a.Logger.Fatal("Server forced to shutdown:", err)
}
a.Logger.Info("* [SYSTEM] * All units have ceased operations. Mission complete. ")
return nil
}