|
@@ -1,13 +1,13 @@
|
|
|
package com.yonge.cooleshow.biz.dal.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
|
|
|
import com.yonge.cooleshow.auth.api.entity.SysUser;
|
|
|
import com.yonge.cooleshow.biz.dal.dao.LiveRoomDao;
|
|
|
import com.yonge.cooleshow.biz.dal.entity.*;
|
|
|
-import com.yonge.cooleshow.biz.dal.enums.CourseScheduleTypeEnum;
|
|
|
+import com.yonge.cooleshow.biz.dal.enums.CourseScheduleEnum;
|
|
|
import com.yonge.cooleshow.biz.dal.enums.RoomTypeEnum;
|
|
|
import com.yonge.cooleshow.biz.dal.service.CourseGroupService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
|
|
@@ -15,6 +15,7 @@ import com.yonge.cooleshow.biz.dal.service.LiveRoomService;
|
|
|
import com.yonge.cooleshow.biz.dal.service.SysConfigService;
|
|
|
import com.yonge.cooleshow.biz.dal.support.IMHelper;
|
|
|
import com.yonge.cooleshow.biz.dal.support.WrapperUtil;
|
|
|
+import com.yonge.cooleshow.biz.dal.vo.RoomVo;
|
|
|
import com.yonge.cooleshow.common.exception.BizException;
|
|
|
import com.yonge.toolset.utils.date.DateUtil;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
@@ -24,6 +25,7 @@ import org.redisson.api.RMap;
|
|
|
import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
@@ -33,6 +35,7 @@ import java.util.concurrent.TimeUnit;
|
|
|
import java.util.function.BiFunction;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
+import static com.yonge.cooleshow.biz.dal.constant.LiveRoomConstant.*;
|
|
|
import static com.yonge.cooleshow.biz.dal.constant.SysConfigConstant.DESTROY_EXPIRED_LIVE_ROOM_MINUTE;
|
|
|
import static com.yonge.cooleshow.biz.dal.constant.SysConfigConstant.PRE_CREATE_LIVE_ROOM_MINUTE;
|
|
|
|
|
@@ -59,22 +62,8 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
@Autowired
|
|
|
private SysConfigService sysConfigService;
|
|
|
|
|
|
- //替换的字符串
|
|
|
- public static final String USER_ID = "${userId}";
|
|
|
- public static final String ROOM_UID = "${roomUid}";
|
|
|
- //缓存排头
|
|
|
- public static final String COOLESHOW = "COOLESHOW";
|
|
|
-
|
|
|
- //直播间累计用户信息-指只要进入到该房间的用户都要记录
|
|
|
- public static final String LIVE_ROOM_TOTAL_USER_LIST = String.join(":", COOLESHOW, "LIVE_ROOM_TOTAL_USER_LIST" + ROOM_UID);
|
|
|
- //用户当前对应的直播间Uid
|
|
|
- public static final String LIVE_USER_ROOM = String.join(":", COOLESHOW, "LIVE_ROOM_USER", USER_ID);
|
|
|
- //房间点赞数
|
|
|
- public static final String LIVE_ROOM_LIKE = String.join(":", COOLESHOW, "LIVE_ROOM_LIKE", ROOM_UID);
|
|
|
//生成房间UID
|
|
|
public static BiFunction<Long, RoomTypeEnum, String> GenRoomUid = (userId, en) -> String.join("-", COOLESHOW, en.getCode(), userId.toString(), new Date().getTime() + "");
|
|
|
- //房间的信息
|
|
|
- public static final String LIVE_ROOM_INFO = String.join(":", COOLESHOW, "LIVE_ROOM_INFO", ROOM_UID);
|
|
|
|
|
|
@Override
|
|
|
public LiveRoomDao getDao() {
|
|
@@ -82,6 +71,26 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 根据房间uid查询房间信息
|
|
|
+ *
|
|
|
+ * @param roomUid 房间uid
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public RoomVo queryRoomInfo(String roomUid) {
|
|
|
+ LiveRoom liveRoom = this.getOne(Wrappers.<LiveRoom>lambdaQuery()
|
|
|
+ .eq(LiveRoom::getRoomUid, roomUid));
|
|
|
+ if (liveRoom == null) {
|
|
|
+ throw new BizException("房间不存在");
|
|
|
+ }
|
|
|
+ RoomVo roomVo = new RoomVo();
|
|
|
+ BeanUtils.copyProperties(liveRoom, roomVo);
|
|
|
+ roomVo.setSpeakerName(getSysUser(liveRoom.getSpeakerId()).getRealName());
|
|
|
+ roomVo.setLikeNum(getLike(roomUid));
|
|
|
+ roomVo.setLookNum(getLooker(roomUid));
|
|
|
+ return roomVo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 定时任务创建直播间
|
|
|
*/
|
|
|
@Override
|
|
@@ -96,8 +105,8 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
}
|
|
|
Date endTime = DateUtil.addMinutes(now, Integer.parseInt(preCreateRoomMinute));
|
|
|
//查询课时表生成直播间
|
|
|
- List<CourseSchedule> courseScheduleList = courseScheduleService.list(new QueryWrapper<CourseSchedule>().lambda()
|
|
|
- .eq(CourseSchedule::getType, CourseScheduleTypeEnum.LIVE.getCode())
|
|
|
+ List<CourseSchedule> courseScheduleList = courseScheduleService.list(Wrappers.<CourseSchedule>lambdaQuery()
|
|
|
+ .eq(CourseSchedule::getType, CourseScheduleEnum.LIVE.getCode())
|
|
|
.eq(CourseSchedule::getLock, 0)
|
|
|
.ge(CourseSchedule::getStartTime, now)
|
|
|
.le(CourseSchedule::getStartTime, endTime));
|
|
@@ -105,12 +114,18 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
return;
|
|
|
}
|
|
|
//获取课程组名称
|
|
|
- Map<Long, String> titleMap = courseScheduleList.stream()
|
|
|
+ Map<Long, String> titleMap = new HashMap<>();
|
|
|
+ //获取课程组介绍
|
|
|
+ Map<Long, String> remarkMap = new HashMap<>();
|
|
|
+ courseScheduleList.stream()
|
|
|
.map(CourseSchedule::getCourseGroupId)
|
|
|
.distinct()
|
|
|
.map(courseGroupService::getById)
|
|
|
.filter(Objects::nonNull)
|
|
|
- .collect(Collectors.toMap(CourseGroup::getId, CourseGroup::getName));
|
|
|
+ .forEach(courseGroup -> {
|
|
|
+ titleMap.put(courseGroup.getId(), courseGroup.getName());
|
|
|
+ remarkMap.put(courseGroup.getId(), courseGroup.getCourseIntroduce());
|
|
|
+ });
|
|
|
//生成课程对应的房间
|
|
|
RoomTypeEnum en = RoomTypeEnum.LIVE;
|
|
|
courseScheduleList.forEach(c -> {
|
|
@@ -119,6 +134,7 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
room.setCourseId(c.getId());
|
|
|
room.setRoomUid(GenRoomUid.apply(c.getTeacherId(), en));
|
|
|
room.setRoomTitle(titleMap.get(c.getCourseGroupId()));
|
|
|
+ room.setLiveRemark(remarkMap.get(c.getCourseGroupId()));
|
|
|
room.setSpeakerId(c.getTeacherId());
|
|
|
room.setLiveStartTime(c.getStartTime());
|
|
|
room.setLiveEndTime(c.getEndTime());
|
|
@@ -131,7 +147,6 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
//去融云创建房间及创建房间缓存信息
|
|
|
createLiveRoomInfo(room);
|
|
|
});
|
|
|
-
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -139,22 +154,24 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
*/
|
|
|
@Override
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- public void createTempLiveRoom(Map<String, Object> param) {
|
|
|
- String roomTitle = WrapperUtil.toStr(param, "roomTitle", "房间标题不能为空!");
|
|
|
- String liveRemark = WrapperUtil.toStr(param, "liveRemark", "直播间描述不能为空!");
|
|
|
- String coverPic = WrapperUtil.toStr(param, "coverPic", "直播间封面不能为空!");
|
|
|
+ public String createTempLiveRoom(Map<String, Object> param) {
|
|
|
//查询主讲人信息
|
|
|
SysUser sysUser = getSysUser();
|
|
|
- Long id = sysUser.getId();
|
|
|
Date now = new Date();
|
|
|
+ //当前时间有课程则不能开启直播
|
|
|
+ checkTempLive(sysUser.getId());
|
|
|
+ String roomTitle = WrapperUtil.toStr(param, "roomTitle", "房间标题不能为空!");
|
|
|
+ String liveRemark = WrapperUtil.toStr(param, "liveRemark", "直播间描述不能为空!");
|
|
|
+
|
|
|
+ Long id = sysUser.getId();
|
|
|
RoomTypeEnum en = RoomTypeEnum.TEMP;
|
|
|
+ String roomUid = GenRoomUid.apply(id, en);
|
|
|
LiveRoom room = new LiveRoom();
|
|
|
room.setCourseGroupId(-1L);
|
|
|
room.setCourseId(-1L);
|
|
|
- room.setRoomUid(GenRoomUid.apply(id, en));
|
|
|
+ room.setRoomUid(roomUid);
|
|
|
room.setRoomTitle(roomTitle);
|
|
|
room.setLiveRemark(liveRemark);
|
|
|
- room.setCoverPic(coverPic);
|
|
|
room.setSpeakerId(id);
|
|
|
room.setLiveStartTime(now);
|
|
|
room.setLiveState(0);
|
|
@@ -165,16 +182,44 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
this.save(room);
|
|
|
log.info("createTempLiveRoom>>>>>>room:{}", room.getRoomUid());
|
|
|
//去融云创建房间及创建房间缓存信息
|
|
|
- createLiveRoomInfo(room);
|
|
|
+ createLiveRoomInfo(room, sysUser);
|
|
|
+ return roomUid;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验开启临时直播间是否会有课程冲突
|
|
|
+ */
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private void checkTempLive(Long teacherId) {
|
|
|
+ //查询当前未锁的最近的一节课
|
|
|
+ CourseSchedule course = courseScheduleService.getOne(Wrappers.<CourseSchedule>lambdaQuery()
|
|
|
+ .eq(CourseSchedule::getTeacherId, teacherId)
|
|
|
+ .eq(CourseSchedule::getLock, 0)
|
|
|
+ .orderByDesc(CourseSchedule::getStartTime));
|
|
|
+ if (Objects.isNull(course)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Date now = new Date();
|
|
|
+ Boolean check = WrapperUtil.inInterSection(now, now, course.getStartTime(), course.getEndTime(), false);
|
|
|
+ if (check) {
|
|
|
+ //如果当前时间和课程时间有交集则不能开启临时直播
|
|
|
+ throw new BizException("当前有陪练课无法开启直播");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 去融云创建房间及创建房间缓存信息-直播间
|
|
|
*/
|
|
|
private void createLiveRoomInfo(LiveRoom room) {
|
|
|
+ //查询主讲人信息
|
|
|
+ SysUser sysUser = getSysUser(room.getSpeakerId());
|
|
|
+ createLiveRoomInfo(room, sysUser);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void createLiveRoomInfo(LiveRoom room, SysUser sysUser) {
|
|
|
try {
|
|
|
//生成主讲人信息
|
|
|
- createRoomInfoCache(room);
|
|
|
+ createRoomInfoCache(room, sysUser);
|
|
|
//去融云创建房间
|
|
|
createLiveRoom(room.getRoomUid(), room.getRoomTitle());
|
|
|
} catch (Exception e) {
|
|
@@ -183,13 +228,6 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
}
|
|
|
|
|
|
//生成主讲人信息
|
|
|
- private void createRoomInfoCache(LiveRoom room) {
|
|
|
- //查询主讲人信息
|
|
|
- SysUser sysUser = getSysUser(room.getSpeakerId());
|
|
|
- createRoomInfoCache(room, sysUser);
|
|
|
- }
|
|
|
-
|
|
|
- //生成主讲人信息
|
|
|
private void createRoomInfoCache(LiveRoom room, SysUser sysUser) {
|
|
|
RoomInfoCache roomCache = new RoomInfoCache();
|
|
|
roomCache.setSpeakerId(sysUser.getId());
|
|
@@ -209,6 +247,9 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
//生成0点赞
|
|
|
redissonClient.getBucket(LIVE_ROOM_LIKE.replace(ROOM_UID, room.getRoomUid()))
|
|
|
.set(0, 2L, TimeUnit.DAYS);
|
|
|
+ //生成房间人员列表数据
|
|
|
+ redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, room.getRoomUid()))
|
|
|
+ .expire(2L, TimeUnit.DAYS);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -242,7 +283,7 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
}
|
|
|
Date now = new Date();
|
|
|
//查询已经开始并且没有删除及销毁的直播间
|
|
|
- List<LiveRoom> list = this.list(new QueryWrapper<LiveRoom>().lambda()
|
|
|
+ List<LiveRoom> list = this.list(Wrappers.<LiveRoom>lambdaQuery()
|
|
|
.eq(LiveRoom::getRoomState, 0)
|
|
|
.eq(LiveRoom::getLiveState, 1)
|
|
|
.eq(LiveRoom::getType, RoomTypeEnum.LIVE.getCode())
|
|
@@ -288,25 +329,28 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
* @param roomUid 房间uid
|
|
|
* @param userId 用户id 主讲人或者用户的id
|
|
|
*/
|
|
|
- public void joinRoom(String roomUid, Long userId) {
|
|
|
+ public RoomInfoCache joinRoom(String roomUid, Long userId) {
|
|
|
//校验房间是否存在
|
|
|
RBucket<RoomInfoCache> roomInfoCache = redissonClient.getBucket(LIVE_ROOM_INFO.replace(ROOM_UID, roomUid));
|
|
|
- RoomInfoCache roomInfo;
|
|
|
- if (roomInfoCache.isExists()) {
|
|
|
- roomInfo = roomInfoCache.get();
|
|
|
- } else {
|
|
|
- throw new BizException("房间不存在!");
|
|
|
+ if (!roomInfoCache.isExists()) {
|
|
|
+ throw new BizException("直播还未开始!");
|
|
|
}
|
|
|
+ RoomInfoCache roomInfo = roomInfoCache.get();
|
|
|
+ roomInfo.setLikeNum(getLike(roomUid));
|
|
|
+ roomInfo.setLookNum(getLooker(roomUid));
|
|
|
+
|
|
|
+ //记录当前对应的房间uid
|
|
|
+ redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, userId.toString())).set(roomUid, 2L, TimeUnit.DAYS);
|
|
|
+
|
|
|
Date now = new Date();
|
|
|
//进入房间的是主讲人
|
|
|
if (roomInfo.getSpeakerId().equals(userId)) {
|
|
|
roomInfo.setSpeakerState(0);
|
|
|
roomInfo.setJoinRoomTime(now);
|
|
|
- roomInfoCache.set(roomInfo, 2L, TimeUnit.DAYS);
|
|
|
- return;
|
|
|
+ roomInfoCache.set(roomInfo);
|
|
|
+ return roomInfo;
|
|
|
}
|
|
|
- //进入房间的是学生 记录用户对应的当前房间uid
|
|
|
- redissonClient.getBucket(LIVE_USER_ROOM.replace(USER_ID, userId.toString())).set(roomUid);
|
|
|
+
|
|
|
//房间累计用户信息-指只要进入到该房间的用户都要记录
|
|
|
RMap<Long, RoomUserInfoCache> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
//判断是否第一次进房间
|
|
@@ -322,10 +366,11 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
userInfo.setUserName(sysUser.getRealName());
|
|
|
userInfo.setFirstJoinTime(now);
|
|
|
}
|
|
|
- userInfo.setState(0);//0 进入/在房间
|
|
|
+ userInfo.setState(0);//0:在房间 1:不在房间
|
|
|
userInfo.setDynamicJoinTime(now);
|
|
|
roomTotalUser.fastPut(userId, userInfo);
|
|
|
log.info("joinRoom>>>> userInfo: {}", JSONObject.toJSONString(userInfo));
|
|
|
+ return roomInfo;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -354,10 +399,10 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
* @param chatroomId 要查询的聊天室 ID(必传)
|
|
|
* @param userId 要查询的用户 ID(必传)
|
|
|
* @return true 在聊天室,false 不在聊天室
|
|
|
- * <p>有可能出现已退出聊天室后使用该功能查询,得到的结果是未退出聊天室
|
|
|
+ * <p>注意:有可能出现已退出聊天室后使用该功能查询,得到的结果是未退出聊天室
|
|
|
* <p>触发融云退出聊天室机制:
|
|
|
- * <p>1.聊天室中用户在离线 30 秒后有新消息产生时或离线后聊天室中产生 30 条消息时会被自动退出聊天室
|
|
|
- * <p>2.此状态需要聊天室中有新消息时才会进行同步
|
|
|
+ * <p>1.聊天室中用户在离线 30 秒后有新消息产生时状态改变为退出聊天室
|
|
|
+ * <p>2.离线后聊天室中产生 30 条消息时状态时状态改变为退出聊天室
|
|
|
*/
|
|
|
private boolean userExistInRoom(String chatroomId, String userId) {
|
|
|
log.info("userExistInRoom chatroomId : {} userId : {}", chatroomId, userId);
|
|
@@ -403,11 +448,40 @@ public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> impl
|
|
|
}
|
|
|
|
|
|
private List<RoomUserInfoCache> queryTotalRoomUserInfo(String roomUid) {
|
|
|
- RMap<Integer, RoomUserInfoCache> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
+ RMap<Long, RoomUserInfoCache> roomTotalUser = redissonClient.getMap(LIVE_ROOM_TOTAL_USER_LIST.replace(ROOM_UID, roomUid));
|
|
|
return roomTotalUser.values().stream()
|
|
|
.filter(Objects::nonNull)
|
|
|
.collect(Collectors.toList());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取房间点赞数
|
|
|
+ *
|
|
|
+ * @param roomUid 房间UId
|
|
|
+ * @return 点赞数
|
|
|
+ */
|
|
|
+ private int getLike(String roomUid) {
|
|
|
+ //点赞数
|
|
|
+ Object like = redissonClient.getBucket(LIVE_ROOM_LIKE.replace(ROOM_UID, roomUid)).get();
|
|
|
+ if (Objects.isNull(like)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return (int) like;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取房间当前观看人数
|
|
|
+ *
|
|
|
+ * @param roomUid 房间uid
|
|
|
+ * @return 当前观看人数
|
|
|
+ */
|
|
|
+ private int getLooker(String roomUid) {
|
|
|
+ List<RoomUserInfoCache> roomUserInfoCaches = queryRoomUserInfo(roomUid);
|
|
|
+ if (CollectionUtils.isEmpty(roomUserInfoCaches)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return roomUserInfoCaches.size();
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|