package main import ( "context" "fmt" "net/http" "carrot_bbs/internal/config" "carrot_bbs/internal/grpc/runner" "carrot_bbs/internal/router" "carrot_bbs/internal/service" "go.uber.org/zap" "gorm.io/gorm" ) // App 应用程序结构体 type App struct { Config *config.Config DB *gorm.DB Router *router.Router PushService service.PushService HotRankWorker *service.HotRankWorker GRPCServer *runner.Server Server *http.Server Logger *zap.Logger } // NewApp 创建应用程序 func NewApp( cfg *config.Config, db *gorm.DB, r *router.Router, pushService service.PushService, hotRankWorker *service.HotRankWorker, grpcServer *runner.Server, logger *zap.Logger, ) *App { return &App{ Config: cfg, DB: db, Router: r, PushService: pushService, HotRankWorker: hotRankWorker, GRPCServer: grpcServer, Logger: logger, } } // Start 启动应用程序 func (a *App) Start(ctx context.Context) error { // 1. 启动 gRPC 服务器(在 HTTP 服务器之前) if a.GRPCServer != nil { a.Logger.Info("Starting gRPC server") if err := a.GRPCServer.Start(); err != nil { return fmt.Errorf("failed to start gRPC server: %w", err) } } // 2. 启动推送 Worker a.PushService.StartPushWorker(ctx) // 2.1 热门榜定时重算 if a.HotRankWorker != nil { a.HotRankWorker.Start(ctx) } // 3. 创建 HTTP 服务器 addr := fmt.Sprintf("%s:%d", a.Config.Server.Host, a.Config.Server.Port) a.Logger.Info("Starting HTTP server", zap.String("address", addr), ) a.Server = &http.Server{ Addr: addr, Handler: a.Router.Engine(), } // 4. 启动 HTTP 服务器 go func() { if err := a.Server.ListenAndServe(); err != nil && err != http.ErrServerClosed { a.Logger.Fatal("HTTP server listen error", zap.Error(err), ) } }() return nil } // Stop 停止应用程序 func (a *App) Stop(ctx context.Context) error { a.Logger.Info("Shutting down server") // 1. 停止 HTTP 服务器 if a.Server != nil { a.Logger.Info("Stopping HTTP server") if err := a.Server.Shutdown(ctx); err != nil { a.Logger.Error("HTTP server forced to shutdown", zap.Error(err), ) } } // 2. 停止 gRPC 服务器 if a.GRPCServer != nil { a.Logger.Info("Stopping gRPC server") a.GRPCServer.Stop() } // 3. 停止推送 Worker a.Logger.Info("Stopping push worker") a.PushService.StopPushWorker() if a.HotRankWorker != nil { a.Logger.Info("Stopping hot rank worker") a.HotRankWorker.Stop() } // 4. 关闭数据库连接 a.Logger.Info("Closing database connection") sqlDB, err := a.DB.DB() if err == nil { sqlDB.Close() } a.Logger.Info("Server exited") return nil }