package app import ( "errors" "net" "net/http" "os" "sync" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "hyapp/services/gateway-service/internal/auth" "hyapp/services/gateway-service/internal/client" "hyapp/services/gateway-service/internal/config" "hyapp/services/gateway-service/internal/healthcheck" httptransport "hyapp/services/gateway-service/internal/transport/http" ) // App 装配 gateway 的 HTTP 入口。 type App struct { server *http.Server listener net.Listener roomConn *grpc.ClientConn userConn *grpc.ClientConn health *healthcheck.State closeOnce sync.Once } // New 初始化 gateway 应用。 func New(cfg config.Config) (*App, error) { roomConn, err := grpc.Dial(cfg.RoomServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { return nil, err } userConn, err := grpc.Dial(cfg.UserServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { _ = roomConn.Close() return nil, err } var roomClient client.RoomClient = client.NewGRPCRoomClient(roomConn) var userClient client.UserAuthClient = client.NewGRPCUserAuthClient(userConn) var userIdentityClient client.UserIdentityClient = client.NewGRPCUserIdentityClient(userConn) handler := httptransport.NewHandlerWithClients(roomClient, userClient, userIdentityClient) verifier := auth.NewVerifier(cfg.JWTSecret) healthState := healthcheck.NewState(nodeID(), cfg.JWTSecret, roomConn) mux := http.NewServeMux() healthHandler := healthcheck.NewHTTPHandler(healthState) mux.HandleFunc("/healthz/live", healthHandler.Live) mux.HandleFunc("/healthz/ready", healthHandler.Ready) mux.Handle("/", handler.Routes(verifier)) listener, err := net.Listen("tcp", cfg.HTTPAddr) if err != nil { _ = roomConn.Close() _ = userConn.Close() return nil, err } server := &http.Server{ Handler: mux, } return &App{ server: server, listener: listener, roomConn: roomConn, userConn: userConn, health: healthState, }, nil } // Run 启动 HTTP 服务。 func (a *App) Run() error { a.health.MarkHTTPServing() err := a.server.Serve(a.listener) a.health.MarkHTTPStopped() if errors.Is(err, http.ErrServerClosed) { return nil } return err } // Close 关闭 HTTP 服务。 func (a *App) Close() error { var err error a.closeOnce.Do(func() { a.health.MarkDraining() if a.roomConn != nil { _ = a.roomConn.Close() } if a.userConn != nil { _ = a.userConn.Close() } err = a.server.Close() }) return err } func nodeID() string { hostname, err := os.Hostname() if err != nil || hostname == "" { return "gateway-service" } return hostname }