package app import ( "context" "fmt" "io" "log/slog" gatewaypb "chatappgateway/api/proto" "chatappgateway/internal/config" "chatappgateway/internal/integration/paygrpc" "chatappgateway/internal/integration/usergrpc" "chatappgateway/internal/service/auth" "chatappgateway/internal/service/pay" httpserver "chatappgateway/internal/transport/http" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" ) // Application 组合网关运行所需的全部组件。 type Application struct { server *httpserver.Server closers []io.Closer } // New 构造完整应用,包括 gRPC 连接、业务服务和 HTTP 服务。 func New(ctx context.Context, cfg config.Config, logger *slog.Logger) (*Application, error) { userConn, err := dialGRPC(ctx, cfg.GRPC.User.Target) if err != nil { return nil, fmt.Errorf("dial ChatAppUser: %w", err) } payConn, err := dialGRPC(ctx, cfg.GRPC.Pay.Target) if err != nil { _ = userConn.Close() return nil, fmt.Errorf("dial ChatAppPay: %w", err) } userClient := usergrpc.New(gatewaypb.NewChatAppUserClient(userConn), cfg.GRPC.User.Timeout) payClient := paygrpc.New(gatewaypb.NewChatAppPayClient(payConn), cfg.GRPC.Pay.Timeout) authService := auth.New(userClient) payService := pay.New(payClient) readinessChecker := newReadinessGroup( namedChecker{ name: "ChatAppUser", check: grpcConnectionReady(userConn), }, namedChecker{ name: "ChatAppPay", check: grpcConnectionReady(payConn), }, ) server := httpserver.New(cfg.App.Name, cfg.App.HTTPAddr, cfg.App.ShutdownTimeout, logger, authService, payService, readinessChecker) return &Application{ server: server, closers: []io.Closer{userConn, payConn}, }, nil } // Run 启动 HTTP 服务。 func (a *Application) Run(ctx context.Context) error { return a.server.Run(ctx) } // Close 关闭底层 gRPC 连接。 func (a *Application) Close() error { var firstErr error for _, closer := range a.closers { if err := closer.Close(); err != nil && firstErr == nil { firstErr = err } } return firstErr } func dialGRPC(ctx context.Context, target string) (*grpc.ClientConn, error) { // 网关只做自身健康检查,因此这里使用懒连接,避免下游暂时不可用时阻塞启动。 return grpc.DialContext( ctx, target, grpc.WithTransportCredentials(insecure.NewCredentials()), ) }