From e8975dca9d7bd99eb66683a1e897ff90428904a5 Mon Sep 17 00:00:00 2001 From: ZuoZuo <68836346+Mrz-sakura@users.noreply.github.com> Date: Fri, 1 May 2026 17:35:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=88=BF=E9=97=B4=E7=BD=AE=E9=A1=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../room/query/RoomVoiceDiscoverQryExe.java | 19 ++++- .../app/common/live/OnlineRoomCommon.java | 17 +++- .../common/room/RoomRegionFilterCommon.java | 11 ++- .../common/room/RoomVoiceProfileCommon.java | 1 + .../query/RoomVoiceDiscoverQryExeTest.java | 82 +++++++++++++++++++ .../room/RoomRegionFilterCommonTest.java | 26 ++++++ .../room/RoomVoiceProfileCommonTest.java | 2 + .../clientobject/room/RoomVoiceProfileCO.java | 8 ++ .../service/live/RoomTopFixedService.java | 5 ++ .../live/impl/ActiveVoiceRoomServiceImpl.java | 6 +- .../live/impl/RoomTopFixedServiceImpl.java | 25 +++++- .../impl/ActiveVoiceRoomServiceImplTest.java | 10 +-- .../ActiveVoiceRoomClientServiceImpl.java | 17 +++- .../live/impl/HotRoomClientServiceImpl.java | 79 +++++++++++++++++- 14 files changed, 283 insertions(+), 25 deletions(-) diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExe.java index 6378c7c8..5c5e9ca5 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExe.java @@ -68,6 +68,7 @@ public class RoomVoiceDiscoverQryExe { private static final String EMPTY_ROOM_CACHE_KEY = "empty_room_cache:*"; private static final String MEMBER_QUANTITY_EXT_KEY = "memberQuantity"; + private static final String FIXED_WEIGHTS_EXT_KEY = "fixedWeights"; private static final int DISCOVERY_LIMIT = 50; private static final long DISCOVERY_SLOW_STEP_MILLIS = 100L; private static final long DISCOVERY_SLOW_TOTAL_MILLIS = 300L; @@ -164,7 +165,7 @@ public class RoomVoiceDiscoverQryExe { DISCOVERY_LIMIT); } stepStart = logDiscoveryStep("fallback-room-profiles", stepStart, reqUserId, sysOrigin, region); - roomList = sortByMemberQuantityDesc(roomList); + roomList = sortByTopWeightAndMemberQuantityDesc(roomList); stepStart = logDiscoveryStep("sort-rooms", stepStart, reqUserId, sysOrigin, region); if (CollectionUtils.isEmpty(roomList)) { @@ -194,20 +195,30 @@ public class RoomVoiceDiscoverQryExe { return roomList; } - private List sortByMemberQuantityDesc(List roomList) { + private List sortByTopWeightAndMemberQuantityDesc( + List roomList) { if (CollectionUtils.isEmpty(roomList)) { return CollectionUtils.newArrayList(); } return roomList.stream() - .sorted(Comparator.comparingInt(this::roomMemberQuantity).reversed()) + .sorted(Comparator.comparingInt(this::roomFixedWeights).reversed() + .thenComparing(Comparator.comparingInt(this::roomMemberQuantity).reversed())) .toList(); } + private int roomFixedWeights(RoomVoiceProfileCO room) { + return roomIntExtValue(room, FIXED_WEIGHTS_EXT_KEY); + } + private int roomMemberQuantity(RoomVoiceProfileCO room) { + return roomIntExtValue(room, MEMBER_QUANTITY_EXT_KEY); + } + + private int roomIntExtValue(RoomVoiceProfileCO room, String key) { if (Objects.isNull(room) || Objects.isNull(room.getExtValues())) { return 0; } - Object value = room.getExtValues().get(MEMBER_QUANTITY_EXT_KEY); + Object value = room.getExtValues().get(key); if (value instanceof Number number) { return Math.max(number.intValue(), 0); } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/live/OnlineRoomCommon.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/live/OnlineRoomCommon.java index 30d6af82..adc96afb 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/live/OnlineRoomCommon.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/live/OnlineRoomCommon.java @@ -19,6 +19,8 @@ import com.red.circle.other.infra.database.mongo.entity.live.assist.FamilyProfil import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService; import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; import com.red.circle.other.infra.database.mongo.service.live.RoomTopFixedService; +import com.red.circle.other.infra.database.mongo.entity.user.region.SysRegionConfig; +import com.red.circle.other.infra.database.mongo.service.user.region.SysRegionConfigService; import com.red.circle.other.infra.database.mongo.service.user.status.OnlineUserService; import com.red.circle.other.infra.database.rds.entity.family.FamilyMemberInfo; import com.red.circle.other.infra.database.rds.service.family.FamilyMemberInfoService; @@ -51,6 +53,7 @@ public class OnlineRoomCommon { private final OnlineUserService onlineUserService; private final UserProfileGateway userProfileGateway; private final RoomTopFixedService roomTopFixedService; + private final SysRegionConfigService sysRegionConfigService; private final HotRoomCacheService hotRoomCacheService; private final ActiveVoiceRoomService activeVoiceRoomService; private final FamilyMemberInfoService familyMemberInfoService; @@ -127,7 +130,7 @@ public class OnlineRoomCommon { // ? ActiveVoiceRegion.LANG_AR // : ActiveVoiceRegion.toRegion(userProfile.getCountryCode()); - RoomTopFixed roomTopFixed = roomTopFixedService.getByRoomId(room.getId()); + RoomTopFixed roomTopFixed = roomTopFixedService.getEffectiveByRoomId(room.getId()); Integer roomTopFixedWeights = Optional.ofNullable(roomTopFixed) .map(fixed -> Objects.nonNull(fixed.getWeights()) ? fixed.getWeights() : 0) .orElse(0); @@ -150,7 +153,7 @@ public class OnlineRoomCommon { .setCountryCode(StringUtils.toUpperCase(userProfile.getCountryCode())) .setCountryName(userProfile.getCountryName()) // ALL所有、DEFAULT默认区域、其他根据语言分割. - .setRegion(roomOwnRegionCode) + .setRegion(resolveActiveRoomRegion(roomOwnRegionCode, roomTopFixed)) .setExpiredTime(TimestampUtils.nowPlusMinutes(topRoomForeverOnline ? 60 : 3)) .setCreateTime(TimestampUtils.now()) .setUpdateTime(TimestampUtils.now()) @@ -161,6 +164,16 @@ public class OnlineRoomCommon { ); } + private String resolveActiveRoomRegion(String defaultRegionCode, RoomTopFixed roomTopFixed) { + if (Objects.isNull(roomTopFixed) || StringUtils.isBlank(roomTopFixed.getRegion())) { + return defaultRegionCode; + } + return Optional.ofNullable(sysRegionConfigService.getById(roomTopFixed.getRegion())) + .map(SysRegionConfig::getRegionCode) + .filter(StringUtils::isNotBlank) + .orElse(defaultRegionCode); + } + private FamilyProfile getFamilyProfile(Long userId) { FamilyMemberInfo memberInfo = familyMemberInfoService.getFamilyMemberByUserId(userId); diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomRegionFilterCommon.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomRegionFilterCommon.java index 71077356..ccc336e8 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomRegionFilterCommon.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomRegionFilterCommon.java @@ -56,16 +56,18 @@ public class RoomRegionFilterCommon { public List filterActiveVoiceRoomsByRegion( List activeVoiceRooms, String regionCode) { - return filterByRegionCode(activeVoiceRooms, ActiveVoiceRoom::getUserId, regionCode); + return filterByRegionCode(activeVoiceRooms, ActiveVoiceRoom::getUserId, + ActiveVoiceRoom::getRegion, regionCode); } public List filterRoomProfileManagersByRegion( List roomProfileManagers, String regionCode) { - return filterByRegionCode(roomProfileManagers, RoomProfileManager::getUserId, regionCode); + return filterByRegionCode(roomProfileManagers, RoomProfileManager::getUserId, + item -> null, regionCode); } private List filterByRegionCode(List source, Function userIdGetter, - String regionCode) { + Function regionCodeGetter, String regionCode) { if (CollectionUtils.isEmpty(source) || StringUtils.isBlank(regionCode)) { return Lists.newArrayList(); } @@ -84,7 +86,8 @@ public class RoomRegionFilterCommon { } return source.stream() - .filter(item -> StringUtils.equalsIgnoreCase(regionCode, regionCodeMap.get(userIdGetter.apply(item)))) + .filter(item -> StringUtils.equalsIgnoreCase(regionCode, regionCodeGetter.apply(item)) + || StringUtils.equalsIgnoreCase(regionCode, regionCodeMap.get(userIdGetter.apply(item)))) .toList(); } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommon.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommon.java index 8c2d83bf..0dd7940b 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommon.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommon.java @@ -152,6 +152,7 @@ public class RoomVoiceProfileCommon { return null; } roomVoiceProfile.putRoomMemberQuantity(toRoomMemberQuantity(activeVoiceRoom.getOnlineQuantity())); + roomVoiceProfile.putFixedWeights(activeVoiceRoom.getFixedWeights()); roomVoiceProfile.setHotRoom(activeVoiceRoom.getHot()); roomVoiceProfile.setRoomGameIcon(""); roomVoiceProfile.setUserSVipLevel(SVIPLevelEnum.valueOf(activeVoiceRoom.getSuperVipLevel())); diff --git a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExeTest.java b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExeTest.java index 50d79401..0d662565 100644 --- a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExeTest.java +++ b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/room/query/RoomVoiceDiscoverQryExeTest.java @@ -124,6 +124,88 @@ class RoomVoiceDiscoverQryExeTest { verify(activeVoiceRoomService, never()).listDiscover("YOLO", true, "AE", null, 50); } + @Test + void execute_shouldKeepTopRoomBeforeHigherMemberRoom() { + UserSVipGateway userSVipGateway = mock(UserSVipGateway.class); + UserRegionGateway userRegionGateway = mock(UserRegionGateway.class); + RoomRegionFilterCommon roomRegionFilterCommon = mock(RoomRegionFilterCommon.class); + RoomVoiceProfileCommon roomVoiceProfileCommon = mock(RoomVoiceProfileCommon.class); + ActiveVoiceRoomService activeVoiceRoomService = mock(ActiveVoiceRoomService.class); + RoomUserBlacklistService roomUserBlacklistService = mock(RoomUserBlacklistService.class); + LatestMobileDeviceService latestMobileDeviceService = mock(LatestMobileDeviceService.class); + RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class); + RegionRoomCacheService regionRoomCacheService = mock(RegionRoomCacheService.class); + LiveMicClient liveMicClient = mock(LiveMicClient.class); + RedisTemplate redisTemplate = mock(RedisTemplate.class); + RocketStatusCacheService rocketStatusCacheService = mock(RocketStatusCacheService.class); + GameLudoService gameLudoService = mock(GameLudoService.class); + UserProfileGateway userProfileGateway = mock(UserProfileGateway.class); + CountryCodeAliasSupport countryCodeAliasSupport = mock(CountryCodeAliasSupport.class); + RoomVoiceDiscoverQryExe exe = new RoomVoiceDiscoverQryExe( + userSVipGateway, + userRegionGateway, + roomRegionFilterCommon, + roomVoiceProfileCommon, + activeVoiceRoomService, + roomUserBlacklistService, + latestMobileDeviceService, + roomProfileManagerService, + regionRoomCacheService, + liveMicClient, + redisTemplate, + rocketStatusCacheService, + gameLudoService, + userProfileGateway, + countryCodeAliasSupport + ); + + AppExtCommand cmd = new AppExtCommand(); + cmd.setReqUserId(1L); + cmd.setReqSysOrigin(ReqSysOrigin.of("YOLO", "YOLO")); + + RegionConfig currentRegion = new RegionConfig().setRegionCode("AE").setCountryCodes("AE,SA"); + UserProfile userProfile = new UserProfile(); + ActiveVoiceRoom activeVoiceRoom = new ActiveVoiceRoom().setId(101L).setUserId(201L); + RoomProfileManager fallbackRoomManager = new RoomProfileManager(); + fallbackRoomManager.setId(102L); + fallbackRoomManager.setUserId(202L); + + RoomVoiceProfileCO topRoomCo = new RoomVoiceProfileCO().setId(101L).setUserId(201L) + .putRoomMemberQuantity(0) + .putFixedWeights(100); + RoomVoiceProfileCO fallbackRoomCo = new RoomVoiceProfileCO().setId(102L).setUserId(202L) + .putRoomMemberQuantity(2); + + when(roomRegionFilterCommon.requireRegionConfig(1L)).thenReturn(currentRegion); + when(userProfileGateway.getByUserId(1L)).thenReturn(userProfile); + when(regionRoomCacheService.getRegionsRoom("YOLOAE")).thenReturn(null); + when(activeVoiceRoomService.listByRegion("YOLO", "AE", 50)).thenReturn(List.of(activeVoiceRoom)); + when(roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(List.of(activeVoiceRoom), "AE")) + .thenReturn(List.of(activeVoiceRoom)); + when(roomVoiceProfileCommon.toListRoomVoiceProfileCO(List.of(activeVoiceRoom))).thenReturn( + List.of(topRoomCo) + ); + when(roomRegionFilterCommon.listCountryCodes(currentRegion)).thenReturn(List.of("AE", "SA")); + when(roomProfileManagerService.listSelectiveLimitByCountryCodes( + "YOLO", List.of("AE", "SA"), List.of(101L), 50 + )).thenReturn(List.of(fallbackRoomManager)); + when(roomRegionFilterCommon.filterRoomProfileManagersByRegion( + List.of(fallbackRoomManager), "AE" + )).thenReturn(List.of(fallbackRoomManager)); + when(roomVoiceProfileCommon.listRoomVoiceProfilesV2(List.of(fallbackRoomManager))).thenReturn( + List.of(fallbackRoomCo) + ); + when(userSVipGateway.checkSVipIdentity(anySet())).thenReturn( + Map.of(201L, SVIPLevelEnum.NONE, 202L, SVIPLevelEnum.NONE) + ); + when(rocketStatusCacheService.batchGetRocketStatus(List.of(101L, 102L))).thenReturn(Map.of()); + when(gameLudoService.listGameCoverByRoomIds(List.of(101L, 102L))).thenReturn(Map.of()); + + List roomList = exe.execute(cmd); + + assertEquals(List.of(topRoomCo, fallbackRoomCo), roomList); + } + @Test void execute_shouldReturnAllRegionRoomsForWhiteListUser() { UserSVipGateway userSVipGateway = mock(UserSVipGateway.class); diff --git a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomRegionFilterCommonTest.java b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomRegionFilterCommonTest.java index 5669463d..4b43901d 100644 --- a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomRegionFilterCommonTest.java +++ b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomRegionFilterCommonTest.java @@ -34,6 +34,32 @@ class RoomRegionFilterCommonTest { assertEquals(List.of(currentRegionRoom), filteredRooms); } + @Test + void filterActiveVoiceRoomsByRegion_shouldKeepConfiguredRegionRooms() { + UserRegionGateway userRegionGateway = mock(UserRegionGateway.class); + RoomRegionFilterCommon roomRegionFilterCommon = new RoomRegionFilterCommon(userRegionGateway); + + ActiveVoiceRoom topRegionRoom = new ActiveVoiceRoom() + .setId(1001L) + .setUserId(2001L) + .setRegion("AE"); + ActiveVoiceRoom otherRegionRoom = new ActiveVoiceRoom() + .setId(1002L) + .setUserId(2002L) + .setRegion("SA"); + + when(userRegionGateway.mapRegionCode(Set.of(2001L, 2002L))).thenReturn( + Map.of(2001L, "SA", 2002L, "SA") + ); + + List filteredRooms = roomRegionFilterCommon.filterActiveVoiceRoomsByRegion( + List.of(topRegionRoom, otherRegionRoom), + "AE" + ); + + assertEquals(List.of(topRegionRoom), filteredRooms); + } + @Test void filterRoomProfileManagersByRegion_shouldKeepOnlyCurrentRegionRooms() { UserRegionGateway userRegionGateway = mock(UserRegionGateway.class); diff --git a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommonTest.java b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommonTest.java index d6c72f89..4b774cc0 100644 --- a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommonTest.java +++ b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/common/room/RoomVoiceProfileCommonTest.java @@ -42,6 +42,7 @@ class RoomVoiceProfileCommonTest { .setId(10001L) .setUserId(20001L) .setOnlineQuantity(6L) + .setFixedWeights(88) .setSuperVipLevel("NONE"); RoomProfileManager roomProfileManager = new RoomProfileManager(); @@ -75,6 +76,7 @@ class RoomVoiceProfileCommonTest { assertEquals(1, roomProfiles.size()); assertEquals("6", getExtValue(roomProfiles.get(0), "memberQuantity")); + assertEquals(88, getExtValue(roomProfiles.get(0), "fixedWeights")); } private Object getExtValue(RoomVoiceProfileCO roomVoiceProfileCO, String key) { diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/room/RoomVoiceProfileCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/room/RoomVoiceProfileCO.java index 039ccf4f..d64c5042 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/room/RoomVoiceProfileCO.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/room/RoomVoiceProfileCO.java @@ -154,6 +154,14 @@ public class RoomVoiceProfileCO extends ClientObject { return this; } + /** + * 设置房间置顶权重. + */ + public RoomVoiceProfileCO putFixedWeights(final Integer fixedWeights) { + putExtField("fixedWeights", Objects.isNull(fixedWeights) ? 0 : fixedWeights); + return this; + } + /** * 是否存在密码. */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomTopFixedService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomTopFixedService.java index e427a8fa..6e692ed4 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomTopFixedService.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomTopFixedService.java @@ -29,6 +29,11 @@ public interface RoomTopFixedService { */ RoomTopFixed getByRoomId(Long roomId); + /** + * 获取当前生效中的置顶房间. + */ + RoomTopFixed getEffectiveByRoomId(Long roomId); + /** * 房间置顶权重. */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImpl.java index 22a7e4d6..db02641d 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImpl.java @@ -126,7 +126,7 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService { if (Objects.nonNull(qryCmd.getOrderByStrategy())) { query.with( - Sort.by(Stream.of("onlineQuantity", "fixedWeights", "weights").map(Order::desc) + Sort.by(Stream.of("fixedWeights", "onlineQuantity", "weights").map(Order::desc) .toArray(Order[]::new))); } @@ -174,9 +174,9 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService { // 3. 排序逻辑 Aggregation.sort(Sort.by( + Sort.Order.desc("fixedWeightsScore"), // 如果区域不匹配,fixedWeights 为 0,不影响排序 Sort.Order.desc("onlineQuantity"), Sort.Order.desc("regionMatchScore"), - Sort.Order.desc("fixedWeightsScore"), // 如果区域不匹配,fixedWeights 为 0,不影响排序 Sort.Order.desc("weights") )), @@ -196,8 +196,8 @@ public class ActiveVoiceRoomServiceImpl implements ActiveVoiceRoomService { Criteria.where("sysOrigin").is(sysOrigin) .and("region").is(region) ).with(Sort.by( - Sort.Order.desc("onlineQuantity"), Sort.Order.desc("fixedWeights"), + Sort.Order.desc("onlineQuantity"), Sort.Order.desc("weights") )); diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomTopFixedServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomTopFixedServiceImpl.java index f19b23fd..e76bbbae 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomTopFixedServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomTopFixedServiceImpl.java @@ -6,7 +6,9 @@ import com.red.circle.framework.mybatis.constant.PageConstant; import com.red.circle.other.infra.database.mongo.entity.live.RoomTopFixed; import com.red.circle.other.infra.database.mongo.service.live.RoomTopFixedService; import com.red.circle.other.inner.model.cmd.sys.RoomTopFixedQryCmd; +import com.red.circle.tool.core.date.TimestampUtils; import com.red.circle.tool.core.text.StringUtils; +import java.sql.Timestamp; import java.util.Objects; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -44,7 +46,7 @@ public class RoomTopFixedServiceImpl implements RoomTopFixedService { } if (StringUtils.isNotBlank(query.getRegion())) { - criteria.and("region").lt(query.getRegion()); + criteria.and("region").is(query.getRegion()); } if (Objects.isNull(query.getLimit())) { @@ -64,13 +66,28 @@ public class RoomTopFixedServiceImpl implements RoomTopFixedService { return mongoTemplate.findOne(Query.query(Criteria.where("id").is(roomId)), RoomTopFixed.class); } + @Override + public RoomTopFixed getEffectiveByRoomId(Long roomId) { + return mongoTemplate.findOne(Query.query(effectiveCriteria(roomId)), RoomTopFixed.class); + } + @Override public Integer getWeights(Long roomId) { - Query query = Query.query(Criteria.where("id").is(roomId)); - query.fields().include("weights"); - return Optional.ofNullable(mongoTemplate.findOne(query, RoomTopFixed.class)) + return Optional.ofNullable(getEffectiveByRoomId(roomId)) .map(top -> Objects.nonNull(top.getWeights()) ? top.getWeights() : 0) .orElse(0); } + private Criteria effectiveCriteria(Long roomId) { + Timestamp now = TimestampUtils.now(); + return new Criteria().andOperator( + Criteria.where("id").is(roomId), + Criteria.where("startTime").lte(now), + new Criteria().orOperator( + Criteria.where("expiredTime").is(null), + Criteria.where("expiredTime").gt(now) + ) + ); + } + } diff --git a/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImplTest.java b/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImplTest.java index de562a7c..73a4ecf5 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImplTest.java +++ b/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/database/mongo/service/live/impl/ActiveVoiceRoomServiceImplTest.java @@ -43,15 +43,15 @@ class ActiveVoiceRoomServiceImplTest { assertEquals(50, query.getLimit()); Document sortObject = query.getSortObject(); - assertIterableEquals(List.of("onlineQuantity", "fixedWeights", "weights"), + assertIterableEquals(List.of("fixedWeights", "onlineQuantity", "weights"), sortObject.keySet()); - assertEquals(-1, sortObject.getInteger("onlineQuantity")); assertEquals(-1, sortObject.getInteger("fixedWeights")); + assertEquals(-1, sortObject.getInteger("onlineQuantity")); assertEquals(-1, sortObject.getInteger("weights")); } @Test - void listOps_shouldUseOnlineQuantityFirstForDiscoverySort() { + void listOps_shouldUseFixedWeightsFirstForDiscoverySort() { ArgumentCaptor queryCaptor = ArgumentCaptor.forClass(Query.class); when(mongoTemplate.find(queryCaptor.capture(), eq(ActiveVoiceRoom.class))).thenReturn(List.of()); @@ -63,10 +63,10 @@ class ActiveVoiceRoomServiceImplTest { service.listOps(cmd); Document sortObject = queryCaptor.getValue().getSortObject(); - assertIterableEquals(List.of("onlineQuantity", "fixedWeights", "weights"), + assertIterableEquals(List.of("fixedWeights", "onlineQuantity", "weights"), sortObject.keySet()); - assertEquals(-1, sortObject.getInteger("onlineQuantity")); assertEquals(-1, sortObject.getInteger("fixedWeights")); + assertEquals(-1, sortObject.getInteger("onlineQuantity")); assertEquals(-1, sortObject.getInteger("weights")); } } diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/ActiveVoiceRoomClientServiceImpl.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/ActiveVoiceRoomClientServiceImpl.java index 4192fe46..8e0223a4 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/ActiveVoiceRoomClientServiceImpl.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/ActiveVoiceRoomClientServiceImpl.java @@ -14,6 +14,8 @@ import com.red.circle.other.infra.database.mongo.entity.live.*; import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService; import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; import com.red.circle.other.infra.database.mongo.service.live.RoomTopFixedService; +import com.red.circle.other.infra.database.mongo.entity.user.region.SysRegionConfig; +import com.red.circle.other.infra.database.mongo.service.user.region.SysRegionConfigService; import com.red.circle.other.inner.model.cmd.live.AppActiveVoiceRoomQryCmd; import com.red.circle.other.inner.model.dto.live.ActiveVoiceRoomDTO; import java.util.List; @@ -43,6 +45,7 @@ public class ActiveVoiceRoomClientServiceImpl implements ActiveVoiceRoomClientSe private final UserProfileGateway userProfileGateway; private final UserRegionGateway userRegionGateway; private final RoomTopFixedService roomTopFixedService; + private final SysRegionConfigService sysRegionConfigService; @Override public Long count(String sysOrigin) { @@ -62,7 +65,7 @@ public class ActiveVoiceRoomClientServiceImpl implements ActiveVoiceRoomClientSe UserProfile userProfile = userProfileGateway.getByUserId(room.getUserId()); String roomOwnRegionCode = userRegionGateway.getRegionCode(room.getUserId()); - RoomTopFixed roomTopFixed = roomTopFixedService.getByRoomId(room.getId()); + RoomTopFixed roomTopFixed = roomTopFixedService.getEffectiveByRoomId(room.getId()); Integer roomTopFixedWeights = Optional.ofNullable(roomTopFixed) .map(fixed -> Objects.nonNull(fixed.getWeights()) ? fixed.getWeights() : 0) .orElse(0); @@ -89,7 +92,7 @@ public class ActiveVoiceRoomClientServiceImpl implements ActiveVoiceRoomClientSe .setCountryCode(StringUtils.toUpperCase(userProfile.getCountryCode())) .setCountryName(userProfile.getCountryName()) // ALL所有、DEFAULT默认区域、其他根据语言分割. - .setRegion(roomOwnRegionCode) + .setRegion(resolveActiveRoomRegion(roomOwnRegionCode, roomTopFixed)) .setExpiredTime(TimestampUtils.nowPlusMinutes(topRoomForeverOnline ? 60 : 3)) .setCreateTime(TimestampUtils.now()) .setUpdateTime(TimestampUtils.now()) @@ -100,5 +103,15 @@ public class ActiveVoiceRoomClientServiceImpl implements ActiveVoiceRoomClientSe ); } + private String resolveActiveRoomRegion(String defaultRegionCode, RoomTopFixed roomTopFixed) { + if (Objects.isNull(roomTopFixed) || StringUtils.isBlank(roomTopFixed.getRegion())) { + return defaultRegionCode; + } + return Optional.ofNullable(sysRegionConfigService.getById(roomTopFixed.getRegion())) + .map(SysRegionConfig::getRegionCode) + .filter(StringUtils::isNotBlank) + .orElse(defaultRegionCode); + } + } diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/HotRoomClientServiceImpl.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/HotRoomClientServiceImpl.java index aaf4fc38..e455836a 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/HotRoomClientServiceImpl.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/live/impl/HotRoomClientServiceImpl.java @@ -3,16 +3,21 @@ package com.red.circle.other.app.inner.service.live.impl; import com.red.circle.common.business.dto.cmd.PageRoomIdCmd; import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.dto.PageResult; +import com.red.circle.other.app.common.live.OnlineRoomCommon; import com.red.circle.other.app.inner.convertor.live.RoomProfileInnerConvertor; import com.red.circle.other.app.inner.service.live.HotRoomClientService; import com.red.circle.other.infra.database.cache.service.other.SetHotRoomCacheService; +import com.red.circle.other.infra.database.cache.service.user.RegionRoomCacheService; import com.red.circle.other.infra.database.mongo.entity.live.RoomProfile; +import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager; import com.red.circle.other.infra.database.mongo.entity.live.RoomTopFixed; import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; import com.red.circle.other.infra.database.mongo.service.live.RoomTopFixedService; +import com.red.circle.other.infra.database.mongo.entity.user.region.SysRegionConfig; import com.red.circle.other.infra.database.mongo.service.user.region.SysRegionConfigService; import com.red.circle.other.infra.database.rds.entity.live.HotRoom; import com.red.circle.other.infra.database.rds.service.live.HotRoomService; +import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway; import com.red.circle.other.inner.asserts.RoomErrorCode; import com.red.circle.other.inner.model.cmd.sys.RoomTopFixedCmd; import com.red.circle.other.inner.model.cmd.sys.RoomTopFixedQryCmd; @@ -21,15 +26,21 @@ import com.red.circle.other.inner.model.dto.sys.SysHotRoomDTO; import com.red.circle.other.inner.model.dto.sys.SysTopRoomDTO; import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.date.TimestampUtils; +import com.red.circle.tool.core.text.StringUtils; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /** * @author lisizhe on 2020/12/11 */ +@Slf4j @Service @RequiredArgsConstructor public class HotRoomClientServiceImpl implements HotRoomClientService { @@ -38,8 +49,11 @@ public class HotRoomClientServiceImpl implements HotRoomClientService { private final RoomTopFixedService roomTopFixedService; private final SysRegionConfigService sysRegionConfigService; private final SetHotRoomCacheService setHotRoomCacheService; + private final RegionRoomCacheService regionRoomCacheService; private final RoomProfileInnerConvertor roomProfileInnerConvertor; private final RoomProfileManagerService roomProfileManagerService; + private final OnlineRoomCommon onlineRoomCommon; + private final UserRegionGateway userRegionGateway; @Override public void addOrUpdate(SysHotRoomCmd param) { @@ -124,11 +138,74 @@ public class HotRoomClientServiceImpl implements HotRoomClientService { public void addOrUpdateRoomTop(RoomTopFixedCmd param) { RoomProfile roomProfile = roomProfileManagerService.getProfileById(param.getId()); ResponseAssert.notNull(RoomErrorCode.ROOM_NOT_EXISTS, roomProfile); - roomTopFixedService.add(roomProfileInnerConvertor.toRoomTopFixed(param)); + RoomTopFixed oldRoomTopFixed = roomTopFixedService.getByRoomId(param.getId()); + RoomTopFixed newRoomTopFixed = roomProfileInnerConvertor.toRoomTopFixed(param); + roomTopFixedService.add(newRoomTopFixed); + refreshActiveRoom(param.getId()); + removeDiscoveryCache(param.getId(), oldRoomTopFixed, newRoomTopFixed); } @Override public void removeRoomTop(Long roomId) { + RoomTopFixed oldRoomTopFixed = roomTopFixedService.getByRoomId(roomId); roomTopFixedService.removeById(roomId); + refreshActiveRoom(roomId); + removeDiscoveryCache(roomId, oldRoomTopFixed); + } + + private void refreshActiveRoom(Long roomId) { + try { + onlineRoomCommon.addHeartbeatOnlineRoomProfileById(roomId); + } catch (Exception e) { + log.warn("刷新置顶房间在线数据失败 roomId={}", roomId, e); + } + } + + private void removeDiscoveryCache(Long roomId, RoomTopFixed... roomTopFixedConfigs) { + try { + Map> regionsBySysOrigin = new HashMap<>(); + appendTopRoomRegions(regionsBySysOrigin, roomTopFixedConfigs); + appendOwnerRegion(regionsBySysOrigin, roomId); + + regionsBySysOrigin.forEach((sysOrigin, regions) -> regions.forEach(regionCode -> { + regionRoomCacheService.remove(sysOrigin + regionCode); + regionRoomCacheService.remove(sysOrigin + regionCode + ":ALL_REGION"); + })); + } catch (Exception e) { + log.warn("清理置顶房间发现缓存失败 roomId={}", roomId, e); + } + } + + private void appendTopRoomRegions(Map> regionsBySysOrigin, + RoomTopFixed... roomTopFixedConfigs) { + if (Objects.isNull(roomTopFixedConfigs)) { + return; + } + for (RoomTopFixed roomTopFixed : roomTopFixedConfigs) { + if (Objects.isNull(roomTopFixed) || StringUtils.isBlank(roomTopFixed.getSysOrigin()) + || StringUtils.isBlank(roomTopFixed.getRegion())) { + continue; + } + SysRegionConfig regionConfig = sysRegionConfigService.getById(roomTopFixed.getRegion()); + if (Objects.isNull(regionConfig) || StringUtils.isBlank(regionConfig.getRegionCode())) { + continue; + } + regionsBySysOrigin.computeIfAbsent(roomTopFixed.getSysOrigin(), key -> new HashSet<>()) + .add(regionConfig.getRegionCode()); + } + } + + private void appendOwnerRegion(Map> regionsBySysOrigin, Long roomId) { + RoomProfileManager roomProfile = roomProfileManagerService.getById(roomId); + if (Objects.isNull(roomProfile) || StringUtils.isBlank(roomProfile.getSysOrigin()) + || Objects.isNull(roomProfile.getUserId())) { + return; + } + String ownerRegionCode = userRegionGateway.getRegionCode(roomProfile.getUserId()); + if (StringUtils.isBlank(ownerRegionCode)) { + return; + } + regionsBySysOrigin.computeIfAbsent(roomProfile.getSysOrigin(), key -> new HashSet<>()) + .add(ownerRegionCode); } }