2026-04-04 01:28:57 +08:00

87 lines
2.3 KiB
Go

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()),
)
}