2026-05-27 18:50:40 +08:00

774 lines
27 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 roomapi
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"`
Title string `json:"title,omitempty"`
CoverURL string `json:"cover_url,omitempty"`
Mode string `json:"mode,omitempty"`
Status string `json:"status,omitempty"`
Locked bool `json:"locked"`
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 createRoomData struct {
Result roomCommandResultData `json:"result"`
Room roomInitialData `json:"room"`
Seats []roomSeatData `json:"seats"`
IM roomIMData `json:"im"`
ServerTimeMS int64 `json:"server_time_ms"`
}
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 roomDetailData struct {
Room roomInitialData `json:"room"`
Viewer roomViewerData `json:"viewer"`
IsFollowed bool `json:"is_followed"`
Seats []roomSeatData `json:"seats"`
RankTop []roomRankItemData `json:"rank_top"`
OnlineCount int32 `json:"online_count"`
Permissions roomPermissionsData `json:"permissions"`
Profiles []roomDisplayProfileData `json:"profiles,omitempty"`
IM roomIMData `json:"im"`
RTC roomRTCData `json:"rtc"`
ServerTimeMS int64 `json:"server_time_ms"`
}
type roomOnlineUsersData struct {
Items []roomOnlineUserData `json:"items"`
Total int64 `json:"total"`
Page int32 `json:"page"`
PageSize int32 `json:"page_size"`
ServerTimeMS int64 `json:"server_time_ms"`
}
type roomOnlineUserData struct {
UserID string `json:"user_id"`
Role string `json:"role,omitempty"`
IsOwner bool `json:"is_owner"`
RoomRole string `json:"room_role,omitempty"`
GiftValue int64 `json:"gift_value"`
JoinedAtMS int64 `json:"joined_at_ms,omitempty"`
LastSeenAtMS int64 `json:"last_seen_at_ms,omitempty"`
Profile *roomDisplayProfileData `json:"profile,omitempty"`
}
type setRoomAdminData struct {
Result roomCommandResultData `json:"result"`
TargetUserID string `json:"target_user_id"`
RoomRole string `json:"room_role"`
ServerTimeMS int64 `json:"server_time_ms"`
}
type roomPermissionsData struct {
IsOwner bool `json:"is_owner"`
IsAdmin bool `json:"is_admin"`
IsMuted bool `json:"is_muted"`
CanSpeak bool `json:"can_speak"`
CanSendGift bool `json:"can_send_gift"`
CanMicUp bool `json:"can_mic_up"`
CanManageRoom bool `json:"can_manage_room"`
CanLeaveRoom bool `json:"can_leave_room"`
CanCloseRoom bool `json:"can_close_room"`
CanMuteMic bool `json:"can_mute_mic"`
CanOpenGiftBox bool `json:"can_open_gift_box"`
}
type roomDisplayProfileData struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Avatar string `json:"avatar"`
DisplayUserID string `json:"display_user_id"`
Gender string `json:"gender"`
Age int32 `json:"age"`
Country string `json:"country"`
CountryName string `json:"country_name"`
CountryDisplayName string `json:"country_display_name"`
CountryFlag string `json:"country_flag"`
VIP map[string]any `json:"vip"`
Level map[string]any `json:"level"`
Badges []map[string]any `json:"badges"`
AvatarFrame map[string]any `json:"avatar_frame"`
Vehicle map[string]any `json:"vehicle"`
Charm int64 `json:"charm"`
}
type roomGiftPanelData struct {
CoinBalance int64 `json:"coin_balance"`
Recipients []roomGiftRecipientData `json:"recipients"`
Tabs []roomGiftTabData `json:"tabs"`
Gifts []giftConfigData `json:"gifts"`
QuantityPresets []int32 `json:"quantity_presets"`
}
type roomTreasureData struct {
Enabled bool `json:"enabled"`
Levels []roomTreasureLevelData `json:"levels"`
State roomTreasureStateData `json:"state"`
BroadcastScope string `json:"broadcast_scope"`
OpenDelayMS int64 `json:"open_delay_ms"`
BroadcastDelayMS int64 `json:"broadcast_delay_ms"`
RewardStackPolicy string `json:"reward_stack_policy"`
ServerTimeMS int64 `json:"server_time_ms"`
}
type roomTreasureLevelData struct {
Level int32 `json:"level"`
EnergyThreshold int64 `json:"energy_threshold"`
CoverURL string `json:"cover_url,omitempty"`
AnimationURL string `json:"animation_url,omitempty"`
OpeningAnimationURL string `json:"opening_animation_url,omitempty"`
OpenedImageURL string `json:"opened_image_url,omitempty"`
InRoomRewards []roomTreasureRewardData `json:"in_room_rewards"`
Top1Rewards []roomTreasureRewardData `json:"top1_rewards"`
IgniterRewards []roomTreasureRewardData `json:"igniter_rewards"`
}
type roomTreasureRewardData struct {
RewardItemID string `json:"reward_item_id"`
ResourceGroupID int64 `json:"resource_group_id"`
Weight int64 `json:"weight,omitempty"`
DisplayName string `json:"display_name,omitempty"`
IconURL string `json:"icon_url,omitempty"`
}
type roomTreasureStateData struct {
CurrentLevel int32 `json:"current_level"`
CurrentProgress int64 `json:"current_progress"`
EnergyThreshold int64 `json:"energy_threshold"`
Status string `json:"status"`
CountdownStartedAtMS int64 `json:"countdown_started_at_ms,omitempty"`
OpenAtMS int64 `json:"open_at_ms,omitempty"`
OpenedAtMS int64 `json:"opened_at_ms,omitempty"`
ResetAtMS int64 `json:"reset_at_ms"`
Top1UserID string `json:"top1_user_id,omitempty"`
IgniterUserID string `json:"igniter_user_id,omitempty"`
BoxID string `json:"box_id,omitempty"`
ConfigVersion int64 `json:"config_version,omitempty"`
LastRewards []roomTreasureRewardGrantData `json:"last_rewards,omitempty"`
}
type roomTreasureRewardGrantData struct {
RewardRole string `json:"reward_role"`
UserID string `json:"user_id"`
RewardItemID string `json:"reward_item_id"`
ResourceGroupID int64 `json:"resource_group_id"`
DisplayName string `json:"display_name,omitempty"`
IconURL string `json:"icon_url,omitempty"`
GrantID string `json:"grant_id,omitempty"`
Status string `json:"status,omitempty"`
}
type roomGiftRecipientData struct {
TargetType string `json:"target_type"`
UserID string `json:"user_id,omitempty"`
SeatNo int32 `json:"seat_no,omitempty"`
Label string `json:"label,omitempty"`
Profile *roomDisplayProfileData `json:"profile,omitempty"`
}
type roomGiftTabData struct {
Key string `json:"key"`
GiftTypeCode string `json:"gift_type_code,omitempty"`
Label string `json:"label,omitempty"`
Order int32 `json:"order"`
}
type updateRoomProfileData struct {
Result roomCommandResultData `json:"result"`
Room roomInitialData `json:"room"`
Seats []roomSeatData `json:"seats"`
ServerTimeMS int64 `json:"server_time_ms"`
}
type roomSnapshotData struct {
Room roomInitialData `json:"room"`
Seats []roomSeatData `json:"seats"`
ContributionRank []roomRankItemData `json:"contribution_rank"`
IsFollowed bool `json:"is_followed"`
ServerTimeMS int64 `json:"server_time_ms"`
}
type roomFollowData struct {
RoomID string `json:"room_id"`
IsFollowed bool `json:"is_followed"`
FollowedAtMS int64 `json:"followed_at_ms,omitempty"`
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"`
Mode string `json:"mode,omitempty"`
Status string `json:"status,omitempty"`
ChatEnabled bool `json:"chat_enabled"`
Locked bool `json:"locked"`
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"`
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"`
MicMuted bool `json:"mic_muted"`
SeatStatus string `json:"seat_status,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 createRoomDataFromProto(resp *roomv1.CreateRoomResponse) createRoomData {
if resp == nil {
return createRoomData{}
}
snapshot := resp.GetRoom()
roomID := snapshot.GetRoomId()
return createRoomData{
Result: commandResultDataFromProto(resp.GetResult()),
Room: roomInitialRoomDataFromSnapshot(snapshot, roomID),
Seats: roomSeatDataFromSnapshot(snapshot),
IM: roomIMData{GroupID: roomIMGroupID(roomID), NeedJoinGroup: true},
ServerTimeMS: resp.GetResult().GetServerTimeMs(),
}
}
func roomTreasureDataFromProto(resp *roomv1.GetRoomTreasureResponse) roomTreasureData {
if resp == nil || resp.GetTreasure() == nil {
return roomTreasureData{}
}
treasure := resp.GetTreasure()
return roomTreasureData{
Enabled: treasure.GetEnabled(),
Levels: roomTreasureLevelsFromProto(treasure.GetLevels()),
State: roomTreasureStateFromProto(treasure.GetState()),
BroadcastScope: treasure.GetBroadcastScope(),
OpenDelayMS: treasure.GetOpenDelayMs(),
BroadcastDelayMS: treasure.GetBroadcastDelayMs(),
RewardStackPolicy: treasure.GetRewardStackPolicy(),
ServerTimeMS: resp.GetServerTimeMs(),
}
}
func roomTreasureLevelsFromProto(levels []*roomv1.RoomTreasureLevel) []roomTreasureLevelData {
out := make([]roomTreasureLevelData, 0, len(levels))
for _, level := range levels {
out = append(out, roomTreasureLevelData{
Level: level.GetLevel(),
EnergyThreshold: level.GetEnergyThreshold(),
CoverURL: level.GetCoverUrl(),
AnimationURL: level.GetAnimationUrl(),
OpeningAnimationURL: level.GetOpeningAnimationUrl(),
OpenedImageURL: level.GetOpenedImageUrl(),
InRoomRewards: roomTreasureRewardsFromProto(level.GetInRoomRewards()),
Top1Rewards: roomTreasureRewardsFromProto(level.GetTop1Rewards()),
IgniterRewards: roomTreasureRewardsFromProto(level.GetIgniterRewards()),
})
}
return out
}
func roomTreasureRewardsFromProto(rewards []*roomv1.RoomTreasureRewardItem) []roomTreasureRewardData {
out := make([]roomTreasureRewardData, 0, len(rewards))
for _, reward := range rewards {
out = append(out, roomTreasureRewardData{
RewardItemID: reward.GetRewardItemId(),
ResourceGroupID: reward.GetResourceGroupId(),
Weight: reward.GetWeight(),
DisplayName: reward.GetDisplayName(),
IconURL: reward.GetIconUrl(),
})
}
return out
}
func roomTreasureStateFromProto(state *roomv1.RoomTreasureState) roomTreasureStateData {
if state == nil {
return roomTreasureStateData{}
}
return roomTreasureStateData{
CurrentLevel: state.GetCurrentLevel(),
CurrentProgress: state.GetCurrentProgress(),
EnergyThreshold: state.GetEnergyThreshold(),
Status: state.GetStatus(),
CountdownStartedAtMS: state.GetCountdownStartedAtMs(),
OpenAtMS: state.GetOpenAtMs(),
OpenedAtMS: state.GetOpenedAtMs(),
ResetAtMS: state.GetResetAtMs(),
Top1UserID: formatOptionalUserID(state.GetTop1UserId()),
IgniterUserID: formatOptionalUserID(state.GetIgniterUserId()),
BoxID: state.GetBoxId(),
ConfigVersion: state.GetConfigVersion(),
LastRewards: roomTreasureRewardGrantsFromProto(state.GetLastRewards()),
}
}
func roomTreasureRewardGrantsFromProto(rewards []*roomv1.RoomTreasureRewardGrant) []roomTreasureRewardGrantData {
out := make([]roomTreasureRewardGrantData, 0, len(rewards))
for _, reward := range rewards {
out = append(out, roomTreasureRewardGrantData{
RewardRole: reward.GetRewardRole(),
UserID: formatOptionalUserID(reward.GetUserId()),
RewardItemID: reward.GetRewardItemId(),
ResourceGroupID: reward.GetResourceGroupId(),
DisplayName: reward.GetDisplayName(),
IconURL: reward.GetIconUrl(),
GrantID: reward.GetGrantId(),
Status: reward.GetStatus(),
})
}
return out
}
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()),
Title: room.GetTitle(),
CoverURL: room.GetCoverUrl(),
Mode: room.GetMode(),
Status: room.GetStatus(),
Locked: room.GetLocked(),
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 roomSnapshotDataFromProto(resp *roomv1.GetRoomSnapshotResponse) roomSnapshotData {
if resp == nil {
return roomSnapshotData{}
}
snapshot := resp.GetRoom()
return roomSnapshotData{
Room: roomInitialRoomDataFromSnapshot(snapshot, snapshot.GetRoomId()),
Seats: roomSeatDataFromSnapshot(snapshot),
ContributionRank: roomRankDataFromSnapshot(snapshot, 0),
IsFollowed: resp.GetIsFollowed(),
ServerTimeMS: resp.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()),
Mode: snapshot.GetMode(),
Status: snapshot.GetStatus(),
ChatEnabled: snapshot.GetChatEnabled(),
Locked: snapshot.GetLocked(),
Heat: snapshot.GetHeat(),
OnlineCount: int32(len(snapshot.GetOnlineUsers())),
SeatCount: seatCount,
OccupiedSeatCount: occupiedSeatCount,
VisibleRegionID: snapshot.GetVisibleRegionId(),
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(),
MicMuted: seat.GetMicMuted(),
SeatStatus: seat.GetSeatStatus(),
})
}
return items
}
func roomDetailDataFromSnapshot(resp *roomv1.GetRoomSnapshotResponse, viewerUserID int64, rtc roomRTCData, profiles []roomDisplayProfileData) roomDetailData {
if resp == nil {
return roomDetailData{}
}
snapshot := resp.GetRoom()
roomID := snapshot.GetRoomId()
viewer := protoRoomUserByID(snapshot, viewerUserID)
return roomDetailData{
Room: roomInitialRoomDataFromSnapshot(snapshot, roomID),
Viewer: roomViewerDataFromProto(viewer, viewerUserID),
IsFollowed: resp.GetIsFollowed(),
Seats: roomSeatDataFromSnapshot(snapshot),
RankTop: roomRankDataFromSnapshot(snapshot, joinRoomContributionRankLimit),
OnlineCount: int32(len(snapshot.GetOnlineUsers())),
Permissions: roomPermissionsFromSnapshot(snapshot, viewerUserID),
Profiles: profiles,
IM: roomIMData{GroupID: roomIMGroupID(roomID), NeedJoinGroup: true},
RTC: rtc,
ServerTimeMS: resp.GetServerTimeMs(),
}
}
func roomFollowDataFromProto(resp *roomv1.FollowRoomResponse) roomFollowData {
if resp == nil {
return roomFollowData{}
}
return roomFollowData{
RoomID: resp.GetRoomId(),
IsFollowed: resp.GetFollowed(),
FollowedAtMS: resp.GetFollowedAtMs(),
ServerTimeMS: resp.GetServerTimeMs(),
}
}
func roomUnfollowDataFromProto(resp *roomv1.UnfollowRoomResponse) roomFollowData {
if resp == nil {
return roomFollowData{}
}
return roomFollowData{
RoomID: resp.GetRoomId(),
IsFollowed: resp.GetFollowed(),
ServerTimeMS: resp.GetServerTimeMs(),
}
}
func roomPermissionsFromSnapshot(snapshot *roomv1.RoomSnapshot, viewerUserID int64) roomPermissionsData {
if snapshot == nil || viewerUserID <= 0 {
return roomPermissionsData{}
}
isOwner := snapshot.GetOwnerUserId() == viewerUserID
isAdmin := !isOwner && containsInt64(snapshot.GetAdminUserIds(), viewerUserID)
isMuted := containsInt64(snapshot.GetMuteUserIds(), viewerUserID)
inRoom := protoRoomUserByID(snapshot, viewerUserID) != nil
return roomPermissionsData{
IsOwner: isOwner,
IsAdmin: isAdmin,
IsMuted: isMuted,
CanSpeak: inRoom && snapshot.GetChatEnabled() && !isMuted,
CanSendGift: inRoom && snapshot.GetStatus() == "active",
CanMicUp: inRoom && snapshot.GetStatus() == "active" && protoSeatByUserID(snapshot, viewerUserID) == nil,
CanManageRoom: inRoom && (isOwner || isAdmin),
CanLeaveRoom: inRoom,
CanCloseRoom: inRoom,
CanMuteMic: inRoom && protoSeatByUserID(snapshot, viewerUserID) != nil,
CanOpenGiftBox: inRoom && snapshot.GetStatus() == "active",
}
}
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(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 roomOnlineUserDataFromProto(resp *roomv1.ListRoomOnlineUsersResponse, profiles map[int64]roomDisplayProfileData) roomOnlineUsersData {
if resp == nil {
return roomOnlineUsersData{}
}
source := resp.GetItems()
if len(source) == 0 {
source = roomOnlineUsersFromLegacyUsers(resp.GetUsers())
}
items := make([]roomOnlineUserData, 0, len(source))
for _, user := range source {
item := roomOnlineUserData{
UserID: formatOptionalUserID(user.GetUserId()),
Role: user.GetRole(),
IsOwner: user.GetIsOwner(),
RoomRole: user.GetRoomRole(),
GiftValue: user.GetGiftValue(),
JoinedAtMS: user.GetJoinedAtMs(),
LastSeenAtMS: user.GetLastSeenAtMs(),
}
if profile, ok := profiles[user.GetUserId()]; ok {
copied := profile
item.Profile = &copied
}
items = append(items, item)
}
return roomOnlineUsersData{
Items: items,
Total: resp.GetTotal(),
Page: resp.GetPage(),
PageSize: resp.GetPageSize(),
ServerTimeMS: resp.GetServerTimeMs(),
}
}
func roomOnlineUsersFromLegacyUsers(users []*roomv1.RoomUser) []*roomv1.RoomOnlineUser {
items := make([]*roomv1.RoomOnlineUser, 0, len(users))
for _, user := range users {
items = append(items, &roomv1.RoomOnlineUser{
UserId: user.GetUserId(),
Role: user.GetRole(),
JoinedAtMs: user.GetJoinedAtMs(),
LastSeenAtMs: user.GetLastSeenAtMs(),
RoomRole: "normal",
})
}
return items
}
func protoRoomUserByID(snapshot *roomv1.RoomSnapshot, userID int64) *roomv1.RoomUser {
if snapshot == nil || userID <= 0 {
return nil
}
for _, user := range snapshot.GetOnlineUsers() {
if user.GetUserId() == userID {
return user
}
}
return nil
}
func protoSeatByUserID(snapshot *roomv1.RoomSnapshot, userID int64) *roomv1.SeatState {
if snapshot == nil || userID <= 0 {
return nil
}
for _, seat := range snapshot.GetMicSeats() {
if seat.GetUserId() == userID {
return seat
}
}
return nil
}
func containsInt64(values []int64, target int64) bool {
for _, value := range values {
if value == target {
return true
}
}
return false
}
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)
}