package gameapi import ( "io" "net/http" "strings" "time" gamev1 "hyapp.local/api/proto/game/v1" userv1 "hyapp.local/api/proto/user/v1" "hyapp/pkg/appcode" "hyapp/pkg/xerr" "hyapp/services/gateway-service/internal/auth" "hyapp/services/gateway-service/internal/transport/http/httpkit" ) func (h *Handler) listGames(writer http.ResponseWriter, request *http.Request) { if h.gameClient == nil || h.userProfileClient == nil { httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error") return } userID := auth.UserIDFromContext(request.Context()) userResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{ Meta: httpkit.UserMeta(request, ""), UserId: userID, }) if err != nil { httpkit.WriteRPCError(writer, request, err) return } resp, err := h.gameClient.ListGames(request.Context(), &gamev1.ListGamesRequest{ Meta: gameMeta(request), UserId: userID, Scene: strings.TrimSpace(request.URL.Query().Get("scene")), RoomId: strings.TrimSpace(request.URL.Query().Get("room_id")), RegionId: userResp.GetUser().GetRegionId(), Language: requestLanguage(request), ClientPlatform: httpkit.FirstHeader(request, "X-App-Platform", "X-Platform"), }) httpkit.Write(writer, request, gameListDataFromProto(resp), err) } func (h *Handler) launchGame(writer http.ResponseWriter, request *http.Request) { if h.gameClient == nil || h.userProfileClient == nil { httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error") return } gameID := strings.TrimSpace(request.PathValue("game_id")) if gameID == "" { httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument") return } var body struct { Scene string `json:"scene"` RoomID string `json:"room_id"` } if !httpkit.Decode(writer, request, &body) { return } userID := auth.UserIDFromContext(request.Context()) userResp, err := h.userProfileClient.GetUser(request.Context(), &userv1.GetUserRequest{ Meta: httpkit.UserMeta(request, ""), UserId: userID, }) if err != nil { httpkit.WriteRPCError(writer, request, err) return } resp, err := h.gameClient.LaunchGame(request.Context(), &gamev1.LaunchGameRequest{ Meta: gameMeta(request), UserId: userID, DisplayUserId: userResp.GetUser().GetDisplayUserId(), GameId: gameID, Scene: body.Scene, RoomId: body.RoomID, AccessToken: bearerAccessToken(request), }) httpkit.Write(writer, request, gameLaunchDataFromProto(resp), err) } func (h *Handler) handleGameCallback(writer http.ResponseWriter, request *http.Request) { if h.gameClient == nil { http.Error(writer, "upstream service error", http.StatusBadGateway) return } raw, err := io.ReadAll(request.Body) if err != nil { http.Error(writer, "invalid request body", http.StatusBadRequest) return } resp, err := h.gameClient.HandleCallback(request.Context(), &gamev1.CallbackRequest{ Meta: gameMeta(request), PlatformCode: strings.TrimSpace(request.PathValue("platform_code")), Operation: strings.TrimSpace(request.PathValue("operation")), RawBody: raw, Headers: flattenedHeaders(request), Query: flattenedQuery(request), RemoteAddr: request.RemoteAddr, }) if err != nil { status := xerr.SpecOf(xerr.ReasonFromGRPC(err)).HTTPStatus http.Error(writer, xerr.SpecOf(xerr.ReasonFromGRPC(err)).PublicMessage, status) return } contentType := strings.TrimSpace(resp.GetContentType()) if contentType == "" { contentType = "application/json" } writer.Header().Set("Content-Type", contentType) writer.WriteHeader(http.StatusOK) _, _ = writer.Write(resp.GetRawBody()) } func gameMeta(request *http.Request) *gamev1.RequestMeta { return &gamev1.RequestMeta{ RequestId: httpkit.RequestIDFromContext(request.Context()), Caller: "gateway-service", GatewayNodeId: "", ActorUserId: auth.UserIDFromContext(request.Context()), SentAtMs: time.Now().UnixMilli(), AppCode: appcode.FromContext(request.Context()), } } func requestLanguage(request *http.Request) string { value := httpkit.FirstHeader(request, "X-App-Language", "X-Language") if value == "" { value = request.Header.Get("Accept-Language") } if index := strings.Index(value, ","); index >= 0 { value = value[:index] } return strings.TrimSpace(value) } func bearerAccessToken(request *http.Request) string { header := strings.TrimSpace(request.Header.Get("Authorization")) if !strings.HasPrefix(header, "Bearer ") { return "" } return strings.TrimSpace(strings.TrimPrefix(header, "Bearer ")) } func flattenedHeaders(request *http.Request) map[string]string { headers := make(map[string]string, len(request.Header)) for key, values := range request.Header { if len(values) > 0 { headers[key] = values[0] } } return headers } func flattenedQuery(request *http.Request) map[string]string { query := request.URL.Query() result := make(map[string]string, len(query)) for key, values := range query { if len(values) > 0 { result[key] = values[0] } } return result }