package http import ( "strconv" "hyapp/pkg/tencentrtc" roomv1 "hyapp.local/api/proto/room/v1" ) const joinRoomContributionRankLimit = 10 type roomListData struct { Rooms []roomListItemData `json:"rooms"` NextCursor string `json:"next_cursor,omitempty"` } type myRoomData struct { HasRoom bool `json:"has_room"` Room *roomListItemData `json:"room,omitempty"` ServerTimeMS int64 `json:"server_time_ms"` } type roomListItemData struct { RoomID string `json:"room_id"` IMGroupID string `json:"im_group_id"` OwnerUserID string `json:"owner_user_id,omitempty"` HostUserID string `json:"host_user_id,omitempty"` Title string `json:"title,omitempty"` CoverURL string `json:"cover_url,omitempty"` Mode string `json:"mode,omitempty"` Status string `json:"status,omitempty"` Heat int64 `json:"heat"` OnlineCount int32 `json:"online_count"` SeatCount int32 `json:"seat_count"` OccupiedSeatCount int32 `json:"occupied_seat_count"` VisibleRegionID int64 `json:"visible_region_id,omitempty"` AppCode string `json:"app_code,omitempty"` RoomShortID string `json:"room_short_id,omitempty"` } type joinRoomData struct { Result roomCommandResultData `json:"result"` Room roomInitialData `json:"room"` Viewer roomViewerData `json:"viewer"` Seats []roomSeatData `json:"seats"` ContributionRank []roomRankItemData `json:"contribution_rank"` Profiles []roomUserProfileData `json:"profiles"` IM roomIMData `json:"im"` RTC roomRTCData `json:"rtc"` ServerTimeMS int64 `json:"server_time_ms"` } type updateRoomProfileData struct { Result roomCommandResultData `json:"result"` Room roomInitialData `json:"room"` Seats []roomSeatData `json:"seats"` ServerTimeMS int64 `json:"server_time_ms"` } type roomCommandResultData struct { Applied bool `json:"applied"` RoomVersion int64 `json:"room_version"` ServerTimeMS int64 `json:"server_time_ms"` } type roomInitialData struct { RoomID string `json:"room_id"` IMGroupID string `json:"im_group_id"` RoomShortID string `json:"room_short_id,omitempty"` Title string `json:"title,omitempty"` CoverURL string `json:"cover_url,omitempty"` Description string `json:"description,omitempty"` OwnerUserID string `json:"owner_user_id,omitempty"` HostUserID string `json:"host_user_id,omitempty"` Mode string `json:"mode,omitempty"` Status string `json:"status,omitempty"` ChatEnabled bool `json:"chat_enabled"` Heat int64 `json:"heat"` OnlineCount int32 `json:"online_count"` SeatCount int32 `json:"seat_count"` OccupiedSeatCount int32 `json:"occupied_seat_count"` Version int64 `json:"version"` } type roomViewerData struct { UserID string `json:"user_id"` Role string `json:"role,omitempty"` JoinedAtMS int64 `json:"joined_at_ms,omitempty"` LastSeenAtMS int64 `json:"last_seen_at_ms,omitempty"` } type roomSeatData struct { SeatNo int32 `json:"seat_no"` UserID string `json:"user_id,omitempty"` Locked bool `json:"locked"` PublishState string `json:"publish_state,omitempty"` MicSessionID string `json:"mic_session_id,omitempty"` PublishDeadlineMS int64 `json:"publish_deadline_ms,omitempty"` } type roomRankItemData struct { UserID string `json:"user_id"` Score int64 `json:"score"` GiftValue int64 `json:"gift_value"` UpdatedAtMS int64 `json:"updated_at_ms,omitempty"` } type roomUserProfileData struct { UserID string `json:"user_id"` DisplayUserID string `json:"display_user_id,omitempty"` Username string `json:"username,omitempty"` Avatar string `json:"avatar,omitempty"` } type roomIMData struct { GroupID string `json:"group_id"` NeedJoinGroup bool `json:"need_join_group"` } type roomRTCData struct { NeedToken bool `json:"need_token"` Available bool `json:"available"` Token *tencentrtc.TokenResult `json:"token,omitempty"` Reason string `json:"reason,omitempty"` } func roomListDataFromProto(resp *roomv1.ListRoomsResponse) roomListData { if resp == nil { return roomListData{} } items := make([]roomListItemData, 0, len(resp.GetRooms())) for _, room := range resp.GetRooms() { items = append(items, roomListItemDataFromProto(room)) } return roomListData{Rooms: items, NextCursor: resp.GetNextCursor()} } func myRoomDataFromProto(resp *roomv1.GetMyRoomResponse) myRoomData { if resp == nil { return myRoomData{} } data := myRoomData{HasRoom: resp.GetHasRoom(), ServerTimeMS: resp.GetServerTimeMs()} if resp.GetHasRoom() && resp.GetRoom() != nil { room := roomListItemDataFromProto(resp.GetRoom()) data.Room = &room } return data } func roomListItemDataFromProto(room *roomv1.RoomListItem) roomListItemData { if room == nil { return roomListItemData{} } roomID := room.GetRoomId() return roomListItemData{ RoomID: roomID, IMGroupID: roomIMGroupID(roomID), OwnerUserID: formatOptionalUserID(room.GetOwnerUserId()), HostUserID: formatOptionalUserID(room.GetHostUserId()), Title: room.GetTitle(), CoverURL: room.GetCoverUrl(), Mode: room.GetMode(), Status: room.GetStatus(), Heat: room.GetHeat(), OnlineCount: room.GetOnlineCount(), SeatCount: room.GetSeatCount(), OccupiedSeatCount: room.GetOccupiedSeatCount(), VisibleRegionID: room.GetVisibleRegionId(), AppCode: room.GetAppCode(), RoomShortID: room.GetRoomShortId(), } } func commandResultDataFromProto(result *roomv1.CommandResult) roomCommandResultData { if result == nil { return roomCommandResultData{} } return roomCommandResultData{ Applied: result.GetApplied(), RoomVersion: result.GetRoomVersion(), ServerTimeMS: result.GetServerTimeMs(), } } func updateRoomProfileDataFromProto(resp *roomv1.UpdateRoomProfileResponse) updateRoomProfileData { if resp == nil { return updateRoomProfileData{} } snapshot := resp.GetRoom() return updateRoomProfileData{ Result: commandResultDataFromProto(resp.GetResult()), Room: roomInitialRoomDataFromSnapshot(snapshot, snapshot.GetRoomId()), Seats: roomSeatDataFromSnapshot(snapshot), ServerTimeMS: resp.GetResult().GetServerTimeMs(), } } func roomInitialRoomDataFromSnapshot(snapshot *roomv1.RoomSnapshot, roomID string) roomInitialData { if snapshot == nil { return roomInitialData{RoomID: roomID, IMGroupID: roomIMGroupID(roomID)} } ext := snapshot.GetRoomExt() if roomID == "" { roomID = snapshot.GetRoomId() } roomShortID := snapshot.GetRoomShortId() if roomShortID == "" { roomShortID = ext["room_short_id"] } seatCount, occupiedSeatCount := roomSeatCounts(snapshot) return roomInitialData{ RoomID: roomID, IMGroupID: roomIMGroupID(roomID), RoomShortID: roomShortID, Title: ext["title"], CoverURL: ext["cover_url"], Description: ext["description"], OwnerUserID: formatOptionalUserID(snapshot.GetOwnerUserId()), HostUserID: formatOptionalUserID(snapshot.GetHostUserId()), Mode: snapshot.GetMode(), Status: snapshot.GetStatus(), ChatEnabled: snapshot.GetChatEnabled(), Heat: snapshot.GetHeat(), OnlineCount: int32(len(snapshot.GetOnlineUsers())), SeatCount: seatCount, OccupiedSeatCount: occupiedSeatCount, Version: snapshot.GetVersion(), } } func roomViewerDataFromProto(user *roomv1.RoomUser, fallbackUserID int64) roomViewerData { userID := fallbackUserID if user.GetUserId() > 0 { userID = user.GetUserId() } return roomViewerData{ UserID: formatOptionalUserID(userID), Role: user.GetRole(), JoinedAtMS: user.GetJoinedAtMs(), LastSeenAtMS: user.GetLastSeenAtMs(), } } func roomSeatDataFromSnapshot(snapshot *roomv1.RoomSnapshot) []roomSeatData { seats := snapshot.GetMicSeats() items := make([]roomSeatData, 0, len(seats)) for _, seat := range seats { items = append(items, roomSeatData{ SeatNo: seat.GetSeatNo(), UserID: formatOptionalUserID(seat.GetUserId()), Locked: seat.GetLocked(), PublishState: seat.GetPublishState(), MicSessionID: seat.GetMicSessionId(), PublishDeadlineMS: seat.GetPublishDeadlineMs(), }) } return items } func roomRankDataFromSnapshot(snapshot *roomv1.RoomSnapshot, limit int) []roomRankItemData { rank := snapshot.GetGiftRank() if limit > 0 && len(rank) > limit { rank = rank[:limit] } items := make([]roomRankItemData, 0, len(rank)) for _, item := range rank { items = append(items, roomRankItemData{ UserID: formatOptionalUserID(item.GetUserId()), Score: item.GetScore(), GiftValue: item.GetGiftValue(), UpdatedAtMS: item.GetUpdatedAtMs(), }) } return items } func roomInitialProfileUserIDs(snapshot *roomv1.RoomSnapshot, viewerUserID int64, rankLimit int) []int64 { seen := map[int64]bool{} userIDs := make([]int64, 0, 16) add := func(userID int64) { if userID <= 0 || seen[userID] { return } seen[userID] = true userIDs = append(userIDs, userID) } add(snapshot.GetOwnerUserId()) add(snapshot.GetHostUserId()) add(viewerUserID) for _, seat := range snapshot.GetMicSeats() { add(seat.GetUserId()) } rank := snapshot.GetGiftRank() if rankLimit > 0 && len(rank) > rankLimit { rank = rank[:rankLimit] } for _, item := range rank { add(item.GetUserId()) } return userIDs } func roomSeatCounts(snapshot *roomv1.RoomSnapshot) (int32, int32) { seatCount := int32(len(snapshot.GetMicSeats())) occupiedSeatCount := int32(0) for _, seat := range snapshot.GetMicSeats() { if seat.GetUserId() > 0 { occupiedSeatCount++ } } return seatCount, occupiedSeatCount } func roomIMGroupID(roomID string) string { // 当前房间群规则固定为腾讯云 IM GroupID 等于内部 room_id;显式下发给客户端,避免端侧硬编码规则。 return roomID } func formatOptionalUserID(userID int64) string { if userID <= 0 { return "" } return strconv.FormatInt(userID, 10) }