2026-04-27 02:29:42 +08:00

120 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package http
import (
"net/http"
"time"
roomv1 "hyapp/api/proto/room/v1"
"hyapp/pkg/idgen"
"hyapp/pkg/tencentim"
"hyapp/services/gateway-service/internal/auth"
"hyapp/services/gateway-service/internal/client"
)
// Handler 是 gateway 的 HTTP transport adapter。
// 它只依赖跨服务 client不持有房间状态也不直接实现房间命令语义。
type Handler struct {
roomClient client.RoomClient
roomGuardClient client.RoomGuardClient
userClient client.UserAuthClient
userIdentityClient client.UserIdentityClient
tencentIM TencentIMConfig
}
// TencentIMConfig 是 gateway transport 层签发客户端腾讯云 IM 登录票据所需的配置。
type TencentIMConfig struct {
SDKAppID int64
SecretKey string
UserSigTTL time.Duration
CallbackAuthToken string
}
// NewHandler 装配 gateway HTTP handler 的内部依赖。
func NewHandler(roomClient client.RoomClient, userClient ...client.UserAuthClient) *Handler {
handler := &Handler{roomClient: roomClient}
if len(userClient) > 0 {
handler.userClient = userClient[0]
}
return handler
}
// NewHandlerWithClients 装配完整 gateway HTTP handler。
// 保留 NewHandler 是为了不破坏只测 room/auth transport 的旧测试构造。
func NewHandlerWithClients(roomClient client.RoomClient, userClient client.UserAuthClient, userIdentityClient client.UserIdentityClient) *Handler {
return &Handler{
roomClient: roomClient,
userClient: userClient,
userIdentityClient: userIdentityClient,
}
}
// NewHandlerWithConfig 装配完整 gateway HTTP handler 和外部云服务配置。
func NewHandlerWithConfig(roomClient client.RoomClient, roomGuardClient client.RoomGuardClient, userClient client.UserAuthClient, userIdentityClient client.UserIdentityClient, tencentIM TencentIMConfig) *Handler {
return &Handler{
roomClient: roomClient,
roomGuardClient: roomGuardClient,
userClient: userClient,
userIdentityClient: userIdentityClient,
tencentIM: tencentIM,
}
}
// meta 把外部 HTTP 请求上下文转换成 room-service 命令元信息。
// 当前 gateway 只生成命令入口所需的最小追踪字段,状态版本和幂等落点由 room-service 负责。
func meta(request *http.Request, roomID string) *roomv1.RequestMeta {
return &roomv1.RequestMeta{
RequestId: requestIDFromContext(request.Context()),
CommandId: idgen.New("cmd"),
ActorUserId: auth.UserIDFromContext(request.Context()),
RoomId: roomID,
GatewayNodeId: "gateway-local",
SessionId: idgen.New("sess"),
SentAtMs: time.Now().UnixMilli(),
}
}
// decode 统一处理 HTTP JSON 入参解析失败分支。
// gateway 在这里拒绝非法 JSON不做房间业务校验避免把 Room Cell 规则复制到入口层。
func decode(writer http.ResponseWriter, request *http.Request, out any) bool {
if err := decodeJSON(request.Body, out); err != nil {
writeError(writer, request, http.StatusBadRequest, codeInvalidJSON, "invalid request body")
return false
}
return true
}
// write 统一把内部 gRPC 调用结果转换为 HTTP JSON 响应。
// 首版不在 gateway 细分 gRPC 错误码,避免入口层提前耦合 room-service 的业务错误模型。
func write(writer http.ResponseWriter, request *http.Request, body any, err error) {
if err != nil {
writeRPCError(writer, request, err)
return
}
writeOK(writer, request, body)
}
func (h *Handler) issueTencentIMUserSig(writer http.ResponseWriter, request *http.Request) {
userID := auth.UserIDFromContext(request.Context())
if userID <= 0 {
// 正常路径已由 auth middleware 拦截;这里兜底避免签发匿名 IM 票据。
writeError(writer, request, http.StatusUnauthorized, codeUnauthorized, "unauthorized")
return
}
result, err := tencentim.GenerateUserSig(tencentim.UserSigConfig{
SDKAppID: h.tencentIM.SDKAppID,
SecretKey: h.tencentIM.SecretKey,
TTL: h.tencentIM.UserSigTTL,
}, tencentim.FormatUserID(userID), time.Now())
if err != nil {
// 缺少 SDKAppID 或 SecretKey 属于服务端配置错误,不能返回假票据给客户端。
writeError(writer, request, http.StatusInternalServerError, codeInternalError, "internal error")
return
}
writeOK(writer, request, result)
}