Browse Source

优化用户观看时长算法

hgw 3 years ago
parent
commit
f9bba3feba

+ 60 - 40
mec-biz/src/main/java/com/ym/mec/biz/service/impl/ImLiveBroadcastRoomServiceImpl.java

@@ -75,6 +75,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
     @Autowired
     private ImLiveBroadcastRoomDataService liveBroadcastRoomDataService;
 
+    //待替换的变量
     public static final String USER_ID = "${userId}";
     public static final String ROOM_UID = "${roomUid}";
 
@@ -375,25 +376,15 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
     }
 
     public void roomDestroy(ImLiveBroadcastRoom room) {
+        //10秒内同一个房间不能重复销毁-防重复销毁
+        RBucket<Object> bucket = redissonClient.getBucket("IM:ROOMDESTROY:" + room.getRoomUid());
+        if (!bucket.trySet(1, 10, TimeUnit.SECONDS)) {
+            return;
+        }
         log.error("roomDestroy>>>> room : {}", JSONObject.toJSONString(room));
         String roomUid = room.getRoomUid();
         Integer speakerId = room.getSpeakerId();
 
-        try {
-            //向聊天室发自定义消息踢出所有人
-            ImRoomMessage message = new ImRoomMessage();
-            message.setFromUserId(speakerId.toString());
-            message.setToChatroomId(roomUid);
-            message.setObjectName(ImRoomMessage.FORCED_OFFLINE);
-            imFeignService.publishRoomMsg(message);
-            log.info("roomDestroy>>>> FORCED_OFFLINE {}", JSONObject.toJSONString(message));
-            //销毁直播间
-            imFeignService.destroyLiveRoom(roomUid);
-            log.info("roomDestroy>>>> destroyLiveRoom {}", JSONObject.toJSONString(message));
-        } catch (Exception e) {
-            log.error("roomDestroy>>>> errorMsg{}", e.getMessage(), e.getCause());
-        }
-
         //获取所有直播间缓存数据并写入数据库后并清理缓存
         insertAndCleanLiveData(roomUid, speakerId);
         log.info("roomDestroy>>>> insertAndCleanLiveData {}", JSONObject.toJSONString(room));
@@ -412,6 +403,21 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
         room.setLiveEndTime(date);
         room.setPopularize(0);//销毁直播间后要关闭推广
         this.updateById(room);
+
+        //向聊天室发自定义消息踢出所有人
+        try {
+            ImRoomMessage message = new ImRoomMessage();
+            message.setFromUserId(speakerId.toString());
+            message.setToChatroomId(roomUid);
+            message.setObjectName(ImRoomMessage.FORCED_OFFLINE);
+            imFeignService.publishRoomMsg(message);
+            log.info("roomDestroy>>>> FORCED_OFFLINE {}", JSONObject.toJSONString(message));
+            //销毁直播间
+            imFeignService.destroyLiveRoom(roomUid);
+            log.info("roomDestroy>>>> destroyLiveRoom {}", JSONObject.toJSONString(message));
+        } catch (Exception e) {
+            log.error("roomDestroy>>>> errorMsg{}", e.getMessage(), e.getCause());
+        }
     }
 
     //获取该直播间所有数据写入数据库-并清理缓存
@@ -428,16 +434,9 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
                 member.setRoomUid(roomUid);
                 member.setUserId(v.getUserId());
                 member.setJoinTime(v.getFirstJoinTime());
-                member.setTotalTime(v.getTotalViewTime());
+                member.setTotalTime(getLookMinutes(v.getDynamicLookTime(), v.getTotalViewTime()));
                 memberList.add(member);
             }
-            //删除用户对应的直播间关系缓存
-            roomTotalUser.stream()
-                    .map(RoomUserInfoVo::getUserId)
-                    .filter(Objects::nonNull)
-                    .forEach(id -> redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, id.toString())).delete());
-            //删除直播间所有人数据
-            roomTotalUserCache.clear();
         }
 
         //获取直播点赞
@@ -459,7 +458,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
             liveData.setLikeNum(like);
             liveData.setTotalUserNum(CollectionUtils.isNotEmpty(memberList) ? memberList.size() : 0);
             liveData.setUpdatedTime(new Date());
-            liveData.setLiveTime(speakerInfo.getTotalLiveTime());
+            liveData.setLiveTime(getLookMinutes(speakerInfo.getStartLiveTime(), speakerInfo.getTotalLiveTime()));
             liveBroadcastRoomDataService.save(liveData);
             //删除房间主讲人数据
             speakerCache.delete();
@@ -475,7 +474,14 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
                 }
             }
             liveBroadcastRoomMemberService.getDao().insertBatch(memberList);
+            //删除用户对应的直播间关系缓存
+            memberList.stream()
+                    .map(ImLiveBroadcastRoomMember::getUserId)
+                    .filter(Objects::nonNull)
+                    .forEach(id -> redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, id.toString())).delete());
         }
+        //删除直播间所有用户数据
+        roomTotalUserCache.clear();
     }
 
     /**
@@ -573,8 +579,8 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
             }
             //只有在主播开播后用户才有观看时间,才需要计算当前用户观看时长
             if (Objects.nonNull(userInfo.getDynamicLookTime())) {
-                int minutesBetween = getMinutesBetween(userInfo.getDynamicLookTime(), now);
-                userInfo.setTotalViewTime(userInfo.getTotalViewTime() + minutesBetween);
+                userInfo.setTotalViewTime(getLookMinutes(userInfo.getDynamicLookTime(), userInfo.getTotalViewTime()));
+                userInfo.setDynamicLookTime(null);
             }
             //记录退出时间 并写入缓存
             userInfo.setState(1);
@@ -701,6 +707,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
         speakerCache.set(roomSpeakerInfo);
     }
 
+
     private void closeLive(RoomSpeakerInfo roomSpeakerInfo) {
         //直播状态 true 直播中 false关闭直播
         boolean stateFlag = Objects.nonNull(roomSpeakerInfo.getState()) && roomSpeakerInfo.getState() == 0;
@@ -720,15 +727,10 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
             Date now = new Date();
             roomSpeakerInfo.setEndLiveTime(now);
             roomSpeakerInfo.setState(1);
-            //计算时长方法
-            BiFunction<Date, Integer, Integer> getLookMinutes = (startDate, nowMinutes) -> {
-                int minutesBetween = getMinutesBetween(startDate, new Date());
-                minutesBetween += Objects.isNull(nowMinutes) ? 0 : nowMinutes;
-                return Math.max(minutesBetween, 0);
-            };
             //写入本次直播时长
-            int lookMinutes = getLookMinutes.apply(roomSpeakerInfo.getStartLiveTime(), roomSpeakerInfo.getTotalLiveTime());
-            roomSpeakerInfo.setTotalLiveTime(lookMinutes);
+            roomSpeakerInfo.setTotalLiveTime(getLookMinutes(roomSpeakerInfo.getStartLiveTime(), roomSpeakerInfo.getTotalLiveTime()));
+            //计算完后将开始直播时间设置为空,待下次开启后再计算
+            roomSpeakerInfo.setStartLiveTime(null);
             //主播关闭直播,查询所有在直播间的用户并计算观看时长
             RMap<Integer, RoomUserInfoVo> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomSpeakerInfo.getRoomUid()));
             if (!roomTotalUser.isExists()) {
@@ -737,8 +739,8 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
             roomTotalUser.forEach((id, userInfo) -> {
                 //对在房间的用户计算观看时长
                 if (Objects.nonNull(userInfo.getState()) && userInfo.getState() == 0) {
-                    Integer userLookMinutes = getLookMinutes.apply(userInfo.getDynamicLookTime(), userInfo.getTotalViewTime());
-                    userInfo.setTotalViewTime(userLookMinutes);
+                    userInfo.setTotalViewTime(getLookMinutes(userInfo.getDynamicLookTime(), userInfo.getTotalViewTime()));
+                    userInfo.setDynamicLookTime(null);
                     roomTotalUser.fastPut(id, userInfo);
                 }
             });
@@ -965,9 +967,25 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
         return userInfo;
     }
 
-    //计算时间差-分钟数不满一分钟为0
-    private int getMinutesBetween(Date startDT, Date endDT) {
-        if (Objects.isNull(startDT) || Objects.isNull(endDT)) {
+    /**
+     * 计算观看时长差-分钟数不满一分钟为0
+     *
+     * @param startDT    开始时间
+     * @param nowMinutes 现在观看时长
+     */
+    private int getLookMinutes(Date startDT, Integer nowMinutes) {
+        return getLookMinutes(startDT, new Date(), nowMinutes);
+    }
+
+    /**
+     * 计算观看时长差-分钟数不满一分钟为0
+     *
+     * @param startDT    开始时间
+     * @param endDT      结束时间
+     * @param nowMinutes 现在观看时长
+     */
+    private int getLookMinutes(Date startDT, Date endDT, Integer nowMinutes) {
+        if (Objects.isNull(startDT)) {
             return 0;
         }
         if (startDT.getTime() > endDT.getTime()) {
@@ -976,7 +994,9 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
         //课程结束时间-课程开始时间
         long durationTime = endDT.getTime() - startDT.getTime();
         //相差多少分钟
-        return new Long(durationTime / 1000 / 60).intValue();
+        int minutesBetween = new Long(durationTime / 1000 / 60).intValue();
+        minutesBetween += Objects.isNull(nowMinutes) ? 0 : nowMinutes;
+        return Math.max(minutesBetween, 0);
     }
 
     /**