package main import ( "flag" "fmt" "os" "os/signal" "strconv" "syscall" dubboclient "dubbo.apache.org/dubbo-go/v3/client" _ "dubbo.apache.org/dubbo-go/v3/imports" "dubbo.apache.org/dubbo-go/v3/protocol" "dubbo.apache.org/dubbo-go/v3/server" "github.com/topfans/backend/pkg/database" "github.com/topfans/backend/pkg/logger" "github.com/topfans/backend/pkg/models" pbAsset "github.com/topfans/backend/pkg/proto/asset" pbGallery "github.com/topfans/backend/pkg/proto/gallery" pbUser "github.com/topfans/backend/pkg/proto/user" rpcclient "github.com/topfans/backend/services/galleryService/client" "github.com/topfans/backend/services/galleryService/provider" "github.com/topfans/backend/services/galleryService/repository" "github.com/topfans/backend/services/galleryService/service" ) var ( port = flag.Int("port", getEnvInt("PORT", 20001), "Dubbo service port") dbHost = flag.String("db-host", getEnv("DB_HOST", "localhost"), "Database host") dbPort = flag.Int("db-port", getEnvInt("DB_PORT", 5432), "Database port") dbUser = flag.String("db-user", getEnv("DB_USER", "postgres"), "Database user") dbPassword = flag.String("db-password", getEnv("DB_PASSWORD", ""), "Database password") dbName = flag.String("db-name", getEnv("DB_NAME", "top-fans"), "Database name") assetServiceURL = flag.String("asset-service-url", getEnv("ASSET_SERVICE_URL", "tri://localhost:20003"), "Asset service URL") userServiceURL = flag.String("user-service-url", getEnv("USER_SERVICE_URL", "tri://localhost:20000"), "User service URL") ) func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func getEnvInt(key string, fallback int) int { if v := os.Getenv(key); v != "" { if n, err := strconv.Atoi(v); err == nil { return n } } return fallback } func main() { flag.Parse() // 初始化日志(必须在最前面) env := os.Getenv("ENV") if env == "" { env = "development" } if err := logger.Init(logger.Config{ ServiceName: "gallery-service", Environment: env, LogLevel: os.Getenv("LOG_LEVEL"), }); err != nil { panic(fmt.Sprintf("Failed to initialize logger: %v", err)) } defer logger.Sync() logger.Logger.Info("Starting Gallery Service...") // 初始化数据库 dbConfig := database.Config{ Host: *dbHost, Port: *dbPort, User: *dbUser, Password: *dbPassword, DBName: *dbName, SSLMode: "disable", TimeZone: "Asia/Shanghai", } if err := database.Init(dbConfig); err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to initialize database: %v", err)) } logger.Logger.Info("Database initialized successfully") // 创建 Repository 层实例 db := database.GetDB() // 自动迁移展馆相关表(booth_slots / exhibitions) if err := db.AutoMigrate(&models.BoothSlot{}, &models.Exhibition{}); err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to migrate gallery tables: %v", err)) } galleryRepo := repository.NewGalleryRepository(db) logger.Logger.Info("Repository layer initialized") // 创建 Dubbo 客户端 assetCli, err := dubboclient.NewClient( dubboclient.WithClientURL(*assetServiceURL), ) if err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to create Asset Service Dubbo client: %v", err)) } userCli, err := dubboclient.NewClient( dubboclient.WithClientURL(*userServiceURL), ) if err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to create User Service Dubbo client: %v", err)) } // 获取 Asset Service RPC 客户端 assetServiceClient, err := pbAsset.NewAssetService(assetCli) if err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to create Asset Service RPC client: %v", err)) } assetRPCClient := rpcclient.NewAssetRPCClient(assetServiceClient) logger.Logger.Info("Asset Service RPC client initialized") // 获取 User Service RPC 客户端 userServiceClient, err := pbUser.NewUserSocialService(userCli) if err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to create User Service RPC client: %v", err)) } userRPCClient := rpcclient.NewUserRPCClient(userServiceClient) logger.Logger.Info("User Service RPC client initialized") // 创建 Service 层实例 galleryService := service.NewGalleryService(galleryRepo, assetRPCClient, userRPCClient) slotService := service.NewSlotService(galleryRepo, userRPCClient) exhibitionService := service.NewExhibitionService(galleryRepo, assetRPCClient) logger.Logger.Info("Service layer initialized") // 创建并启动清理 Worker(注入 assetRPCClient 以便下架时清除点赞记录) cleanupWorker := service.NewCleanupWorker(galleryRepo, assetRPCClient) go cleanupWorker.Start() logger.Logger.Info("Cleanup worker started") // 创建 Provider 层实例 galleryProvider := provider.NewGalleryProvider(galleryService, slotService, exhibitionService) logger.Logger.Info("Provider layer initialized") // 创建 Dubbo 服务器 srv, err := server.NewServer( server.WithServerProtocol( protocol.WithPort(*port), protocol.WithTriple(), ), ) if err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to create Dubbo server: %v", err)) } // 使用 Triple 协议生成的 RegisterHandler 函数注册服务 if err := pbGallery.RegisterGalleryServiceHandler(srv, galleryProvider); err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to register Gallery Service: %v", err)) } // 启动服务 if err := srv.Serve(); err != nil { logger.Logger.Fatal(fmt.Sprintf("Failed to start Gallery Service: %v", err)) } logger.Logger.Info(fmt.Sprintf("Gallery Service started successfully on port %d", *port)) // 等待退出信号 quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit logger.Logger.Info("Shutting down Gallery Service...") // 停止清理 Worker cleanupWorker.Stop() logger.Logger.Info("Cleanup worker stopped") }