2026-05-02 13:02:38 +08:00

110 lines
3.9 KiB
Go

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