From 49922904ec37430728f2f9855ea06991d44e3cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E8=89=AF=28004796=29?= Date: Thu, 28 Dec 2023 21:35:37 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E8=AF=9D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-cai/pom.xml | 10 ++ .../java/com/ruoyi/cai/chat/ChatManager.java | 15 +- .../com/ruoyi/cai/domain/CaiUserCall.java | 3 + .../ruoyi/cai/service/CaiAnchorService.java | 2 + .../com/ruoyi/cai/service/CaiUserService.java | 2 + .../service/impl/CaiAnchorServiceImpl.java | 8 + .../cai/service/impl/CaiUserServiceImpl.java | 7 + .../com/ruoyi/cai/ws/bean/CallerRoom.java | 4 + .../java/com/ruoyi/cai/ws/bean/FdCtxData.java | 14 ++ .../main/java/com/ruoyi/cai/ws/bean/Room.java | 34 ++++ .../java/com/ruoyi/cai/ws/bean/RoomData.java | 15 ++ .../java/com/ruoyi/cai/ws/bean/UserData.java | 21 +++ .../ruoyi/cai/ws/cache/CallerRoomCache.java | 41 +++++ .../ruoyi/cai/ws/cache/FdCtxDataCache.java | 26 ++++ .../ruoyi/cai/ws/cache/OnlineDataCache.java | 20 +++ .../com/ruoyi/cai/ws/cache/RoomCtxCache.java | 24 +++ .../com/ruoyi/cai/ws/cache/RoomDataCache.java | 90 +++++++++++ .../com/ruoyi/cai/ws/cache/UserDataCache.java | 72 +++++++++ .../ruoyi/cai/ws/constant/HangUpEnums.java | 25 +++ .../ruoyi/cai/ws/constant/RedisConstant.java | 12 ++ .../cai/ws/constant/RoomStatusEnums.java | 64 ++++++++ .../cai/ws/manager/WebSocketManager.java | 128 ++++++++++++++- .../com/ruoyi/cai/ws/processon/OpenLogic.java | 147 ++++++++++++++++++ .../cai/ws/service/CheckConnectionDTO.java | 18 +++ .../com/ruoyi/cai/ws/service/RoomService.java | 89 +++++++++++ .../com/ruoyi/cai/ws/util/MapGetUtil.java | 51 ++++++ .../ruoyi/cai/ws/util/WsExceptionUtil.java | 16 ++ .../websocket/config/WebSocketConfig.java | 23 +-- .../ruoyi/websocket/handle/IOpenLogic.java | 9 ++ .../handler/PlusWebSocketHandler.java | 16 +- .../holder/WebSocketSessionHolder.java | 12 +- .../interceptor/PlusWebSocketInterceptor.java | 2 + .../listener/WebSocketTopicListener.java | 2 + .../ruoyi/websocket/util/WebSocketUtils.java | 12 +- 34 files changed, 984 insertions(+), 50 deletions(-) create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/CallerRoom.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/FdCtxData.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/Room.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/RoomData.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/UserData.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/CallerRoomCache.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/FdCtxDataCache.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/OnlineDataCache.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomCtxCache.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomDataCache.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/UserDataCache.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/HangUpEnums.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RedisConstant.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RoomStatusEnums.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/processon/OpenLogic.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/CheckConnectionDTO.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/RoomService.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/MapGetUtil.java create mode 100644 ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/WsExceptionUtil.java create mode 100644 ruoyi-websocket/src/main/java/com/ruoyi/websocket/handle/IOpenLogic.java diff --git a/ruoyi-cai/pom.xml b/ruoyi-cai/pom.xml index 601f539e..22e3e5d1 100644 --- a/ruoyi-cai/pom.xml +++ b/ruoyi-cai/pom.xml @@ -26,5 +26,15 @@ com.ruoyi ruoyi-system + + com.alibaba + fastjson + 2.0.19 + + + com.ruoyi + ruoyi-websocket + 4.8.2 + diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/chat/ChatManager.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/chat/ChatManager.java index 1e9dd1de..a1d2f7c6 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/chat/ChatManager.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/chat/ChatManager.java @@ -14,6 +14,7 @@ import com.ruoyi.cai.service.CaiAnchorService; import com.ruoyi.cai.service.CaiGuardTotalService; import com.ruoyi.cai.service.CaiUserCallService; import com.ruoyi.cai.service.CaiUserService; +import com.ruoyi.cai.ws.bean.Room; import com.ruoyi.cai.ws.manager.WebSocketManager; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.helper.LoginHelper; @@ -58,10 +59,11 @@ public class ChatManager { if(anchor == null){ throw new ServiceException("主播技能不存在"); } - String roomId = webSocketManager.checkOnlineRoom(fromUser.getId(), toUser.getId()); - if(StringUtils.isEmpty(roomId)){ + String roomId = null; + Room room = webSocketManager.checkOnlineRoom(fromUser.getId(), toUser.getId()); + if(room == null){ CaiUserCall call = userCallService.createCall(fromUser, toUser, anchor); - roomId = webSocketManager.createRoom(call.getId()); + roomId = webSocketManager.createRoom(call.getId()+""); } String weSocketUrl = String.format(properties.getWebSocketUrl(),"token",roomId); Long guardPrice = systemConfigManager.getSystemConfigOfLong(SystemConfigEnum.GUARD_PRICE); @@ -96,11 +98,10 @@ public class ChatManager { if(!userCall.getFromUid().equals(userId) && !userCall.getToUid().equals(userId)){ throw new ServiceException("无权限操作房间"); } - String roomIdNew = webSocketManager.checkOnlineRoom(userCall.getFromUid(), userCall.getToUid()); - if (StringUtils.isNotEmpty(roomIdNew)) { - throw new ServiceException("'服务繁忙'"); + Room room = webSocketManager.checkOnlineRoom(userCall.getFromUid(), userCall.getToUid()); + if (room == null) { + throw new ServiceException("'对方已取消通话'"); } - // 判断房间号是否还存在 TODO List userList = userService.listByIds(Arrays.asList(userCall.getFromUid(), userCall.getToUid())); Map userMap = userList.stream().collect(Collectors.toMap(CaiUser::getId, Function.identity())); CaiUser fromUser = userMap.get(userCall.getFromUid()); diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/CaiUserCall.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/CaiUserCall.java index e31a07ab..08def435 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/CaiUserCall.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/CaiUserCall.java @@ -45,6 +45,7 @@ public class CaiUserCall implements Serializable { * 结束通话时间 */ private LocalDateTime endTime; + private String skillName; /** * 通话时长 */ @@ -85,6 +86,8 @@ public class CaiUserCall implements Serializable { * 接收者-工会-视频比例 */ private BigDecimal receiverUnionVideoDivide; + private Boolean receiverUnionGet; + private Boolean receiverInviteGet; /** * 接收者-邀请人 */ diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiAnchorService.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiAnchorService.java index 0ffafaa9..fd0636e6 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiAnchorService.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiAnchorService.java @@ -21,4 +21,6 @@ public interface CaiAnchorService extends IService { Page pageApp(PageQuery pageQuery, AnchorListQuery query); CaiAnchor getByUserId(Long userId); + + void updateVideoStatus(Long userId, int videoStatus); } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiUserService.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiUserService.java index 98d526fb..9831e0e2 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiUserService.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/CaiUserService.java @@ -29,4 +29,6 @@ public interface CaiUserService extends IService { UserInfoVo info(Long userId); CaiUser getByUserCode(String userCode); + + void updateVideoStatus(Long userId, int videoStatus); } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiAnchorServiceImpl.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiAnchorServiceImpl.java index 07c00fa7..ab60b68e 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiAnchorServiceImpl.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiAnchorServiceImpl.java @@ -7,6 +7,7 @@ import com.ruoyi.cai.domain.CaiAnchor; import com.ruoyi.cai.dto.admin.vo.CaiAnchorAdminVo; import com.ruoyi.cai.dto.app.query.AnchorListQuery; import com.ruoyi.cai.dto.app.vo.AnchorListVo; +import com.ruoyi.cai.dto.app.vo.AnchorVo; import com.ruoyi.cai.mapper.CaiAnchorMapper; import com.ruoyi.cai.service.CaiAnchorService; import com.ruoyi.common.core.domain.PageQuery; @@ -40,4 +41,11 @@ public class CaiAnchorServiceImpl extends ServiceImpl public CaiAnchor getByUserId(Long userId){ return this.getOne(Wrappers.lambdaQuery(CaiAnchor.class).eq(CaiAnchor::getUserId,userId)); } + + @Override + public void updateVideoStatus(Long userId, int videoStatus) { + this.update(Wrappers.lambdaUpdate(CaiAnchor.class) + .eq(CaiAnchor::getUserId,userId) + .set(CaiAnchor::getVideoStatus,videoStatus)); + } } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiUserServiceImpl.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiUserServiceImpl.java index 2072f272..b33cbc36 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiUserServiceImpl.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/CaiUserServiceImpl.java @@ -95,4 +95,11 @@ public class CaiUserServiceImpl extends ServiceImpl impl public CaiUser getByUserCode(String userCode){ return this.getOne(Wrappers.lambdaQuery(CaiUser.class).eq(CaiUser::getUsercode,userCode).last("limit 1")); } + + @Override + public void updateVideoStatus(Long userId, int videoStatus) { + this.update(Wrappers.lambdaUpdate(CaiUser.class) + .eq(CaiUser::getId,userId) + .set(CaiUser::getVideoStatus,videoStatus)); + } } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/CallerRoom.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/CallerRoom.java new file mode 100644 index 00000000..108a0524 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/CallerRoom.java @@ -0,0 +1,4 @@ +package com.ruoyi.cai.ws.bean; + +public class CallerRoom { +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/FdCtxData.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/FdCtxData.java new file mode 100644 index 00000000..733aaed2 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/FdCtxData.java @@ -0,0 +1,14 @@ +package com.ruoyi.cai.ws.bean; + +import lombok.Data; + +@Data +public class FdCtxData { + + private String sessionKey; + private String roomId; + private Long userId; + private Integer userType; + private Long tarUserId; + private Integer tarUserType; +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/Room.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/Room.java new file mode 100644 index 00000000..e9a5a22b --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/Room.java @@ -0,0 +1,34 @@ +package com.ruoyi.cai.ws.bean; + +import com.ruoyi.cai.ws.constant.HangUpEnums; +import com.ruoyi.cai.ws.constant.RoomStatusEnums; +import com.ruoyi.cai.ws.service.CheckConnectionDTO; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class Room { + + private RoomData roomData; + private UserData callUserData; + private UserData receiverUserData; + + public String getRoomId(){ + return roomData.getRoomId(); + } + + public Integer getStatus(){ + return roomData.getStatus(); + } + + public boolean isCanCall(){ + return RoomStatusEnums.isCanCall(roomData.getStatus()); + } + + public boolean isOnline() { + return RoomStatusEnums.STATUS_AGREE.getCode().equals(roomData.getStatus()); + } + +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/RoomData.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/RoomData.java new file mode 100644 index 00000000..9363a282 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/RoomData.java @@ -0,0 +1,15 @@ +package com.ruoyi.cai.ws.bean; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class RoomData { + private String roomId; + private Long callPrice; + private String skillName; + private Integer status; + private BigDecimal videoDivide; + private Long hangUpTime; +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/UserData.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/UserData.java new file mode 100644 index 00000000..0373be91 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/bean/UserData.java @@ -0,0 +1,21 @@ +package com.ruoyi.cai.ws.bean; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class UserData { + private Long id; + private String roomId; + private int userType; + private String nickname; + private String userCode; + private Long inviterId; + private BigDecimal inviterRate; + private Boolean inviterIsGet; + + private Long unionUserId; + private BigDecimal unionUserRate; + private Boolean unionIsGet; +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/CallerRoomCache.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/CallerRoomCache.java new file mode 100644 index 00000000..56e6cf88 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/CallerRoomCache.java @@ -0,0 +1,41 @@ +package com.ruoyi.cai.ws.cache; + +import com.ruoyi.cai.ws.constant.RedisConstant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Component +public class CallerRoomCache { + @Autowired + private StringRedisTemplate redisTemplate; + + public String getKey(Long fromUserId){ + return String.format(RedisConstant.CALLER_ROOM_DATA,fromUserId); + } + + public String getRoomId(Long fromUserId, Long toUserId){ + String key = getKey(fromUserId); + Object roomId = redisTemplate.opsForHash().get(key, toUserId); + return roomId == null ? null : String.valueOf(roomId); + } + + public void addRoom(Long fromUid, Long toUid, Long roomId) { + String key = getKey(fromUid); + redisTemplate.opsForHash().put(key,toUid,roomId); + redisTemplate.expire(key,7, TimeUnit.DAYS); + } + + public Map getAll(Long fromUid){ + String key = getKey(fromUid); + return redisTemplate.opsForHash().entries(key); + } + + public void del(Long fromUid) { + String key = getKey(fromUid); + redisTemplate.delete(key); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/FdCtxDataCache.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/FdCtxDataCache.java new file mode 100644 index 00000000..de32d051 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/FdCtxDataCache.java @@ -0,0 +1,26 @@ +package com.ruoyi.cai.ws.cache; + +import com.alibaba.fastjson2.JSON; +import com.ruoyi.cai.ws.bean.FdCtxData; +import com.ruoyi.cai.ws.constant.RedisConstant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +public class FdCtxDataCache { + @Autowired + private StringRedisTemplate redisTemplate; + + public String getKey(String sessionKey){ + return String.format(RedisConstant.FDCTX_DATA,sessionKey); + } + + public void save(FdCtxData fdCtxData) { + String str = JSON.toJSONString(fdCtxData); + redisTemplate.opsForValue().set(getKey(fdCtxData.getSessionKey()),str,5, TimeUnit.DAYS); + } + +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/OnlineDataCache.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/OnlineDataCache.java new file mode 100644 index 00000000..7ae68e1c --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/OnlineDataCache.java @@ -0,0 +1,20 @@ +package com.ruoyi.cai.ws.cache; + +import com.ruoyi.cai.ws.constant.RedisConstant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +@Component +public class OnlineDataCache { + @Autowired + private StringRedisTemplate redisTemplate; + + public String getKey(){ + return RedisConstant.ONLINE_ROOM_DATA; + } + + public void add(String roomId){ + redisTemplate.opsForSet().add(getKey(),roomId); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomCtxCache.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomCtxCache.java new file mode 100644 index 00000000..0f92478f --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomCtxCache.java @@ -0,0 +1,24 @@ +package com.ruoyi.cai.ws.cache; + +import com.ruoyi.cai.ws.constant.RedisConstant; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +public class RoomCtxCache { + @Autowired + private StringRedisTemplate redisTemplate; + + public String getKey(String roomId){ + return String.format(RedisConstant.FDCTX_ROOM_DATA,roomId); + } + + public void addFd(String sessionKey,String roomId,Integer userType){ + String key = getKey(roomId); + redisTemplate.opsForHash().putIfAbsent(key,sessionKey,userType); + redisTemplate.expire(key,7, TimeUnit.DAYS); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomDataCache.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomDataCache.java new file mode 100644 index 00000000..cc27db53 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/RoomDataCache.java @@ -0,0 +1,90 @@ +package com.ruoyi.cai.ws.cache; + + +import cn.hutool.json.JSONObject; +import com.alibaba.fastjson2.JSON; +import com.ruoyi.cai.ws.bean.RoomData; +import com.ruoyi.cai.ws.constant.RedisConstant; +import com.ruoyi.cai.ws.constant.RoomStatusEnums; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.poi.ss.formula.functions.Roman; +import org.redisson.api.RBucket; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +@Component +public class RoomDataCache { + // 房间状态 + private final static int STATUS_CREATE = 0; // 刚创建 + private final static int STATUS_CALLER_CONNECT = 1; // 呼叫方连接上 + private final static int STATUS_CALLER_CANCEL = 2; // 呼叫方取消通话 + private final static int STATUS_RECEIVER_CONNECT = 3; // 接收方连接上 + private final static int STATUS_CONNECT_CANCEL = 4; // 收到通话未接听 + private final static int STATUS_TIMEOUT_CANCEL = 5; // 超时未接听 + private final static int STATUS_REFUSE = 6; // 接收方已拒绝 + private final static int STATUS_AGREE = 7; // 已接听 + private final static int STATUS_HANGUP = 8; // 通话结束 + + @Autowired + private RedissonClient redissonClient; + @Autowired + private StringRedisTemplate stringRedisTemplate; + + public String getKey(String roomId){ + return String.format(RedisConstant.ROOM_DATA,roomId); + } + + public RoomData getByRoomId(String roomId){ + Map map = stringRedisTemplate.opsForHash().entries(getKey(roomId)); + if(map.get("roomId") == null){ + return null; + } + RoomData roomData = new RoomData(); + roomData.setRoomId(map.get("roomId").toString()); + roomData.setCallPrice(Long.valueOf(map.get("callPrice").toString())); + return roomData; + } + + public void init(RoomData roomData) { + Map map = JSON.parseObject(JSON.toJSONString(roomData)); + stringRedisTemplate.opsForHash().putAll(getKey(roomData.getRoomId()),map); + } + + + private final static String HANG_UP = "local hangupTime = tonumber(redis.call('hGet', KEYS[1], 'hangupTime'))\n" + + "if hangupTime > 0 then\n" + + " return 0\n" + + "end\n" + + "return redis.call('hMSet', KEYS[1], 'status', 8, 'hangupTime', ARGV[1])"; + + public void hangUp(String roomId) { + DefaultRedisScript redisScript = new DefaultRedisScript<>(HANG_UP,Boolean.class); + String currentTime = String.valueOf(System.currentTimeMillis() / 1000); + stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)), currentTime); + } + + public void setStatus(String roomId, RoomStatusEnums status) { + String key = getKey(roomId); + stringRedisTemplate.opsForHash().put(key,"status",status.getCode()); + } + + private final static String SET_STATUS_RECEIVER_CONNECTION = "local status = tonumber(redis.call('hget', KEYS[1], 'status'))\n" + + "if status ~= 1 then\n" + + " return 0\n" + + "end\n" + + "return redis.call('hmset', KEYS[1], 'status', 3)"; + + public boolean setStatusReceiverConnection(String roomId) { + DefaultRedisScript redisScript = new DefaultRedisScript<>(SET_STATUS_RECEIVER_CONNECTION,Boolean.class); + Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId))); + return BooleanUtils.isTrue(execute); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/UserDataCache.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/UserDataCache.java new file mode 100644 index 00000000..631b63ba --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/cache/UserDataCache.java @@ -0,0 +1,72 @@ +package com.ruoyi.cai.ws.cache; + +import com.alibaba.fastjson2.JSON; +import com.ruoyi.cai.ws.bean.UserData; +import com.ruoyi.cai.ws.constant.RedisConstant; +import com.ruoyi.cai.ws.util.MapGetUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +public class UserDataCache { + public final static int TYPE_CALLER = 1; // 视频发起者 + public final static int TYPE_RECEIVER = 2; // 视频接收者 + @Autowired + private StringRedisTemplate redisTemplate; + + public String getKey(String roomId,int type){ + return String.format(RedisConstant.USER_ROOM_DATA,roomId,type==TYPE_CALLER?"caller":"receiver"); + } + + public UserData getCallerUserDataByRoom(String roomId){ + return getUserDataByRoom(roomId,TYPE_CALLER); + } + + public UserData getReceiverUserDataByRoom(String roomId){ + return getUserDataByRoom(roomId,TYPE_RECEIVER); + } + + public UserData getUserDataByRoom(String roomId,int type){ + String key = getKey(roomId, type); + Map entries = redisTemplate.opsForHash().entries(key); + if(entries.get("roomId") == null){ + return null; + } + UserData userData = new UserData(); + userData.setId(MapGetUtil.getLong(entries.get("id"))); + userData.setRoomId(MapGetUtil.getString(entries.get("roomId"))); + userData.setUserType(MapGetUtil.getInt(entries.get("userType"))); + userData.setNickname(MapGetUtil.getString(entries.get("nickname"))); + userData.setUserCode(MapGetUtil.getString(entries.get("userCode"))); + userData.setInviterId(MapGetUtil.getLong(entries.get("inviterId"))); + userData.setInviterRate(MapGetUtil.getBigDecimal(entries.get("inviterRate"))); + userData.setInviterIsGet(MapGetUtil.getBoolean(entries.get("inviterIsGet"))); + userData.setUnionUserId(MapGetUtil.getLong(entries.get("unionUserId"))); + userData.setUnionUserRate(MapGetUtil.getBigDecimal(entries.get("unionUserRate"))); + userData.setUnionIsGet(MapGetUtil.getBoolean(entries.get("unionIsGet"))); + return userData; + } + + public void init(UserData userData,int type){ + String key = getKey(userData.getRoomId(), type); + userData.setUserType(type); + Map map = JSON.parseObject(JSON.toJSONString(userData)); + redisTemplate.opsForHash().putAll(key,map); + } + + public void initCaller(UserData callerUserData) { + init(callerUserData,TYPE_CALLER); + } + + public void initReceiver(UserData callerUserData) { + init(callerUserData,TYPE_RECEIVER); + } + + public void hMSet(String roomId,Integer userType,Map data) { + String key = getKey(roomId, userType); + redisTemplate.opsForHash().putAll(key,data); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/HangUpEnums.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/HangUpEnums.java new file mode 100644 index 00000000..050e444e --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/HangUpEnums.java @@ -0,0 +1,25 @@ +package com.ruoyi.cai.ws.constant; + +import lombok.Getter; + +@Getter +public enum HangUpEnums { + CANCEL(1,"主动取消"), + REFUSE(2,"对方拒绝"), + TIMEOUT(3,"超时"), + TO(4,"被叫者挂断"), + FROM(5,"主叫者挂断"), + NOTMONEY(6,"费用不足"), + OTHER(7,"其他问题"), + TYPE_SPECIAL(8,"特殊用户挂断"), + PORN_FROM(10,"男方色情违规"), + PORN_TO(11,"女方色情违规"), + ; + private final Integer code; + private final String msg; + + HangUpEnums(Integer code, String msg) { + this.code = code; + this.msg = msg; + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RedisConstant.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RedisConstant.java new file mode 100644 index 00000000..39ea7cc3 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RedisConstant.java @@ -0,0 +1,12 @@ +package com.ruoyi.cai.ws.constant; + +public class RedisConstant { + public static final String REDIS_P = "caiws-"; + public static final String ONLINE_ROOM_DATA = REDIS_P + "onlineRoomData"; + public static final String ROOM_DATA = REDIS_P + "roomData:%s"; + public static final String FDCTX_DATA = REDIS_P + "fdctx:%s"; + public static final String FDCTX_ROOM_DATA = REDIS_P + "roomCtx:%s"; + public static final String CALLER_ROOM_DATA = REDIS_P + "caller:%s"; + public static final String USER_ROOM_DATA = REDIS_P + "room:%s:%s"; + public static final String INIT_ROOM_LOCK = REDIS_P + "lock:initRoom:%s-%s"; +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RoomStatusEnums.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RoomStatusEnums.java new file mode 100644 index 00000000..87d23300 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/constant/RoomStatusEnums.java @@ -0,0 +1,64 @@ +package com.ruoyi.cai.ws.constant; + +import lombok.Getter; + +@Getter +public enum RoomStatusEnums { + + /** + * 刚创建 + */ + STATUS_CREATE(0,"刚创建"), + /** + * 呼叫方连接上 + */ + STATUS_CALLER_CONNECT(1,"呼叫方连接上"), + /** + * 呼叫方取消通话 + */ + STATUS_CALLER_CANCEL(2,"呼叫方取消通话"), + /** + * 接收方连接上 + */ + STATUS_RECEIVER_CONNECT(3,"接收方连接上"), + /** + * 收到通话未接听 + */ + STATUS_CONNECT_CANCEL(4,"收到通话未接听"), + /** + * 超时未接听 + */ + STATUS_TIMEOUT_CANCEL(5,"超时未接听"), + /** + * 接收方已拒绝 + */ + STATUS_REFUSE(6,"接收方已拒绝"), + /** + * 已接听 + */ + STATUS_AGREE(7,"已接听"), + /** + * 通话结束 + */ + STATUS_HANGUP(8,"通话结束") + ; + + private final Integer code; + private final String name; + + RoomStatusEnums(Integer code, String name) { + this.code = code; + this.name = name; + } + + public static boolean isCanCall(Integer status){ + if(STATUS_CREATE.getCode().equals(status) + || STATUS_CALLER_CONNECT.getCode().equals(status) + || STATUS_RECEIVER_CONNECT.getCode().equals(status) + || STATUS_AGREE.getCode().equals(status)){ + return true; + } + return false; + } + +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/manager/WebSocketManager.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/manager/WebSocketManager.java index 0ce8b93e..c902a2ea 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/manager/WebSocketManager.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/manager/WebSocketManager.java @@ -1,14 +1,134 @@ package com.ruoyi.cai.ws.manager; +import com.ruoyi.cai.domain.CaiAnchor; +import com.ruoyi.cai.domain.CaiUser; +import com.ruoyi.cai.domain.CaiUserCall; +import com.ruoyi.cai.service.CaiAnchorService; +import com.ruoyi.cai.service.CaiUserCallService; +import com.ruoyi.cai.service.CaiUserInviteService; +import com.ruoyi.cai.service.CaiUserService; +import com.ruoyi.cai.ws.bean.Room; +import com.ruoyi.cai.ws.bean.RoomData; +import com.ruoyi.cai.ws.bean.UserData; +import com.ruoyi.cai.ws.cache.CallerRoomCache; +import com.ruoyi.cai.ws.cache.RoomDataCache; +import com.ruoyi.cai.ws.cache.UserDataCache; +import com.ruoyi.cai.ws.constant.RedisConstant; +import com.ruoyi.cai.ws.service.RoomService; +import com.ruoyi.common.exception.ServiceException; +import org.apache.commons.lang3.StringUtils; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class WebSocketManager { - public String checkOnlineRoom(Long formUserId,Long toUserId){ - return "name"; + @Autowired + private CallerRoomCache callerRoomCache; + @Autowired + private RoomService roomService; + @Autowired + private CaiUserCallService userCallService; + @Autowired + private CaiUserService userService; + @Autowired + private CaiAnchorService anchorService; + @Autowired + private CaiUserInviteService userInviteService; + @Autowired + private RoomDataCache roomDataCache; + @Autowired + private UserDataCache userDataCache; + @Autowired + private RedissonClient redissonClient; + + public Room checkOnlineRoom(Long fromUserId,Long toUserId){ + String roomId = callerRoomCache.getRoomId(fromUserId, toUserId); + if(StringUtils.isEmpty(roomId)){ + return null; + } + Room room = roomService.load(roomId); + if(room == null){ + return null; + } + return room; } - public String createRoom(Long id) { - return "123"; + public String createRoom(String roomId) { + CaiUserCall userCall = userCallService.getById(roomId); + if(userCall == null){ + throw new ServiceException("无效房间"); + } + Room room = checkOnlineRoom(userCall.getFromUid(), userCall.getToUid()); + if(room != null && room.isCanCall()){ // 缓存中存在旧房间,直接返回 + return room.getRoomId(); + } + RLock lock = redissonClient.getLock(String.format(RedisConstant.INIT_ROOM_LOCK, userCall.getFromUid(), userCall.getToUid())); + boolean b = lock.tryLock(); + if(!b){ + throw new ServiceException("系统繁忙"); + } + try { + roomId = initRoom(userCall); + }finally { + lock.unlock(); + } + return roomId; + } + + public String initRoom(CaiUserCall call){ + call = userCallService.getById(call.getId()); + CaiUser callUser = userService.getById(call.getFromUid()); + if(callUser == null){ + throw new ServiceException("无效的呼叫方"); + } + CaiUser receiverUser = userService.getById(call.getToUid()); + if(receiverUser == null){ + throw new ServiceException("无效的接收方"); + } + CaiAnchor anchor = anchorService.getByUserId(call.getToUid()); + if(anchor == null){ + throw new ServiceException("接收方不是女神"); + } + // 检查视频状态 + if(anchor.getVideoStatus() != 0){ + throw new ServiceException("对方正在视频中"); + } + // 检查女神在线状态 TODO + + // 关闭发起的其他房间 + roomService.closeAllRoom(call.getFromUid()); + // 删除旧房间记录 + roomService.delCallRoom(call.getFromUid()); + // 初始化 + RoomData roomData = new RoomData(); + roomData.setRoomId(call.getId()+""); + roomData.setCallPrice(call.getCallPrice()); + roomData.setSkillName(call.getSkillName()); + roomData.setStatus(call.getStatus()); + roomData.setVideoDivide(call.getReceiverVideoDivide()); + roomDataCache.init(roomData); + UserData callerUserData = new UserData(); + callerUserData.setId(call.getFromUid()); + callerUserData.setRoomId(call.getId()+""); + callerUserData.setNickname(callUser.getNickname()); + callerUserData.setUserCode(callUser.getUsercode()); + userDataCache.initCaller(callerUserData); + UserData receiveUserData = new UserData(); + receiveUserData.setId(call.getToUid()); + receiveUserData.setRoomId(call.getId()+""); + receiveUserData.setNickname(receiverUser.getNickname()); + receiveUserData.setUserCode(receiverUser.getUsercode()); + receiveUserData.setInviterId(call.getReceiverInviteUserId()); + receiveUserData.setInviterRate(call.getReceiverIncomeDivide()); + receiveUserData.setInviterIsGet(call.getReceiverInviteGet()); + receiveUserData.setUnionUserId(call.getReceiverUnionUserId()); + receiveUserData.setUnionUserRate(call.getReceiverUnionVideoDivide()); + receiveUserData.setUnionIsGet(call.getReceiverUnionGet()); + userDataCache.initReceiver(callerUserData); + callerRoomCache.addRoom(call.getFromUid(),call.getToUid(),call.getId()); + return call.getId()+""; + } } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/processon/OpenLogic.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/processon/OpenLogic.java new file mode 100644 index 00000000..dc7cc5ff --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/processon/OpenLogic.java @@ -0,0 +1,147 @@ +package com.ruoyi.cai.ws.processon; + +import cn.hutool.core.date.DateUtil; +import com.ruoyi.cai.service.CaiAnchorService; +import com.ruoyi.cai.service.CaiUserService; +import com.ruoyi.cai.ws.bean.FdCtxData; +import com.ruoyi.cai.ws.bean.Room; +import com.ruoyi.cai.ws.cache.*; +import com.ruoyi.cai.ws.constant.HangUpEnums; +import com.ruoyi.cai.ws.constant.RoomStatusEnums; +import com.ruoyi.cai.ws.service.CheckConnectionDTO; +import com.ruoyi.cai.ws.service.RoomService; +import com.ruoyi.cai.ws.util.WsExceptionUtil; +import com.ruoyi.websocket.handle.IOpenLogic; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class OpenLogic implements IOpenLogic { + @Autowired + private RoomService roomService; + @Autowired + private FdCtxDataCache fdCtxDataCache; + @Autowired + private RoomCtxCache roomCtxCache; + @Autowired + private UserDataCache userDataCache; + @Autowired + private RoomDataCache roomDataCache; + @Autowired + private OnlineDataCache onlineDataCache; + @Autowired + private CaiUserService userService; + @Autowired + private CaiAnchorService anchorService; + + @Override + public void processOn(WebSocketSession session) { + Map map = session.getAttributes(); + String token = map.get("token").toString(); + // 校验token + process(token,"",0L); + } + + public void process(String sessionKey,String roomId,Long userId){ + Room room = roomService.load(roomId); + if(room == null || (room.getCallUserData().getId().equals(userId) && room.getReceiverUserData().getId().equals(userId))){ + WsExceptionUtil.throwException(sessionKey,"房间不可用", HangUpEnums.OTHER,roomId); + return; + } + CheckConnectionDTO checkConnect = roomService.checkConnect(room); + if(checkConnect != null){ + WsExceptionUtil.throwException(sessionKey,checkConnect.getMessage(),checkConnect.getHangUpEnums(),roomId); + return; + } + if(userId.equals(room.getCallUserData().getId())){ + // 走主叫方逻辑 + callerConnection(sessionKey,room,userId); + }else { + // 走接收方逻辑 + receiverConnection(sessionKey,room,userId); + } + // 保存上下文到redis + FdCtxData fdCtxData = new FdCtxData(); + fdCtxData.setSessionKey(sessionKey); + fdCtxData.setRoomId(room.getRoomId()); + fdCtxData.setUserId(userId); + if(userId.equals(room.getCallUserData().getId())){ + fdCtxData.setUserType(UserDataCache.TYPE_CALLER); + fdCtxData.setTarUserId(room.getReceiverUserData().getId()); + fdCtxData.setTarUserType(UserDataCache.TYPE_RECEIVER); + } else { + fdCtxData.setUserType(UserDataCache.TYPE_RECEIVER); + fdCtxData.setTarUserId(room.getCallUserData().getId()); + fdCtxData.setTarUserType(UserDataCache.TYPE_CALLER); + } + fdCtxDataCache.save(fdCtxData); + roomCtxCache.addFd(sessionKey,roomId,fdCtxData.getUserType()); + } + + public void callerConnection(String sessionKey,Room room,Long userId){ + boolean isFirst = false; + Integer status = room.getStatus(); + // 首次链接 + if(RoomStatusEnums.STATUS_CREATE.getCode().equals(status)){ + // 更新缓存 + Map map = new HashMap<>(); + map.put("connectTime", DateUtil.currentSeconds()); + map.put("heartTime",DateUtil.currentSeconds()); + userDataCache.hMSet(room.getRoomId(), UserDataCache.TYPE_CALLER,map); + roomDataCache.setStatus(room.getRoomId(),RoomStatusEnums.STATUS_CALLER_CONNECT); + onlineDataCache.add(room.getRoomId()); + userService.updateVideoStatus(userId,1); + isFirst = true; + } + // 已经接通 + if(room.isOnline()){ + // TODO + // 如果视频也掉线了,则重连的时候发送消息提示 +// sgo(function() use ($rs){ +// $users = Agora::getChannelUsers($rs->room->id); +// if (in_array($rs->caller->id, $users)) { +// return; +// } +// +// $rs->sendToCurrent(WsMsgGen::startVideo($rs->room->id, $rs->callTime())) +// ->sendToCurrent(WsMsgGen::sysNotice('重连成功,房间已通话 '.gmdate('H:i:s', $rs->callTime()))) +// ->sendToReceiver(WsMsgGen::sysNotice('对方已重连成功')); +// }); + } + if(RoomStatusEnums.STATUS_CREATE.getCode().equals(status) || + RoomStatusEnums.STATUS_CALLER_CONNECT.getCode().equals(status) || + RoomStatusEnums.STATUS_RECEIVER_CONNECT.getCode().equals(status)){ + // 给当前会话发送消息 - 连线成功 + + } + if(isFirst){ + // 给对方发送呼叫页面 + } + } + public void receiverConnection(String sessionKey,Room room,Long userId){ + Integer status = room.getStatus(); + // 首次链接 + if(RoomStatusEnums.STATUS_CALLER_CONNECT.getCode().equals(status)){ + // 更新缓存 + Map map = new HashMap<>(); + map.put("connectTime", DateUtil.currentSeconds()); + map.put("heartTime",DateUtil.currentSeconds()); + userDataCache.hMSet(room.getRoomId(), UserDataCache.TYPE_RECEIVER,map); + boolean res = roomDataCache.setStatusReceiverConnection(room.getRoomId()); + if(!res){ + return; + } + userService.updateVideoStatus(userId,1); + anchorService.updateVideoStatus(userId,1); + } + // 连线成功 +// $rs->sendToCurrent(WsMsgGen::response($this->roomId)) +// ->sendToCurrent(WsMsgGen::updateTip()); + } + + +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/CheckConnectionDTO.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/CheckConnectionDTO.java new file mode 100644 index 00000000..19246185 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/CheckConnectionDTO.java @@ -0,0 +1,18 @@ +package com.ruoyi.cai.ws.service; + +import com.ruoyi.cai.ws.constant.HangUpEnums; +import lombok.Data; + +@Data +public class CheckConnectionDTO { + private HangUpEnums hangUpEnums; + private String message; + + public CheckConnectionDTO() { + } + + public CheckConnectionDTO(HangUpEnums hangUpEnums, String message) { + this.hangUpEnums = hangUpEnums; + this.message = message; + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/RoomService.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/RoomService.java new file mode 100644 index 00000000..a961f6df --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/service/RoomService.java @@ -0,0 +1,89 @@ +package com.ruoyi.cai.ws.service; + +import com.ruoyi.cai.ws.bean.Room; +import com.ruoyi.cai.ws.bean.RoomData; +import com.ruoyi.cai.ws.bean.UserData; +import com.ruoyi.cai.ws.cache.CallerRoomCache; +import com.ruoyi.cai.ws.cache.RoomDataCache; +import com.ruoyi.cai.ws.cache.UserDataCache; +import com.ruoyi.cai.ws.constant.HangUpEnums; +import com.ruoyi.cai.ws.constant.RoomStatusEnums; +import com.ruoyi.cai.ws.util.WsExceptionUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class RoomService { + @Autowired + private RoomDataCache roomDataCache; + @Autowired + private UserDataCache userDataCache; + @Autowired + private CallerRoomCache callerRoomCache; + + public Room load(String roomId){ + Room room = new Room(); + RoomData roomData = roomDataCache.getByRoomId(roomId); + if(roomData == null){ + return null; + } + room.setRoomData(roomData); + UserData callerUserData = userDataCache.getCallerUserDataByRoom(roomId); + if(callerUserData == null){ + return null; + } + room.setCallUserData(callerUserData); + UserData receiverUserData = userDataCache.getReceiverUserDataByRoom(roomId); + if(receiverUserData == null){ + return null; + } + room.setReceiverUserData(receiverUserData); + return room; + } + + public void closeAllRoom(Long fromUid){ + Map all = callerRoomCache.getAll(fromUid); + for (Map.Entry entry : all.entrySet()) { + String roomId = String.valueOf(entry.getValue()); + Room room = load(roomId); + if(room == null){ + continue; + } + if(room.isCanCall()){ + // 给接收方发送对应已取消 + }else if(room.isOnline()){ + // 对接收方发送对方已挂断 + } + // 挂掉房间 + roomDataCache.hangUp(roomId); + // 关闭所有的websocket进程 + + } + } + + public void delCallRoom(Long fromUid) { + callerRoomCache.del(fromUid); + } + private static Map STATUS_TO_HANG_UP = new HashMap<>(); + static { + STATUS_TO_HANG_UP.put(RoomStatusEnums.STATUS_CALLER_CANCEL.getCode(),new CheckConnectionDTO(HangUpEnums.CANCEL,"通话已取消")); + STATUS_TO_HANG_UP.put(RoomStatusEnums.STATUS_CONNECT_CANCEL.getCode(),new CheckConnectionDTO(HangUpEnums.TIMEOUT,"通话未接听")); + STATUS_TO_HANG_UP.put(RoomStatusEnums.STATUS_REFUSE.getCode(),new CheckConnectionDTO(HangUpEnums.REFUSE,"对方已拒绝")); + STATUS_TO_HANG_UP.put(RoomStatusEnums.STATUS_TIMEOUT_CANCEL.getCode(),new CheckConnectionDTO(HangUpEnums.REFUSE,"通话已拒绝")); + STATUS_TO_HANG_UP.put(RoomStatusEnums.STATUS_HANGUP.getCode(),new CheckConnectionDTO(HangUpEnums.OTHER,"通话已结束")); + } + + public CheckConnectionDTO checkConnect(Room room) { + CheckConnectionDTO checkConnectionDTO = STATUS_TO_HANG_UP.get(room.getRoomData().getStatus()); + if(checkConnectionDTO != null){ + return checkConnectionDTO; + } + if(room.getRoomData().getStatus() > RoomStatusEnums.STATUS_AGREE.getCode()){ + return new CheckConnectionDTO(HangUpEnums.OTHER,"通话已结束"); + } + return null; + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/MapGetUtil.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/MapGetUtil.java new file mode 100644 index 00000000..630c8ab9 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/MapGetUtil.java @@ -0,0 +1,51 @@ +package com.ruoyi.cai.ws.util; + + +import java.math.BigDecimal; + +public class MapGetUtil { + + + public static Long getLong(Object obj){ + return getLong(obj,null); + } + + public static Long getLong(Object obj, Long defaultValue){ + if(obj == null){ + return defaultValue; + } + return Long.valueOf(obj.toString()); + } + + public static String getString(Object obj){ + if(obj == null){ + return null; + } + return String.valueOf(obj); + } + + public static Integer getInt(Object obj){ + if(obj == null){ + return null; + } + return Integer.valueOf(obj.toString()); + } + + public static BigDecimal getBigDecimal(Object obj){ + if(obj == null){ + return null; + } + return new BigDecimal(obj.toString()); + } + + public static Boolean getBoolean(Object obj) { + if(obj == null){ + return null; + } + if(obj instanceof Boolean){ + return (Boolean)obj; + } + String str = String.valueOf(obj); + return str.equals("true"); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/WsExceptionUtil.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/WsExceptionUtil.java new file mode 100644 index 00000000..06988e94 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/ws/util/WsExceptionUtil.java @@ -0,0 +1,16 @@ +package com.ruoyi.cai.ws.util; + +import com.ruoyi.cai.ws.constant.HangUpEnums; + +public class WsExceptionUtil { + public static void throwException(String sessionKey, String message, HangUpEnums hangUpType, String roomId){ + if(hangUpType == null){ + hangUpType = HangUpEnums.OTHER; + } + + } + + public String handUp(String sessionKey,String message,String roomId,HangUpEnums hang){ + return null; + } +} diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/config/WebSocketConfig.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/config/WebSocketConfig.java index a11520b7..2286d2a5 100644 --- a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/config/WebSocketConfig.java +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/config/WebSocketConfig.java @@ -1,13 +1,10 @@ package com.ruoyi.websocket.config; import cn.hutool.core.util.StrUtil; -import com.ruoyi.websocket.handler.PlusWebSocketHandler; -import com.ruoyi.websocket.interceptor.PlusWebSocketInterceptor; -import com.ruoyi.websocket.listener.WebSocketTopicListener; -import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; @@ -18,7 +15,7 @@ import org.springframework.web.socket.server.HandshakeInterceptor; * * @author zendwang */ -@AutoConfiguration +@Configuration @ConditionalOnProperty(value = "websocket.enabled", havingValue = "true") @EnableConfigurationProperties(WebSocketProperties.class) @EnableWebSocket @@ -29,7 +26,7 @@ public class WebSocketConfig { WebSocketHandler webSocketHandler, WebSocketProperties webSocketProperties) { if (StrUtil.isBlank(webSocketProperties.getPath())) { - webSocketProperties.setPath("/websocket"); + webSocketProperties.setPath("/ws"); } if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) { @@ -42,18 +39,4 @@ public class WebSocketConfig { .setAllowedOrigins(webSocketProperties.getAllowedOrigins()); } - @Bean - public HandshakeInterceptor handshakeInterceptor() { - return new PlusWebSocketInterceptor(); - } - - @Bean - public WebSocketHandler webSocketHandler() { - return new PlusWebSocketHandler(); - } - - @Bean - public WebSocketTopicListener topicListener() { - return new WebSocketTopicListener(); - } } diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handle/IOpenLogic.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handle/IOpenLogic.java new file mode 100644 index 00000000..cb6da728 --- /dev/null +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handle/IOpenLogic.java @@ -0,0 +1,9 @@ +package com.ruoyi.websocket.handle; + +import org.springframework.web.socket.WebSocketSession; + +public interface IOpenLogic { + + void processOn(WebSocketSession session); + +} diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handler/PlusWebSocketHandler.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handler/PlusWebSocketHandler.java index f2a8408a..6971b2fd 100644 --- a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handler/PlusWebSocketHandler.java +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/handler/PlusWebSocketHandler.java @@ -2,14 +2,18 @@ package com.ruoyi.websocket.handler; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.websocket.dto.WebSocketMessageDto; +import com.ruoyi.websocket.handle.IOpenLogic; import com.ruoyi.websocket.holder.WebSocketSessionHolder; import com.ruoyi.websocket.util.WebSocketUtils; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; import org.springframework.web.socket.*; import org.springframework.web.socket.handler.AbstractWebSocketHandler; import java.util.Collections; import java.util.List; +import java.util.Map; import static com.ruoyi.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; @@ -19,16 +23,22 @@ import static com.ruoyi.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; * @author zendwang */ @Slf4j +@Component public class PlusWebSocketHandler extends AbstractWebSocketHandler { + @Autowired + private IOpenLogic openLogic; /** * 连接成功后 */ @Override public void afterConnectionEstablished(WebSocketSession session) { - LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); - WebSocketSessionHolder.addSession(loginUser.getUserId(), session); - log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); + Map attributes = session.getAttributes(); + if(attributes.get("token") != null){ + WebSocketSessionHolder.addSession(attributes.get("token").toString(), session); + } + openLogic.processOn(session); + log.info("[connect] sessionId: {},userId:{}", session.getId(), session.getId()); } /** diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/holder/WebSocketSessionHolder.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/holder/WebSocketSessionHolder.java index 4c9d9fe3..1196774b 100644 --- a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/holder/WebSocketSessionHolder.java +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/holder/WebSocketSessionHolder.java @@ -16,27 +16,27 @@ import java.util.concurrent.ConcurrentHashMap; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class WebSocketSessionHolder { - private static final Map USER_SESSION_MAP = new ConcurrentHashMap<>(); + private static final Map USER_SESSION_MAP = new ConcurrentHashMap<>(); - public static void addSession(Long sessionKey, WebSocketSession session) { + public static void addSession(String sessionKey, WebSocketSession session) { USER_SESSION_MAP.put(sessionKey, session); } - public static void removeSession(Long sessionKey) { + public static void removeSession(String sessionKey) { if (USER_SESSION_MAP.containsKey(sessionKey)) { USER_SESSION_MAP.remove(sessionKey); } } - public static WebSocketSession getSessions(Long sessionKey) { + public static WebSocketSession getSessions(String sessionKey) { return USER_SESSION_MAP.get(sessionKey); } - public static Set getSessionsAll() { + public static Set getSessionsAll() { return USER_SESSION_MAP.keySet(); } - public static Boolean existSession(Long sessionKey) { + public static Boolean existSession(String sessionKey) { return USER_SESSION_MAP.containsKey(sessionKey); } } diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/interceptor/PlusWebSocketInterceptor.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/interceptor/PlusWebSocketInterceptor.java index e7074765..435024d6 100644 --- a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/interceptor/PlusWebSocketInterceptor.java +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/interceptor/PlusWebSocketInterceptor.java @@ -5,6 +5,7 @@ import com.ruoyi.common.helper.LoginHelper; import lombok.extern.slf4j.Slf4j; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; +import org.springframework.stereotype.Component; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; @@ -18,6 +19,7 @@ import static com.ruoyi.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; * @author zendwang */ @Slf4j +@Component public class PlusWebSocketInterceptor implements HandshakeInterceptor { /** diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/listener/WebSocketTopicListener.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/listener/WebSocketTopicListener.java index d5f7e41d..040551d1 100644 --- a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/listener/WebSocketTopicListener.java +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/listener/WebSocketTopicListener.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; /** * WebSocket 主题订阅监听器 @@ -14,6 +15,7 @@ import org.springframework.core.Ordered; * @author zendwang */ @Slf4j +@Component public class WebSocketTopicListener implements ApplicationRunner, Ordered { @Override diff --git a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/util/WebSocketUtils.java b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/util/WebSocketUtils.java index 471d65bf..282c76f7 100644 --- a/ruoyi-websocket/src/main/java/com/ruoyi/websocket/util/WebSocketUtils.java +++ b/ruoyi-websocket/src/main/java/com/ruoyi/websocket/util/WebSocketUtils.java @@ -34,20 +34,11 @@ public class WebSocketUtils { * @param sessionKey session主键 一般为用户id * @param message 消息文本 */ - public static void sendMessage(Long sessionKey, String message) { + public static void sendMessage(String sessionKey, String message) { WebSocketSession session = WebSocketSessionHolder.getSessions(sessionKey); sendMessage(session, message); } - /** - * 订阅消息 - * - * @param consumer 自定义处理 - */ - public static void subscribeMessage(Consumer consumer) { - RedisUtils.subscribe(WEB_SOCKET_TOPIC, WebSocketMessageDto.class, consumer); - } - /** * 发布订阅的消息 * @@ -107,4 +98,5 @@ public class WebSocketUtils { } } } + }