|
@@ -0,0 +1,264 @@
|
|
|
+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.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.RoomTypeEnum;
|
|
|
+import com.yonge.cooleshow.biz.dal.service.CourseGroupService;
|
|
|
+import com.yonge.cooleshow.biz.dal.service.CourseScheduleService;
|
|
|
+import com.yonge.cooleshow.biz.dal.service.LiveRoomService;
|
|
|
+import com.yonge.cooleshow.biz.dal.support.IMHelper;
|
|
|
+import com.yonge.cooleshow.common.exception.BizException;
|
|
|
+import com.yonge.toolset.utils.date.DateUtil;
|
|
|
+import org.apache.commons.collections.CollectionUtils;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 直播房间与课程的关系表表(LiveRoom)表服务实现类
|
|
|
+ *
|
|
|
+ * @author hgw
|
|
|
+ * @since 2022-03-18 15:41:17
|
|
|
+ */
|
|
|
+@Service("liveRoomService")
|
|
|
+public class LiveRoomServiceImpl extends ServiceImpl<LiveRoomDao, LiveRoom> implements LiveRoomService {
|
|
|
+ private final static Logger log = LoggerFactory.getLogger(LiveRoomServiceImpl.class);
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private SysUserFeignService sysUserFeignService;
|
|
|
+ @Autowired
|
|
|
+ private IMHelper imHelper;
|
|
|
+ @Autowired
|
|
|
+ private RedissonClient redissonClient;
|
|
|
+ @Autowired
|
|
|
+ private CourseGroupService courseGroupService;
|
|
|
+ @Autowired
|
|
|
+ private CourseScheduleService courseScheduleService;
|
|
|
+
|
|
|
+ //替换的字符串
|
|
|
+ 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 = COOLESHOW + ":LIVE_ROOM_TOTAL_USER_LIST:" + ROOM_UID;
|
|
|
+ //主讲人信息
|
|
|
+ public static final String LIVE_SPEAKER_INFO = COOLESHOW + ":LIVE_SPEAKER_INFO:" + USER_ID;
|
|
|
+ //用户对应的直播间Uid
|
|
|
+ public static final String LIVE_USER_ROOM = COOLESHOW + ":LIVE_ROOM_USER:" + USER_ID;
|
|
|
+ //房间点赞数
|
|
|
+ public static final String LIVE_ROOM_LIKE = COOLESHOW + ":LIVE_ROOM_LIKE:" + ROOM_UID;
|
|
|
+ //生成房间UID
|
|
|
+ public static Function<Long, String> GenRoomUid = (userId) -> COOLESHOW + "-" + userId + "-" + new Date().getTime();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public LiveRoomDao getDao() {
|
|
|
+ return this.baseMapper;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 定时任务创建直播间
|
|
|
+ */
|
|
|
+ public void createLiveRoom() {
|
|
|
+ Date now = new Date();
|
|
|
+ Date endTime = DateUtil.addMinutes(now, 30);
|
|
|
+ //查询课时表生成直播间 这里错了
|
|
|
+ List<CourseSchedule> courseScheduleList = courseScheduleService.list(new QueryWrapper<CourseSchedule>().lambda()
|
|
|
+ .eq(CourseSchedule::getType, CourseScheduleTypeEnum.LIVE.getCode())
|
|
|
+ .eq(CourseSchedule::getLock, 0)
|
|
|
+ .ge(CourseSchedule::getStartTime, now)
|
|
|
+ .le(CourseSchedule::getStartTime, endTime));
|
|
|
+ if (CollectionUtils.isEmpty(courseScheduleList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ courseScheduleList.forEach(c -> {
|
|
|
+ LiveRoom room = new LiveRoom();
|
|
|
+ room.setCourseGroupId(c.getCourseGroupId());
|
|
|
+ room.setCourseId(c.getId());
|
|
|
+ room.setRoomUid(GenRoomUid.apply(c.getTeacherId()));
|
|
|
+ room.setSpeakerId(c.getTeacherId());
|
|
|
+ room.setLiveStartTime(c.getStartTime());
|
|
|
+ room.setLiveEndTime(c.getEndTime());
|
|
|
+ room.setLiveState(0);
|
|
|
+ room.setRoomState(0);
|
|
|
+ room.setType(RoomTypeEnum.LIVE.getCode());
|
|
|
+ room.setCreatedBy(-2L);
|
|
|
+ room.setCreatedTime(now);
|
|
|
+ this.save(room);
|
|
|
+ //生成主讲人信息
|
|
|
+ createSpeakerInfo(room);
|
|
|
+ //
|
|
|
+ //去融云创建房间
|
|
|
+ createLiveRoom(room.getRoomUid(), room.getRoomTitle());
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建临时房间-直播间
|
|
|
+ */
|
|
|
+ public void createTempLiveRoom(LiveRoom room) {
|
|
|
+ log.info("createLiveRoom>>>>>>roomUid:{}", room.getRoomUid());
|
|
|
+ try {
|
|
|
+
|
|
|
+ //临时课程没有课程组和课表
|
|
|
+ if (room.getType().equals(RoomTypeEnum.TEMP.getCode())) {
|
|
|
+ room.setCourseGroupId(0L);
|
|
|
+ room.setCourseId(0L);
|
|
|
+ }
|
|
|
+ //查询主讲人信息
|
|
|
+ SysUser sysUser = getSysUser();
|
|
|
+ if (Objects.isNull(sysUser)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ room.setRoomUid(GenRoomUid.apply(sysUser.getId()));
|
|
|
+ this.save(room);
|
|
|
+ //生成主讲人信息到缓存
|
|
|
+ createSpeakerInfo(room, sysUser);
|
|
|
+ //去融云创建房间
|
|
|
+ createLiveRoom(room.getRoomUid(), room.getRoomTitle());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(">>>>>>>>>> createLiveRoom error roomUid:{} msg:{}", room.getRoomUid(), e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //生成主讲人信息
|
|
|
+ private void createSpeakerInfo(LiveRoom room) {
|
|
|
+ //查询主讲人信息
|
|
|
+ SysUser sysUser = getSysUser(room.getSpeakerId());
|
|
|
+ if (Objects.isNull(sysUser)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ createSpeakerInfo(room, sysUser);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void createSpeakerInfo(LiveRoom room, SysUser sysUser) {
|
|
|
+ RoomSpeakerInfo speakerInfo = new RoomSpeakerInfo();
|
|
|
+ speakerInfo.setSpeakerId(sysUser.getId());
|
|
|
+ speakerInfo.setSpeakerName(sysUser.getRealName());
|
|
|
+ speakerInfo.setCreateRoomTime(new Date());
|
|
|
+ speakerInfo.setRoomUid(room.getRoomUid());
|
|
|
+ speakerInfo.setRoomType(room.getType());
|
|
|
+ //写入主讲人信息
|
|
|
+ redissonClient.getBucket(LIVE_SPEAKER_INFO.replace(USER_ID, room.getSpeakerId().toString())).set(speakerInfo);
|
|
|
+ //生成0点赞
|
|
|
+ redissonClient.getBucket(LIVE_ROOM_LIKE.replace(ROOM_UID, room.getRoomUid())).set(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建房间-聊天室
|
|
|
+ *
|
|
|
+ * @param roomId 房间Uid
|
|
|
+ * @param roomName 房间名称
|
|
|
+ */
|
|
|
+ private IMApiResultInfo createLiveRoom(String roomId, String roomName) {
|
|
|
+ IMApiResultInfo resultInfo;
|
|
|
+ try {
|
|
|
+ resultInfo = imHelper.createChatRoom(roomId, roomName);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("create chatRoom error >>>", e.getCause());
|
|
|
+ throw new RuntimeException("创建聊天室失败!");
|
|
|
+ }
|
|
|
+ if (!resultInfo.isSuccess()) {
|
|
|
+ log.error("create chatRoom error: {}", resultInfo.getErrorMessage());
|
|
|
+ throw new RuntimeException("创建聊天室失败!");
|
|
|
+ }
|
|
|
+ log.info("create chatRoom success: {}", roomId);
|
|
|
+ return resultInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 销毁房间-聊天室
|
|
|
+ *
|
|
|
+ * @param roomId 房间Uid
|
|
|
+ */
|
|
|
+ private IMApiResultInfo destroyLiveRoom(String roomId) {
|
|
|
+ //删除服务器房间
|
|
|
+ List<String> deleteRoomIds = new ArrayList<String>() {{
|
|
|
+ add(roomId);
|
|
|
+ }};
|
|
|
+ IMApiResultInfo resultInfo;
|
|
|
+ try {
|
|
|
+ resultInfo = imHelper.deleteChrm(deleteRoomIds);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException("关闭聊天室失败!");
|
|
|
+ }
|
|
|
+ if (!resultInfo.isSuccess()) {
|
|
|
+ log.error("destroy chatRoom error: {}", resultInfo.getErrorMessage());
|
|
|
+ throw new RuntimeException("关闭聊天室失败!");
|
|
|
+ }
|
|
|
+ return resultInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送消息
|
|
|
+ *
|
|
|
+ * @param message
|
|
|
+ */
|
|
|
+ private IMApiResultInfo publishRoomMessage(ImRoomMessage message) {
|
|
|
+ log.info("publishRoomMessage message : {}", JSONObject.toJSONString(message));
|
|
|
+ IMApiResultInfo resultInfo;
|
|
|
+ try {
|
|
|
+ resultInfo = imHelper.publishRoomMessage(message.getFromUserId(), message.getToChatroomId(), message);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException("消息发送失败" + e.getMessage());
|
|
|
+ }
|
|
|
+ if (!resultInfo.isSuccess()) {
|
|
|
+ log.error("publishRoomMessage chatRoom error: {}", resultInfo.getErrorMessage());
|
|
|
+ throw new RuntimeException("消息发送失败!");
|
|
|
+ }
|
|
|
+ return resultInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询用户是否在聊天室-不是实时的
|
|
|
+ *
|
|
|
+ * @param chatroomId 要查询的聊天室 ID(必传)
|
|
|
+ * @param userId 要查询的用户 ID(必传)
|
|
|
+ * @return true 在聊天室,false 不在聊天室
|
|
|
+ * <p>有可能出现已退出聊天室后使用该功能查询,得到的结果是未退出聊天室
|
|
|
+ * <p>触发融云退出聊天室机制:
|
|
|
+ * <p>1.聊天室中用户在离线 30 秒后有新消息产生时或离线后聊天室中产生 30 条消息时会被自动退出聊天室
|
|
|
+ * <p>2.此状态需要聊天室中有新消息时才会进行同步
|
|
|
+ */
|
|
|
+ private boolean userExistInRoom(String chatroomId, String userId) {
|
|
|
+ log.info("userExistInRoom chatroomId : {} userId : {}", chatroomId, userId);
|
|
|
+ IMApiResultInfo resultInfo;
|
|
|
+ try {
|
|
|
+ resultInfo = imHelper.isInChartRoom(chatroomId, userId);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException("查询失败" + e.getMessage());
|
|
|
+ }
|
|
|
+ if (!resultInfo.isSuccess()) {
|
|
|
+ log.error("userExistInRoom chatroomId : {} userId : {}", chatroomId, userId);
|
|
|
+ throw new RuntimeException("查询失败!");
|
|
|
+ }
|
|
|
+ return resultInfo.isSuccess() && resultInfo.getInChrm();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private SysUser getSysUser(Long userId) {
|
|
|
+ return Optional.ofNullable(userId)
|
|
|
+ .map(sysUserFeignService::queryUserById)
|
|
|
+ .orElseThrow(() -> new BizException("用户不存在"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private SysUser getSysUser() {
|
|
|
+ //修改机构基础信息
|
|
|
+ return Optional.ofNullable(sysUserFeignService.queryUserInfo())
|
|
|
+ .orElseThrow(() -> new BizException("用户不存在"));
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|