package http import ( "log" "net/http" "time" roomv1 "hyapp.local/api/proto/room/v1" "hyapp/pkg/appcode" "hyapp/pkg/roomid" "hyapp/pkg/tencentrtc" "hyapp/pkg/xerr" "hyapp/services/gateway-service/internal/auth" ) // issueTencentRTCToken signs Tencent RTC credentials only after room-service confirms presence. func (h *Handler) issueTencentRTCToken(writer http.ResponseWriter, request *http.Request) { var body struct { RoomID string `json:"room_id"` } if !decode(writer, request, &body) { return } if !roomid.ValidStringID(body.RoomID) { // Token signing repeats room_id validation to fail closed on historical or dirty rooms. writeError(writer, request, http.StatusBadRequest, codeInvalidArgument, "invalid argument") return } userID := auth.UserIDFromContext(request.Context()) if userID <= 0 { // Auth middleware normally blocks this; the handler keeps a defensive guard before signing. writeError(writer, request, http.StatusUnauthorized, codeUnauthorized, "unauthorized") return } rtcConfig := tencentrtc.TokenConfig{ Enabled: h.tencentRTC.Enabled, SDKAppID: h.tencentRTC.SDKAppID, SecretKey: h.tencentRTC.SecretKey, TTL: h.tencentRTC.UserSigTTL, RoomIDType: h.tencentRTC.RoomIDType, AppScene: h.tencentRTC.AppScene, } if err := tencentrtc.ValidateConfig(rtcConfig); err != nil { log.Printf("gateway_rtc_token result=config_error request_id=%s user_id=%d room_id=%s reason=%q", requestIDFromContext(request.Context()), userID, body.RoomID, err.Error()) writeError(writer, request, http.StatusInternalServerError, codeInternalError, "internal error") return } if h.roomGuardClient == nil { // Without room-service presence, gateway cannot safely decide RTC room entry. writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } guardResp, err := h.roomGuardClient.VerifyRoomPresence(request.Context(), &roomv1.VerifyRoomPresenceRequest{ RoomId: body.RoomID, UserId: userID, RequestId: requestIDFromContext(request.Context()), AppCode: appcode.FromContext(request.Context()), }) if err != nil { writeRPCError(writer, request, err) return } if guardResp == nil || !guardResp.GetPresent() { h.writeRTCPresenceDenied(writer, request, body.RoomID, userID, guardResp) return } token, err := tencentrtc.GenerateToken(rtcConfig, userID, body.RoomID, timeNow()) if err != nil { log.Printf("gateway_rtc_token result=config_error request_id=%s user_id=%d room_id=%s reason=%q", requestIDFromContext(request.Context()), userID, body.RoomID, err.Error()) writeError(writer, request, http.StatusInternalServerError, codeInternalError, "internal error") return } log.Printf("gateway_rtc_token result=issued request_id=%s user_id=%d rtc_user_id=%s room_id=%s str_room_id=%s room_version=%d", requestIDFromContext(request.Context()), userID, token.RTCUserID, body.RoomID, token.StrRoomID, guardResp.GetRoomVersion()) writeOK(writer, request, token) } func (h *Handler) writeRTCPresenceDenied(writer http.ResponseWriter, request *http.Request, targetRoomID string, userID int64, guardResp *roomv1.VerifyRoomPresenceResponse) { reason := "not_in_room" roomVersion := int64(0) if guardResp != nil { reason = guardResp.GetReason() roomVersion = guardResp.GetRoomVersion() } log.Printf("gateway_rtc_token result=denied request_id=%s user_id=%d room_id=%s room_version=%d reason=%q", requestIDFromContext(request.Context()), userID, targetRoomID, roomVersion, reason) if reason == "room_not_found" { writeError(writer, request, http.StatusNotFound, codeNotFound, "not found") return } if reason == "room_closed" { writeError(writer, request, http.StatusConflict, string(xerr.RoomClosed), "room closed") return } writeError(writer, request, http.StatusForbidden, codePermissionDenied, "permission denied") } var timeNow = defaultTimeNow func defaultTimeNow() time.Time { return time.Now() }