120 lines
3.4 KiB
Go
120 lines
3.4 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"sort"
|
||
|
||
roomv1 "hyapp.local/api/proto/room/v1"
|
||
"hyapp/pkg/appcode"
|
||
"hyapp/pkg/roomid"
|
||
"hyapp/pkg/xerr"
|
||
"hyapp/services/room-service/internal/room/state"
|
||
)
|
||
|
||
const (
|
||
// defaultRoomBannedUsersPageSize 是房间黑名单面板默认页大小。
|
||
defaultRoomBannedUsersPageSize = 20
|
||
// maxRoomBannedUsersPageSize 限制单次查询量,避免管理面板一次拉完整治理状态。
|
||
maxRoomBannedUsersPageSize = 100
|
||
)
|
||
|
||
// ListRoomBannedUsers 分页读取房间当前仍有效的黑名单。
|
||
// 黑名单状态属于 Room Cell,用户头像、昵称、国家等展示资料由 gateway 批量查询 user-service。
|
||
func (s *Service) ListRoomBannedUsers(ctx context.Context, req *roomv1.ListRoomBannedUsersRequest) (*roomv1.ListRoomBannedUsersResponse, error) {
|
||
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
||
roomID := req.GetRoomId()
|
||
viewerUserID := req.GetViewerUserId()
|
||
if !roomid.ValidStringID(roomID) {
|
||
return nil, xerr.New(xerr.InvalidArgument, "room_id is invalid")
|
||
}
|
||
if viewerUserID <= 0 {
|
||
return nil, xerr.New(xerr.InvalidArgument, "viewer_user_id is required")
|
||
}
|
||
|
||
snapshot, err := s.currentSnapshot(ctx, roomID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if snapshot == nil || snapshot.GetRoomId() == "" {
|
||
return nil, xerr.New(xerr.NotFound, "room not found")
|
||
}
|
||
if snapshot.GetStatus() != state.RoomStatusActive {
|
||
return nil, xerr.New(xerr.RoomClosed, "room closed")
|
||
}
|
||
|
||
current := state.FromProto(snapshot)
|
||
if err := requireManagerPresent(current, viewerUserID); err != nil {
|
||
// 黑名单是房间治理数据,只允许当前仍在房间内的 owner/admin 查看。
|
||
return nil, err
|
||
}
|
||
|
||
nowMS := s.clock.Now().UnixMilli()
|
||
items := activeBannedUsersFromState(current, nowMS)
|
||
page, pageSize := normalizeRoomBannedUsersPage(req.GetPage(), req.GetPageSize())
|
||
total := int64(len(items))
|
||
start := (page - 1) * pageSize
|
||
if start >= len(items) {
|
||
items = nil
|
||
} else {
|
||
end := start + pageSize
|
||
if end > len(items) {
|
||
end = len(items)
|
||
}
|
||
items = items[start:end]
|
||
}
|
||
|
||
return &roomv1.ListRoomBannedUsersResponse{
|
||
Items: items,
|
||
Total: total,
|
||
Page: int32(page),
|
||
PageSize: int32(pageSize),
|
||
ServerTimeMs: nowMS,
|
||
}, nil
|
||
}
|
||
|
||
func activeBannedUsersFromState(current *state.RoomState, nowMS int64) []*roomv1.RoomBannedUser {
|
||
if current == nil || len(current.BanUsers) == 0 {
|
||
return nil
|
||
}
|
||
items := make([]*roomv1.RoomBannedUser, 0, len(current.BanUsers))
|
||
for _, ban := range current.BanUsers {
|
||
if !ban.ActiveAt(nowMS) {
|
||
continue
|
||
}
|
||
remainingMS := int64(0)
|
||
if ban.ExpiresAtMS > 0 {
|
||
remainingMS = ban.ExpiresAtMS - nowMS
|
||
}
|
||
items = append(items, &roomv1.RoomBannedUser{
|
||
UserId: ban.UserID,
|
||
ActorUserId: ban.ActorUserID,
|
||
CreatedAtMs: ban.CreatedAtMS,
|
||
UnbanAtMs: ban.ExpiresAtMS,
|
||
RemainingMs: remainingMS,
|
||
Permanent: ban.ExpiresAtMS == 0,
|
||
})
|
||
}
|
||
sort.Slice(items, func(i, j int) bool {
|
||
if items[i].GetCreatedAtMs() != items[j].GetCreatedAtMs() {
|
||
return items[i].GetCreatedAtMs() > items[j].GetCreatedAtMs()
|
||
}
|
||
return items[i].GetUserId() < items[j].GetUserId()
|
||
})
|
||
return items
|
||
}
|
||
|
||
func normalizeRoomBannedUsersPage(rawPage int32, rawPageSize int32) (int, int) {
|
||
page := int(rawPage)
|
||
if page <= 0 {
|
||
page = 1
|
||
}
|
||
pageSize := int(rawPageSize)
|
||
if pageSize <= 0 {
|
||
pageSize = defaultRoomBannedUsersPageSize
|
||
}
|
||
if pageSize > maxRoomBannedUsersPageSize {
|
||
pageSize = maxRoomBannedUsersPageSize
|
||
}
|
||
return page, pageSize
|
||
}
|