topfans/backend/services/socialService/main.go
2026-04-07 22:29:48 +08:00

245 lines
6.7 KiB
Go
Raw Permalink 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.

package main
import (
"flag"
"fmt"
"os"
"os/signal"
"strconv"
"syscall"
"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"
pb "github.com/topfans/backend/pkg/proto/social"
pbUser "github.com/topfans/backend/pkg/proto/user"
socialClient "github.com/topfans/backend/services/socialService/client"
"github.com/topfans/backend/services/socialService/provider"
"github.com/topfans/backend/services/socialService/repository"
"github.com/topfans/backend/services/socialService/service"
)
var (
port = flag.Int("port", getEnvInt("PORT", 20002), "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")
userServiceURL = flag.String("user-service-url", getEnv("USER_SERVICE_URL", "tri://localhost:20000"), "User service URL")
assetServiceURL = flag.String("asset-service-url", getEnv("ASSET_SERVICE_URL", "tri://localhost:20003"), "Asset 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: "social-service",
Environment: env,
LogLevel: os.Getenv("LOG_LEVEL"),
}); err != nil {
panic(fmt.Sprintf("Failed to initialize logger: %v", err))
}
defer logger.Sync()
logger.Sugar.Info("Starting Social Service...")
// 初始化数据库
if err := initDatabase(); err != nil {
logger.Sugar.Fatalf("Failed to initialize database: %v", err)
}
// 自动迁移数据库表
if err := autoMigrate(); err != nil {
logger.Sugar.Fatalf("Failed to migrate database: %v", err)
}
// 初始化 Dubbo-go 服务器
if err := initDubboService(); err != nil {
logger.Sugar.Fatalf("Failed to initialize Dubbo service: %v", err)
}
// 等待信号(优雅关闭)
logger.Sugar.Info("Social service started successfully. Press Ctrl+C to exit.")
gracefulShutdown()
}
// initDatabase 初始化数据库连接
func initDatabase() error {
config := database.Config{
Host: *dbHost,
Port: *dbPort,
User: *dbUser,
Password: *dbPassword,
DBName: *dbName,
SSLMode: "disable",
TimeZone: "Asia/Shanghai",
}
return database.Init(config)
}
// autoMigrate 自动迁移数据库表
func autoMigrate() error {
db := database.GetDB()
if db == nil {
return fmt.Errorf("database is not initialized")
}
// 迁移好友相关表
tables := []interface{}{
&models.FriendRequest{},
&models.Friendship{},
}
for _, table := range tables {
if err := db.AutoMigrate(table); err != nil {
return fmt.Errorf("failed to migrate table: %w", err)
}
}
logger.Sugar.Info("Database migration completed successfully")
return nil
}
// gracefulShutdown 优雅关闭
func gracefulShutdown() {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logger.Sugar.Info("Shutting down server...")
// 关闭数据库连接
if err := database.Close(); err != nil {
logger.Sugar.Errorf("Error closing database: %v", err)
}
logger.Sugar.Info("Server exited")
}
// initDubboService 初始化Dubbo-go服务
func initDubboService() error {
db := database.GetDB()
if db == nil {
return fmt.Errorf("database is not initialized")
}
// 创建Repository实例
socialRepo := repository.NewSocialRepository()
// 创建UserService RPC客户端
userServiceClient, err := createUserServiceClient()
if err != nil {
return fmt.Errorf("failed to create user service client: %w", err)
}
// 创建AssetService RPC客户端
assetClient, err := createAssetServiceClient(*assetServiceURL)
if err != nil {
return fmt.Errorf("failed to create asset service client: %w", err)
}
// 创建Service实例
friendService := service.NewFriendService(socialRepo, userServiceClient, db)
assetLikeService := service.NewAssetLikeService(assetClient)
// 创建Provider实例
socialProvider := provider.NewSocialProvider(friendService, assetLikeService)
// 创建 Dubbo Server
srv, err := server.NewServer(
server.WithServerProtocol(
protocol.WithPort(*port),
protocol.WithTriple(),
),
)
if err != nil {
return fmt.Errorf("failed to create Dubbo server: %w", err)
}
// 使用 Triple 协议生成的 RegisterHandler 函数注册服务
if err := pb.RegisterSocialServiceHandler(srv, socialProvider); err != nil {
return fmt.Errorf("failed to register SocialService handler: %w", err)
}
logger.Sugar.Info("Dubbo-go social provider registered successfully",
"service", "topfans.social.SocialService",
"port", *port,
)
// 在后台启动 Dubbo 服务器
go func() {
if err := srv.Serve(); err != nil {
logger.Sugar.Fatalf("Failed to serve Dubbo: %v", err)
}
}()
return nil
}
// createUserServiceClient 创建UserService RPC客户端
func createUserServiceClient() (service.UserServiceClient, error) {
// 创建 Dubbo 客户端(直连模式)
// URL 格式tri://host:port
cli, err := client.NewClient(
client.WithClientURL(*userServiceURL),
)
if err != nil {
return nil, fmt.Errorf("failed to create Dubbo client: %w", err)
}
// 创建 UserSocialService 客户端
// NewUserSocialService 会自动处理接口名称和连接
svc, err := pbUser.NewUserSocialService(cli)
if err != nil {
return nil, fmt.Errorf("failed to create UserSocialService: %w", err)
}
// 创建我们的 RPC 客户端封装
userServiceClient := service.NewUserServiceClient(svc)
logger.Sugar.Info("User service client created successfully", "url", *userServiceURL)
return userServiceClient, nil
}
// createAssetServiceClient 创建AssetService RPC客户端
func createAssetServiceClient(serviceURL string) (*socialClient.AssetClient, error) {
assetClient, err := socialClient.NewAssetClient(serviceURL, logger.Logger)
if err != nil {
return nil, fmt.Errorf("failed to create asset client: %w", err)
}
logger.Sugar.Info("Asset service client created successfully", "url", serviceURL)
return assetClient, nil
}