|
@@ -4,9 +4,11 @@ import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
import com.ym.mec.auth.api.client.SysUserFeignService;
|
|
|
import com.ym.mec.auth.api.entity.SysUser;
|
|
|
import com.ym.mec.biz.dal.dao.ImLiveBroadcastRoomDao;
|
|
@@ -16,6 +18,7 @@ import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoom;
|
|
|
import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomData;
|
|
|
import com.ym.mec.biz.dal.entity.ImLiveBroadcastRoomMember;
|
|
|
import com.ym.mec.biz.dal.enums.MessageTypeEnum;
|
|
|
+import com.ym.mec.biz.dal.vo.BaseRoomUserVo;
|
|
|
import com.ym.mec.biz.dal.vo.ImLiveBroadcastRoomVo;
|
|
|
import com.ym.mec.biz.dal.vo.RoomUserInfoVo;
|
|
|
import com.ym.mec.biz.service.*;
|
|
@@ -32,6 +35,7 @@ import com.ym.mec.util.http.HttpUtil;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
import org.redisson.api.RBucket;
|
|
|
+import org.redisson.api.RLock;
|
|
|
import org.redisson.api.RMap;
|
|
|
import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
@@ -43,8 +47,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.io.Serializable;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.function.BiConsumer;
|
|
|
+import java.util.function.BiFunction;
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
@@ -73,11 +80,14 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
@Autowired
|
|
|
private ImLiveBroadcastRoomDataService liveBroadcastRoomDataService;
|
|
|
|
|
|
+ //待替换的变量
|
|
|
public static final String USER_ID = "${userId}";
|
|
|
public static final String ROOM_UID = "${roomUid}";
|
|
|
|
|
|
//直播间累计用户信息-指只要进入到该房间的用户都要记录
|
|
|
public static final String LIVE_ROOM_TOTAL_USER_LIST = "IM:LIVE_ROOM_TOTAL_USER_LIST:" + ROOM_UID;
|
|
|
+ //直播间在线用户信息
|
|
|
+ public static final String LIVE_ROOM_ONLINE_USER_LIST = "IM:LIVE_ROOM_ONLINE_USER_LIST:" + ROOM_UID;
|
|
|
//主讲人信息
|
|
|
public static final String LIVE_SPEAKER_INFO = "IM:LIVE_SPEAKER_INFO:" + USER_ID;
|
|
|
//用户对应的直播间Uid
|
|
@@ -86,6 +96,8 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
public static final String LIVE_USER_STATE_TIME = "IM:LIVE_USER_STATE_TIME:" + USER_ID;
|
|
|
//房间点赞数
|
|
|
public static final String LIVE_ROOM_LIKE = "IM:LIVE_ROOM_LIKE:" + ROOM_UID;
|
|
|
+ //计算人员观看时长锁
|
|
|
+ public static final String LIVE_LOOK_LOCK = "IM:LIVE_LOOK_LOCK:" + ROOM_UID;
|
|
|
//直播提前开始时间
|
|
|
public static final int PRE_LIVE_TIME_MINUTE = 30;
|
|
|
|
|
@@ -125,7 +137,6 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
return room;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* 查询直播间信息
|
|
|
*
|
|
@@ -133,15 +144,20 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
*/
|
|
|
@Override
|
|
|
public ImLiveBroadcastRoomVo queryRoomInfo(String roomUid) {
|
|
|
+ ImLiveBroadcastRoomVo roomVo = getImLiveBroadcastRoomVo(roomUid);
|
|
|
+ if (roomVo == null) return null;
|
|
|
+ getRoomData(roomVo);
|
|
|
+ return roomVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ private ImLiveBroadcastRoomVo getImLiveBroadcastRoomVo(String roomUid) {
|
|
|
List<ImLiveBroadcastRoomVo> list = baseMapper.queryPage(new HashMap<String, Object>() {{
|
|
|
put("roomUid", roomUid);
|
|
|
}});
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
|
return null;
|
|
|
}
|
|
|
- ImLiveBroadcastRoomVo roomVo = list.get(0);
|
|
|
- getRoomData(roomVo);
|
|
|
- return roomVo;
|
|
|
+ return list.get(0);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -235,10 +251,61 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
obj.setRoomState(1);
|
|
|
obj.setUpdatedBy(getSysUser().getId());
|
|
|
obj.setUpdatedTime(new Date());
|
|
|
+ obj.setPopularize(0);
|
|
|
this.updateById(obj);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 推广直播间-每个机构只能有一个直播间在首页推广
|
|
|
+ *
|
|
|
+ * @param id 直播间id
|
|
|
+ * @param popularize 是否在首页推广 0否 1是
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public void opsPopularize(Integer id, Integer popularize) {
|
|
|
+ if (!WrapperUtil.checkInObj(popularize, 0, 1)) {
|
|
|
+ throw new BizException("参数错误");
|
|
|
+ }
|
|
|
+ Optional<ImLiveBroadcastRoom> roomOptional = Optional.ofNullable(id)
|
|
|
+ .map(this::getById);
|
|
|
+ roomOptional.orElseThrow(() -> new BizException("直播间不存在"));
|
|
|
+ roomOptional.filter(room -> room.getRoomState() == 0)
|
|
|
+ .orElseThrow(() -> new BizException("直播间已经删除,无法设置推广"));
|
|
|
+ roomOptional.filter(room -> room.getLiveState() != 2)
|
|
|
+ .orElseThrow(() -> new BizException("直播已结束,无法设置推广"));
|
|
|
+ ImLiveBroadcastRoom obj = roomOptional.get();
|
|
|
+ if (Objects.equals(obj.getPopularize(), popularize)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //推广该直播间,先清除其该机构他直播间的推广状态
|
|
|
+ if (popularize == 1) {
|
|
|
+ this.update(Wrappers.<ImLiveBroadcastRoom>lambdaUpdate()
|
|
|
+ .set(ImLiveBroadcastRoom::getPopularize, 0)
|
|
|
+ .eq(ImLiveBroadcastRoom::getRoomState, 0)
|
|
|
+ .eq(ImLiveBroadcastRoom::getTenantId, obj.getTenantId()));
|
|
|
+ }
|
|
|
+ //更新直播间推广状态
|
|
|
+ obj.setPopularize(popularize);
|
|
|
+ this.updateById(obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询该机构目前推广的直播间
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public ImLiveBroadcastRoomVo queryPopularizeRoom() {
|
|
|
+ Map<String, Object> param = new HashMap<>();
|
|
|
+ param.put("tenantId", TenantContextHolder.getTenantId());
|
|
|
+ param.put("popularize", 1);
|
|
|
+ List<ImLiveBroadcastRoomVo> list = baseMapper.queryPage(param);
|
|
|
+ if (CollectionUtils.isNotEmpty(list)) {
|
|
|
+ return list.get(0);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 定时任务,每分钟执行
|
|
|
* 销毁主讲人退出超过30分钟的直播间
|
|
|
*/
|
|
@@ -281,7 +348,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
|
|
|
//1.主播没有进入房间,则直接销毁房间
|
|
|
if (Objects.isNull(speakerInfo.getJoinRoomTime())) {
|
|
|
- log.info("roomDestroy not joinRoom >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid(), room.getSpeakerId())));
|
|
|
+ log.info("roomDestroy not joinRoom >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid())));
|
|
|
roomDestroy(room);
|
|
|
return;
|
|
|
}
|
|
@@ -293,7 +360,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
//如果退出时间大于进入时间,就将退出时间+expiredMinute分钟
|
|
|
Date exitExpiredTime = DateUtil.addMinutes(speakerInfo.getExitRoomTime(), expiredMinute);
|
|
|
if (now.getTime() >= exitExpiredTime.getTime()) {
|
|
|
- log.info("roomDestroy exitExpiredTime >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid(), room.getSpeakerId())));
|
|
|
+ log.info("roomDestroy exitExpiredTime >>>> cache : {}", JSONObject.toJSONString(test(room.getRoomUid())));
|
|
|
roomDestroy(room);
|
|
|
}
|
|
|
}
|
|
@@ -318,31 +385,25 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
if (room.getLiveState() == 0) {
|
|
|
throw new BizException("直播未开始");
|
|
|
}
|
|
|
+ if (room.getLiveState() == 2) {
|
|
|
+ throw new BizException("直播已经结束,请刷新数据!");
|
|
|
+ }
|
|
|
+ //销毁房间
|
|
|
roomDestroy(room);
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
+ CompletableFuture.runAsync(() -> insertAndCleanLiveData(roomUid, speakerId));
|
|
|
log.info("roomDestroy>>>> insertAndCleanLiveData {}", JSONObject.toJSONString(room));
|
|
|
|
|
|
//将房间状态改为已销毁
|
|
@@ -357,38 +418,43 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
room.setUpdatedBy(userId);
|
|
|
room.setUpdatedTime(date);
|
|
|
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());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//获取该直播间所有数据写入数据库-并清理缓存
|
|
|
private void insertAndCleanLiveData(String roomUid, Integer speakerId) {
|
|
|
+ Date now = new Date();
|
|
|
//总观看人数
|
|
|
- int totalLookNum = 0;
|
|
|
+ List<ImLiveBroadcastRoomMember> memberList = new ArrayList<>();
|
|
|
//获取直播间所有人数据写入 im_live_broadcast_room_member
|
|
|
- RMap<Integer, RoomUserInfoVo> roomTotalUserCache = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUserCache = getTotalUserCache(roomUid);
|
|
|
if (roomTotalUserCache.isExists()) {
|
|
|
List<RoomUserInfoVo> roomTotalUser = new ArrayList<>(roomTotalUserCache.values());
|
|
|
- List<ImLiveBroadcastRoomMember> memberList = new ArrayList<>();
|
|
|
- roomTotalUser.forEach(v -> {
|
|
|
+ for (RoomUserInfoVo v : roomTotalUser) {
|
|
|
ImLiveBroadcastRoomMember member = new ImLiveBroadcastRoomMember();
|
|
|
member.setTenantId(v.getTenantId());
|
|
|
member.setRoomUid(roomUid);
|
|
|
member.setUserId(v.getUserId());
|
|
|
member.setJoinTime(v.getFirstJoinTime());
|
|
|
- member.setTotalTime(v.getTotalViewTime());
|
|
|
+ member.setTotalTime(getLookMinutes(v.getDynamicLookTime(), now, v.getTotalViewTime()));
|
|
|
memberList.add(member);
|
|
|
- });
|
|
|
- if (CollectionUtils.isNotEmpty(memberList)) {
|
|
|
- liveBroadcastRoomMemberService.getDao().insertBatch(memberList);
|
|
|
- totalLookNum = roomTotalUser.size();
|
|
|
}
|
|
|
- //删除用户对应的直播间关系缓存
|
|
|
- roomTotalUser.stream()
|
|
|
- .map(RoomUserInfoVo::getUserId)
|
|
|
- .filter(Objects::nonNull)
|
|
|
- .forEach(id -> redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, id.toString())).delete());
|
|
|
- //删除直播间所有人数据
|
|
|
- roomTotalUserCache.clear();
|
|
|
}
|
|
|
|
|
|
//获取直播点赞
|
|
@@ -399,7 +465,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
//删除房间点赞数据
|
|
|
likeCache.delete();
|
|
|
}
|
|
|
-
|
|
|
+ int speakerLiveTime = 0;
|
|
|
//获取直播间主讲人信息 写入im_live_broadcast_room_data
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, speakerId.toString()));
|
|
|
if (speakerCache.isExists()) {
|
|
@@ -408,14 +474,35 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
liveData.setTenantId(speakerInfo.getTenantId());
|
|
|
liveData.setRoomUid(roomUid);
|
|
|
liveData.setLikeNum(like);
|
|
|
- liveData.setTotalUserNum(totalLookNum);
|
|
|
- liveData.setUpdatedTime(new Date());
|
|
|
- liveData.setLiveTime(speakerInfo.getTotalLiveTime());
|
|
|
+ liveData.setTotalUserNum(CollectionUtils.isNotEmpty(memberList) ? memberList.size() : 0);
|
|
|
+ liveData.setUpdatedTime(now);
|
|
|
+ liveData.setLiveTime(getLookMinutes(speakerInfo.getStartLiveTime(), now, speakerInfo.getTotalLiveTime()));
|
|
|
liveBroadcastRoomDataService.save(liveData);
|
|
|
//删除房间主讲人数据
|
|
|
speakerCache.delete();
|
|
|
+ //获取主讲人直播时长
|
|
|
+ speakerLiveTime = speakerInfo.getTotalLiveTime();
|
|
|
}
|
|
|
|
|
|
+ //写入im_live_broadcast_room_member表,校验用户观看时长,不能大于主讲人直播时长
|
|
|
+ if (CollectionUtils.isNotEmpty(memberList)) {
|
|
|
+ for (ImLiveBroadcastRoomMember member : memberList) {
|
|
|
+ if (member.getTotalTime() > speakerLiveTime) {
|
|
|
+ member.setTotalTime(speakerLiveTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Lists.partition(memberList, 500)
|
|
|
+ .forEach(list -> liveBroadcastRoomMemberService.getDao().insertBatch(list));
|
|
|
+ //删除用户对应的直播间关系缓存
|
|
|
+ memberList.stream()
|
|
|
+ .map(ImLiveBroadcastRoomMember::getUserId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .forEach(id -> redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, id.toString())).delete());
|
|
|
+ }
|
|
|
+ //删除直播间所有用户数据
|
|
|
+ roomTotalUserCache.delete();
|
|
|
+ //删除在线用户数据
|
|
|
+ getOnlineUserCache(roomUid).delete();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -458,7 +545,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
}
|
|
|
//将最新的时间写入缓存
|
|
|
- userStateTimeCache.set(userStateTime,5L, TimeUnit.MINUTES);
|
|
|
+ userStateTimeCache.set(userStateTime, 5L, TimeUnit.MINUTES);
|
|
|
//查询主讲人userId,若是主讲人
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userid));
|
|
|
if (speakerCache.isExists()) {
|
|
@@ -490,15 +577,19 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
Integer userId = Integer.valueOf(userid);
|
|
|
|
|
|
//从房间累计用户信息中查询该用户的信息
|
|
|
- RMap<Integer, RoomUserInfoVo> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUser = getTotalUserCache(roomUid);
|
|
|
//该房间未查询到用户数据则不处理
|
|
|
if (!roomTotalUser.isExists() && !roomTotalUser.containsKey(userId)) {
|
|
|
return;
|
|
|
}
|
|
|
//查询到用户数据
|
|
|
RoomUserInfoVo userInfo = roomTotalUser.get(userId);
|
|
|
+ //查询在线人员列表
|
|
|
+ RMap<Integer, BaseRoomUserVo> onlineUserInfo = getOnlineUserCache(roomUid);
|
|
|
+ //获取当前用户是否在房间状态 true在 false不在
|
|
|
+ boolean userOnline = onlineUserInfo.isExists() && onlineUserInfo.containsKey(userId);
|
|
|
//用户是在房间的状态 并且 突然离线 - 那么融云会发送用户离线消息-此刻就发送退出房间消息给主讲人
|
|
|
- if (userInfo.getState() == 0 && user.getStatus().equals("1")) {
|
|
|
+ if (userOnline && user.getStatus().equals("1")) {
|
|
|
ImRoomMessage message = new ImRoomMessage();
|
|
|
message.setFromUserId(userId.toString());
|
|
|
message.setToChatroomId(roomUid);
|
|
@@ -511,16 +602,16 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
log.info("opsRoom>>>> looker LOOKER_LOGIN_OUT : {}", JSONObject.toJSONString(userInfo));
|
|
|
}
|
|
|
- //每次退出房间计算当前用户观看时长
|
|
|
- int minutesBetween = getMinutesBetween(userInfo.getDynamicJoinTime(), now);
|
|
|
- userInfo.setTotalViewTime(userInfo.getTotalViewTime() + minutesBetween);
|
|
|
- //记录退出时间 并写入缓存
|
|
|
- userInfo.setLastOutTime(now);
|
|
|
- userInfo.setState(1);
|
|
|
+ //只有在主播开播后用户才有观看时间,才需要计算当前用户观看时长
|
|
|
+ if (Objects.nonNull(userInfo.getDynamicLookTime())) {
|
|
|
+ userInfo.setTotalViewTime(getLookMinutes(userInfo.getDynamicLookTime(), userInfo.getTotalViewTime()));
|
|
|
+ userInfo.setDynamicLookTime(null);
|
|
|
+ }
|
|
|
roomTotalUser.fastPut(userId, userInfo);
|
|
|
+ //从在线人员列表删除该人员
|
|
|
+ onlineUserInfo.fastRemove(userId);
|
|
|
log.info("opsRoom>>>> looker userInfo: {}", JSONObject.toJSONString(userInfo));
|
|
|
});
|
|
|
-
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -556,10 +647,18 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
* @param userId 用户id
|
|
|
*/
|
|
|
public void joinRoom(String roomUid, Integer userId) {
|
|
|
+ //查询房间信息
|
|
|
+ ImLiveBroadcastRoomVo imLiveBroadcastRoomVo = getImLiveBroadcastRoomVo(roomUid);
|
|
|
+ if (Objects.isNull(imLiveBroadcastRoomVo)) {
|
|
|
+ log.info("opsRoom>>>> joinRoom error roomUid: {}", roomUid);
|
|
|
+ return;
|
|
|
+ }
|
|
|
//记录用户当前房间uid
|
|
|
- redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, userId.toString())).set(roomUid);
|
|
|
+ redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, userId.toString())).set(roomUid, 12L, TimeUnit.HOURS);
|
|
|
+ //在线人员列表
|
|
|
+ RMap<Integer, BaseRoomUserVo> onlineUserInfo = getOnlineUserCache(roomUid);
|
|
|
//房间累计用户信息-指只要进入到该房间的用户都要记录
|
|
|
- RMap<Integer, RoomUserInfoVo> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUser = getTotalUserCache(roomUid);
|
|
|
//判断是否第一次进房间
|
|
|
RoomUserInfoVo userInfo;
|
|
|
Date now = new Date();
|
|
@@ -572,9 +671,18 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
userInfo.setFirstJoinTime(now);
|
|
|
userInfo.setTotalViewTime(0);
|
|
|
}
|
|
|
- userInfo.setState(0);//0 进入/在房间
|
|
|
- userInfo.setDynamicJoinTime(now);
|
|
|
+ //查询主讲人信息
|
|
|
+ RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, imLiveBroadcastRoomVo.getSpeakerId().toString()));
|
|
|
+ if (speakerCache.isExists()) {
|
|
|
+ //如果用户进来时主讲人已经开启直播则修改学生观看时间
|
|
|
+ Integer state = speakerCache.get().getState();
|
|
|
+ if (Objects.nonNull(state) && state == 0) {
|
|
|
+ userInfo.setDynamicLookTime(now);
|
|
|
+ }
|
|
|
+ }
|
|
|
roomTotalUser.fastPut(userId, userInfo);
|
|
|
+ //进入房间写如在线人员列表
|
|
|
+ onlineUserInfo.fastPut(userId, userInfo);
|
|
|
log.info("joinRoom>>>> userInfo: {}", JSONObject.toJSONString(userInfo));
|
|
|
}
|
|
|
|
|
@@ -584,10 +692,18 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
* @param roomUid 房间uid
|
|
|
*/
|
|
|
public void startLive(String roomUid, Integer userId) {
|
|
|
- //查询房间信息是否允许录像
|
|
|
+ //查询房间信息
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId.toString()));
|
|
|
+ if (!speakerCache.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
RoomSpeakerInfo roomSpeakerInfo = speakerCache.get();
|
|
|
- if (Objects.nonNull(roomSpeakerInfo.getWhetherVideo()) && roomSpeakerInfo.getWhetherVideo() == 0) {
|
|
|
+ //已是直播状态则直接返回
|
|
|
+ if (intEquals(roomSpeakerInfo.getState(), 0)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //是否允许录像
|
|
|
+ if (intEquals(roomSpeakerInfo.getWhetherVideo(), 0)) {
|
|
|
//开始录制视频
|
|
|
try {
|
|
|
imFeignService.startRecord(roomUid);
|
|
@@ -595,51 +711,110 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
log.error("startRecord error: {}", e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+ Date now = new Date();
|
|
|
//开始直播
|
|
|
roomSpeakerInfo.setState(0);
|
|
|
- roomSpeakerInfo.setStartLiveTime(new Date());
|
|
|
+ roomSpeakerInfo.setStartLiveTime(now);
|
|
|
speakerCache.set(roomSpeakerInfo);
|
|
|
log.info("startLive>>>> roomSpeakerInfo: {}", JSONObject.toJSONString(roomSpeakerInfo));
|
|
|
+ //主播开启直播,查询所有在直播间的用户并写入观看时间
|
|
|
+ CompletableFuture.runAsync(() -> this.asyncOpsLiveLookTime(roomUid, 1));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 关闭直播-录像
|
|
|
*
|
|
|
* @param roomUid 房间uid
|
|
|
+ * @param userId 老师id
|
|
|
*/
|
|
|
public void closeLive(String roomUid, Integer userId) {
|
|
|
//查询房间主播信息
|
|
|
RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId.toString()));
|
|
|
+ if (!speakerCache.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
RoomSpeakerInfo roomSpeakerInfo = speakerCache.get();
|
|
|
//关闭直播
|
|
|
closeLive(roomSpeakerInfo);
|
|
|
speakerCache.set(roomSpeakerInfo);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 关闭直播-录像
|
|
|
+ *
|
|
|
+ * @param roomSpeakerInfo 房间主播信息
|
|
|
+ */
|
|
|
private void closeLive(RoomSpeakerInfo roomSpeakerInfo) {
|
|
|
- boolean stateFlag = Objects.nonNull(roomSpeakerInfo.getState()) && roomSpeakerInfo.getState() == 0;
|
|
|
- if (Objects.nonNull(roomSpeakerInfo.getWhetherVideo()) && roomSpeakerInfo.getWhetherVideo() == 0
|
|
|
- && stateFlag) {
|
|
|
- //停止录制视频
|
|
|
+ //直播状态 true 直播中 false关闭直播
|
|
|
+ boolean stateFlag = intEquals(roomSpeakerInfo.getState(), 0);
|
|
|
+ //是否录像 true允许 false不允许
|
|
|
+ boolean whetherVideoFlag = intEquals(roomSpeakerInfo.getWhetherVideo(), 0);
|
|
|
+ //允许录像并在直播中
|
|
|
+ if (whetherVideoFlag && stateFlag) {
|
|
|
try {
|
|
|
+ //停止录制视频
|
|
|
imFeignService.stopRecord(roomSpeakerInfo.getRoomUid());
|
|
|
} catch (Exception e) {
|
|
|
log.error("stopRecord error: {}", e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
+ //直播状态 true 直播中
|
|
|
if (stateFlag) {
|
|
|
Date now = new Date();
|
|
|
roomSpeakerInfo.setEndLiveTime(now);
|
|
|
roomSpeakerInfo.setState(1);
|
|
|
- //计算时长
|
|
|
- int minutesBetween = getMinutesBetween(roomSpeakerInfo.getStartLiveTime(), now);
|
|
|
- int i = Objects.isNull(roomSpeakerInfo.getTotalLiveTime()) ? 0 : roomSpeakerInfo.getTotalLiveTime();
|
|
|
- roomSpeakerInfo.setTotalLiveTime(i + minutesBetween);
|
|
|
+ //如果开播时间和本次操作结束播放时间小于1分钟则不计算观看时间
|
|
|
+ int liveMinutes = getLookMinutes(roomSpeakerInfo.getStartLiveTime(), null);
|
|
|
+ if (liveMinutes > 1) {
|
|
|
+ //写入本次直播时长
|
|
|
+ roomSpeakerInfo.setTotalLiveTime(getLookMinutes(roomSpeakerInfo.getStartLiveTime(), roomSpeakerInfo.getTotalLiveTime()));
|
|
|
+ //关闭直播后异步执行计算房间人员观看时长
|
|
|
+ CompletableFuture.runAsync(() -> this.asyncOpsLiveLookTime(roomSpeakerInfo.getRoomUid(), 2));
|
|
|
+ }
|
|
|
+ //计算完后将开始直播时间设置为空,待下次开启后再计算
|
|
|
+ roomSpeakerInfo.setStartLiveTime(null);
|
|
|
}
|
|
|
log.info("closeLive>>>> roomSpeakerInfo: {}", JSONObject.toJSONString(roomSpeakerInfo));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 打开/关闭直播后-异步计算房间人员观看时长
|
|
|
+ *
|
|
|
+ * @param roomUid 房间uid
|
|
|
+ * @param type type 1:开始直播-开始录像 2:关闭直播关闭录像
|
|
|
+ */
|
|
|
+ private void asyncOpsLiveLookTime(String roomUid, Integer type) {
|
|
|
+ //加锁-避免快速点击开启直播和关闭直后异步执行后直播数据错误
|
|
|
+ boolean b = this.runIfLockCanGet(LIVE_LOOK_LOCK.replace(ROOM_UID, roomUid), () -> {
|
|
|
+ //查询所有在直播间的用户并计算观看时长
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUser = getTotalUserCache(roomUid);
|
|
|
+ if (!roomTotalUser.isExists()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //查询在线人员列表
|
|
|
+ RMap<Integer, BaseRoomUserVo> onlineUserInfo = getOnlineUserCache(roomUid);
|
|
|
+ roomTotalUser.forEach((id, userInfo) -> {
|
|
|
+ //获取当前用户是否在房间状态 true在 false不在
|
|
|
+ if (onlineUserInfo.isExists() && onlineUserInfo.containsKey(id)) {
|
|
|
+ if (type.equals(1)) {
|
|
|
+ //开启直播后对当前在房间的用户写入观看时间
|
|
|
+ userInfo.setDynamicLookTime(new Date());
|
|
|
+ } else if (type.equals(2)) {
|
|
|
+ userInfo.setTotalViewTime(getLookMinutes(userInfo.getDynamicLookTime(), userInfo.getTotalViewTime()));
|
|
|
+ userInfo.setDynamicLookTime(null);
|
|
|
+ } else {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ roomTotalUser.fastPut(id, userInfo);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }, 2, 1, TimeUnit.MINUTES);
|
|
|
+ if (!b) {
|
|
|
+ this.asyncOpsLiveLookTime(roomUid, type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 定时任务,每分钟执行
|
|
|
* 提前30分钟主动去融云注册并创建房间
|
|
|
*/
|
|
@@ -724,18 +899,24 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
roomVo.setLikeNum((int) like);
|
|
|
//累计总用户数量
|
|
|
- List<RoomUserInfoVo> roomUserInfoVos = queryTotalRoomUserInfo(roomVo.getRoomUid());
|
|
|
- if (CollectionUtils.isNotEmpty(roomUserInfoVos)) {
|
|
|
- roomVo.setTotalLookNum(roomUserInfoVos.size());
|
|
|
- //在房间观看用户数量
|
|
|
- roomVo.setLookNum(queryRoomUserInfo(roomUserInfoVos).size());
|
|
|
- } else {
|
|
|
- roomVo.setTotalLookNum(0);
|
|
|
- roomVo.setLookNum(0);
|
|
|
- }
|
|
|
-
|
|
|
+ roomVo.setTotalLookNum(getNum.apply(this::getTotalUserCache, roomVo.getRoomUid()));
|
|
|
+ //在房间观看用户数量
|
|
|
+ roomVo.setLookNum(getNum.apply(this::getOnlineUserCache, roomVo.getRoomUid()));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取房间缓存中的用户数量/观看人数
|
|
|
+ *
|
|
|
+ * <p> func:查询用户数量/观看人数的方法
|
|
|
+ * <p> roomUid :房间uid
|
|
|
+ * <p> return :用户数量/观看人数
|
|
|
+ */
|
|
|
+ private final BiFunction<Function<String, RMap<Integer, ?>>, String, Integer> getNum = (func, roomUid) -> Optional.of(roomUid)
|
|
|
+ .map(func)
|
|
|
+ .filter(RMap::isExists)
|
|
|
+ .map(RMap::size)
|
|
|
+ .orElse(0);
|
|
|
+
|
|
|
private SysUser getSysUser(Integer userId) {
|
|
|
return Optional.ofNullable(userId)
|
|
|
.map(sysUserFeignService::queryUserById)
|
|
@@ -751,7 +932,7 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
/**
|
|
|
* 测试
|
|
|
*/
|
|
|
- public Map<String, Object> test(String roomUid, Integer userId) {
|
|
|
+ public Map<String, Object> test(String roomUid) {
|
|
|
//test
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
|
//点赞数
|
|
@@ -763,13 +944,11 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
|
|
|
int totalLook = 0;
|
|
|
int look = 0;
|
|
|
- List<RoomUserInfoVo> inRoomUserInfo;
|
|
|
-
|
|
|
+ //正在房间观看的用户数据
|
|
|
+ List<BaseRoomUserVo> inRoomUserInfo = queryRoomOnlineUserInfo(roomUid);
|
|
|
//累计总观看的用户数量
|
|
|
List<RoomUserInfoVo> totalUserInfo = queryTotalRoomUserInfo(roomUid);
|
|
|
if (CollectionUtils.isNotEmpty(totalUserInfo)) {
|
|
|
- //正在房间观看的用户数据
|
|
|
- inRoomUserInfo = queryRoomUserInfo(totalUserInfo);
|
|
|
if (CollectionUtils.isNotEmpty(inRoomUserInfo)) {
|
|
|
look = inRoomUserInfo.size();
|
|
|
result.put("正在观看的人员信息", inRoomUserInfo);
|
|
@@ -781,9 +960,15 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
} else {
|
|
|
result.put("总人员数据", "没有人员数据");
|
|
|
}
|
|
|
+ String userId = "";
|
|
|
+ try {
|
|
|
+ String[] split = roomUid.split("-");
|
|
|
+ userId = split[1];
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
|
|
|
//获取主讲人信息
|
|
|
- RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId.toString()));
|
|
|
+ RBucket<RoomSpeakerInfo> speakerCache = redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, userId));
|
|
|
if (speakerCache.isExists()) {
|
|
|
result.put("主讲人信息", speakerCache.get());
|
|
|
} else {
|
|
@@ -802,37 +987,59 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
}
|
|
|
SysUser sysUser = sysUserFeignService.queryUserInfo();
|
|
|
String baseApiUrl = sysConfigDao.findConfigValue(SysConfigService.BASE_API_URL);
|
|
|
- StringBuffer pushUrl = new StringBuffer(baseApiUrl).append("/#/liveClassTransfer?roomUid=").append(roomUid);
|
|
|
sysMessageService.batchSendImGroupMessage(MessageTypeEnum.IM_SHARE_LIVE_URL, sysUser.getId().toString(), null, groupIds.split(","), null,
|
|
|
imLiveBroadcastRoomVo.getTenantName(), imLiveBroadcastRoomVo.getRoomTitle(), imLiveBroadcastRoomVo.getSpeakerName(),
|
|
|
DateUtil.format(imLiveBroadcastRoomVo.getLiveStartTime(), DateUtil.CHINESE_DATA_FORMAT_1),
|
|
|
- imLiveBroadcastRoomVo.getLiveRemark(), HttpUtil.getSortUrl(pushUrl.toString()));
|
|
|
+ imLiveBroadcastRoomVo.getLiveRemark(), HttpUtil.getSortUrl(baseApiUrl + "/#/liveClassTransfer?roomUid=" + roomUid));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 查询在观看直播的用户信息
|
|
|
+ * 查询直播间在线的用户
|
|
|
*
|
|
|
* @param roomUid 直播间uid
|
|
|
*/
|
|
|
@Override
|
|
|
- public List<RoomUserInfoVo> queryRoomUserInfo(String roomUid) {
|
|
|
- List<RoomUserInfoVo> roomUserInfoVos = queryTotalRoomUserInfo(roomUid);
|
|
|
- return queryRoomUserInfo(roomUserInfoVos);
|
|
|
+ public List<BaseRoomUserVo> queryRoomLimitOnlineUserInfo(String roomUid) {
|
|
|
+ RMap<Integer, BaseRoomUserVo> onlineUserCache = getOnlineUserCache(roomUid);
|
|
|
+ return onlineUserCache.values().stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .limit(200)
|
|
|
+ .collect(Collectors.toList());
|
|
|
}
|
|
|
|
|
|
- public List<RoomUserInfoVo> queryRoomUserInfo(List<RoomUserInfoVo> totalUserInfo) {
|
|
|
- return totalUserInfo.stream()
|
|
|
- .filter(o -> Objects.nonNull(o.getState()) && o.getState() == 0)
|
|
|
+ /**
|
|
|
+ * 查询直播间在线的用户
|
|
|
+ *
|
|
|
+ * @param roomUid 直播间uid
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<BaseRoomUserVo> queryRoomOnlineUserInfo(String roomUid) {
|
|
|
+ RMap<Integer, BaseRoomUserVo> onlineUserInfo = getOnlineUserCache(roomUid);
|
|
|
+ return onlineUserInfo.values().stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
.collect(Collectors.toList());
|
|
|
}
|
|
|
|
|
|
- public List<RoomUserInfoVo> queryTotalRoomUserInfo(String roomUid) {
|
|
|
- RMap<Integer, RoomUserInfoVo> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ /**
|
|
|
+ * 查询直播间所有用户信息
|
|
|
+ *
|
|
|
+ * @param roomUid 直播间uid
|
|
|
+ */
|
|
|
+ private List<RoomUserInfoVo> queryTotalRoomUserInfo(String roomUid) {
|
|
|
+ RMap<Integer, RoomUserInfoVo> roomTotalUser = getTotalUserCache(roomUid);
|
|
|
return roomTotalUser.values().stream()
|
|
|
.filter(Objects::nonNull)
|
|
|
.collect(Collectors.toList());
|
|
|
}
|
|
|
|
|
|
+ private RMap<Integer, BaseRoomUserVo> getOnlineUserCache(String roomUid) {
|
|
|
+ return redissonClient.getMap(LIVE_ROOM_ONLINE_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ }
|
|
|
+
|
|
|
+ private RMap<Integer, RoomUserInfoVo> getTotalUserCache(String roomUid) {
|
|
|
+ return redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ }
|
|
|
+
|
|
|
private RoomUserInfoVo getUserInfo(Integer userId) {
|
|
|
RoomUserInfoVo userInfo = new RoomUserInfoVo();
|
|
|
userInfo.setUserId(userId);
|
|
@@ -853,15 +1060,89 @@ 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()) {
|
|
|
return 0;
|
|
|
}
|
|
|
//课程结束时间-课程开始时间
|
|
|
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);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断Integer是否相等-null值不相等
|
|
|
+ *
|
|
|
+ * @param key1 第一个Integer
|
|
|
+ * @param key2 第二个Integer
|
|
|
+ * @return 相等 true 不相等 false
|
|
|
+ */
|
|
|
+ private boolean intEquals(Integer key1, Integer key2) {
|
|
|
+ return Objects.nonNull(key1) && Objects.nonNull(key2) && Objects.equals(key1, key2);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分布式锁
|
|
|
+ *
|
|
|
+ * @param lockName lockKey
|
|
|
+ * @param runnable 任务
|
|
|
+ * @param waitTime 等待抢锁的时间,若该key已被占用则等待抢锁。
|
|
|
+ * @param timeout 超时时间
|
|
|
+ * @param unit 时间单位
|
|
|
+ * @return true 锁成功 false 锁失败
|
|
|
+ */
|
|
|
+ public boolean runIfLockCanGet(final String lockName, Runnable runnable, final long waitTime, final long timeout, TimeUnit unit) {
|
|
|
+ RLock lock = redissonClient.getLock(lockName);
|
|
|
+ if (Objects.isNull(lock)) {
|
|
|
+ log.info("runIfLockCanGet lock is null lockName : {}", lockName);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (lock.tryLock(waitTime, timeout, unit)) {
|
|
|
+ if (Objects.nonNull(runnable)) {
|
|
|
+ runnable.run();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("runIfLockCanGet error lockName : {}", lockName, e);
|
|
|
+ throw new RuntimeException("runIfLockCanGet error lockName :" + lockName, e);
|
|
|
+ } finally {
|
|
|
+ this.unlock(lock);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解锁
|
|
|
+ */
|
|
|
+ public void unlock(RLock lock) {
|
|
|
+ if (lock.getHoldCount() != 0) {
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -913,10 +1194,16 @@ public class ImLiveBroadcastRoomServiceImpl extends ServiceImpl<ImLiveBroadcastR
|
|
|
this.speakerName = speakerName;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 直播状态 0 直播中 1关闭直播
|
|
|
+ */
|
|
|
public Integer getState() {
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 直播状态 0 直播中 1关闭直播
|
|
|
+ */
|
|
|
public void setState(Integer state) {
|
|
|
this.state = state;
|
|
|
}
|