通话逻辑

This commit is contained in:
张良(004796)
2023-12-29 12:45:41 +08:00
parent 973c9545af
commit 244fadd1e6
33 changed files with 746 additions and 69 deletions

View File

@@ -0,0 +1,40 @@
package com.ruoyi.websocket.handler;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.cache.RoomCtxCache;
import com.ruoyi.websocket.dto.WsR;
import com.ruoyi.websocket.util.RoomWebSocketUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public abstract class AbstractMessageHandle implements IMessageHandler {
@Autowired
private RoomCtxCache roomCtxCache;
protected void sendToCurrent(FdCtxData fdCtxData, WsR r){
RoomWebSocketUtil.sendSendMessage(fdCtxData.getSessionKey(), r);
}
protected void sendToTar(FdCtxData fdCtxData, WsR r) {
String sessionKey = roomCtxCache.getSessionKeyByRoomIdAndUserType(fdCtxData.getRoomId(), fdCtxData.getTarUserType());
RoomWebSocketUtil.sendSendMessage(sessionKey, r);
}
protected void sendToReceiver(String roomId, WsR r){
String receiverSessionKey = roomCtxCache.getSessionKeyReceiverByRoomId(roomId);
RoomWebSocketUtil.sendSendMessage(receiverSessionKey, r);
}
protected void sendToAll(String roomId, WsR ... r ){
List<String> sessionKeys = roomCtxCache.getSessionKeysByRoomId(roomId);
for (WsR wsR : r) {
RoomWebSocketUtil.sendSendMessage(sessionKeys, wsR);
}
}
}

View File

@@ -0,0 +1,10 @@
package com.ruoyi.websocket.handler;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
public interface IMessageHandler {
void processOn(Room room, FdCtxData fdCtxData, JSONObject map);
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.websocket.handler;
import org.springframework.web.socket.WebSocketSession;
public interface IOpenLogic {
void processOn(WebSocketSession session);
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.websocket.handler;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.FdCtxDataCache;
import com.ruoyi.cai.ws.constant.HangUpEnums;
import com.ruoyi.cai.ws.service.CheckConnectionDTO;
import com.ruoyi.cai.ws.service.RoomService;
import com.ruoyi.cai.ws.util.WsExceptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.util.Map;
/**
* ws消息处理器统一入口
*/
@Component
public class MessageHandleApplication {
@Autowired
private Map<String,IMessageHandler> map;
@Autowired
private RoomService roomService;
@Autowired
private FdCtxDataCache fdCtxDataCache;
public void processOn(WebSocketSession session, TextMessage message) {
String payload = message.getPayload();
JSONObject jsonObject = JSON.parseObject(payload);
Object method = jsonObject.get("method");
if(method == null){
return;
}
Map<String, Object> attributes = session.getAttributes();
String roomId = (String) attributes.get("roomId");
String sessionKey = (String) attributes.get("token");
Room room = roomService.load(roomId);
if(room == null){
WsExceptionUtil.throwException("房间不可用", sessionKey,HangUpEnums.OTHER, roomId);
return;
}
CheckConnectionDTO checkConnect = roomService.checkConnect(room);
if(checkConnect != null){
WsExceptionUtil.throwException(sessionKey,checkConnect.getMessage(),checkConnect.getHangUpEnums(),roomId);
return;
}
IMessageHandler handler = map.get(String.valueOf(method));
if(handler == null){
return;
}
FdCtxData fdCtxData = fdCtxDataCache.getByRoomId(sessionKey);
handler.processOn(room,fdCtxData, jsonObject);
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.websocket.handler;
import com.ruoyi.websocket.constant.WebSocketConstants;
import com.ruoyi.websocket.handle.IOpenLogic;
import com.ruoyi.websocket.holder.WebSocketSessionHolder;
import com.ruoyi.websocket.util.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
@@ -19,10 +18,12 @@ import java.util.Map;
*/
@Slf4j
@Component
public class PlusWebSocketHandler extends AbstractWebSocketHandler {
public class RoomWebSocketHandler extends AbstractWebSocketHandler {
@Autowired
private IOpenLogic openLogic;
@Autowired
private MessageHandleApplication messageHandleApplication;
/**
* 连接成功后
*/
@@ -46,6 +47,7 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String token = String.valueOf(session.getAttributes().get(WebSocketConstants.TOKEN));
messageHandleApplication.processOn(session,message);
}
@Override

View File

@@ -0,0 +1,47 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.cai.domain.CaiUserCall;
import com.ruoyi.cai.service.CaiUserCallService;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.RoomDataCache;
import com.ruoyi.cai.ws.constant.RoomStatusEnums;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* 被叫同意接听处理
*/
@Component("agree")
public class AgreeMessageHandle extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private RoomDataCache roomDataCache;
@Autowired
private CaiUserCallService userCallService;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
if(!fdCtxData.isReceiver()){
return;
}
boolean agree = roomDataCache.setStatusAgree(room.getRoomId());
if(!agree){
return;
}
// 通知可进行接通
userCallService.update(Wrappers.lambdaUpdate(CaiUserCall.class)
.eq(CaiUserCall::getId,room.getRoomId())
.set(CaiUserCall::getStatus, RoomStatusEnums.STATUS_AGREE.getCode())
.set(CaiUserCall::getBeginTime, LocalDateTime.now()));
String message = "提示禁止任何涉黄、任何微信QQ引导到其它平台行为";
sendToAll(room.getRoomId(), WsRMsgGen.startVideo(room.getRoomId(),0L),WsRMsgGen.sysNotice(message));
}
}

View File

@@ -0,0 +1,25 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.service.RoomService;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 获取可通话时长
*/
@Component("cancalltime")
public class CanCallTimeMessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private RoomService roomService;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
Long time = roomService.canCallTime(room);
sendToCurrent(fdCtxData,WsRMsgGen.canCallTime(time));
}
}

View File

@@ -0,0 +1,46 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.cai.domain.CaiUserCall;
import com.ruoyi.cai.service.CaiUserCallService;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.constant.HangUpEnums;
import com.ruoyi.cai.ws.constant.RoomStatusEnums;
import com.ruoyi.cai.ws.service.RoomService;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 主叫方取消通话
*/
@Component("cancel")
public class CancelMessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private CaiUserCallService userCallService;
@Autowired
private RoomService roomService;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
if(!fdCtxData.isCaller()){
return;
}
if(!RoomStatusEnums.STATUS_CALLER_CONNECT.getCode().equals(room.getStatus())
&& !RoomStatusEnums.STATUS_RECEIVER_CONNECT.getCode().equals(room.getStatus())){
return;
}
String roomId = room.getRoomId();
sendToCurrent(fdCtxData,WsRMsgGen.hangup("通话已取消",roomId, HangUpEnums.CANCEL.getCode()));
sendToReceiver(roomId,WsRMsgGen.hangup("对方已取消",roomId, HangUpEnums.CANCEL.getCode()));
roomService.closeAllFd(roomId);
// IM TODO
// 更新房间状态
userCallService.update(Wrappers.lambdaUpdate(CaiUserCall.class)
.eq(CaiUserCall::getId,roomId)
.set(CaiUserCall::getStatus,RoomStatusEnums.STATUS_CALLER_CANCEL.getCode()));
}
}

View File

@@ -0,0 +1,60 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.domain.CaiAccount;
import com.ruoyi.cai.domain.CaiGift;
import com.ruoyi.cai.dto.app.query.GiveGiftRes;
import com.ruoyi.cai.service.CaiAccountService;
import com.ruoyi.cai.service.CaiGiftService;
import com.ruoyi.cai.service.CaiUserGiftService;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("gift")
public class GiftMessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private CaiGiftService giftService;
@Autowired
private CaiAccountService accountService;
@Autowired
private CaiUserGiftService userGiftService;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
Long giftId = map.getLong("giftId");
if(giftId == null){
return;
}
Long giftCount = map.getLongValue("giftCount",1L);
CaiGift gift = giftService.getById(giftId);
if(gift == null){
return;
}
Long giftAmount = gift.getPrice() * giftCount;
CaiAccount account = accountService.getByUserId(fdCtxData.getUserId());
Long userAccount = account.getIncomeCoin() + account.getCoin();
if(userAccount < giftAmount){
sendToCurrent(fdCtxData,WsRMsgGen.rechargeNotice("余额不足,点此充值"));
return;
}
if(fdCtxData.isCaller() && (userAccount - giftAmount) < room.getRoomData().getCallPrice()){
sendToCurrent(fdCtxData,WsRMsgGen.rechargeNotice("赠送后通话时间不足1分钟点此充值"));
return;
}
GiveGiftRes giveGiftRes = new GiveGiftRes();
giveGiftRes.setType(3);
giveGiftRes.setToUserId(fdCtxData.getTarUserId());
giveGiftRes.setGiftId(giftId);
giveGiftRes.setGiftCount(giftCount);
boolean b = userGiftService.giveGift(giveGiftRes);
if(!b){
sendToCurrent(fdCtxData,WsRMsgGen.sysNotice("赠送失败,请重试"));
return;
}
sendToAll(room.getRoomId(),WsRMsgGen.gift(gift,fdCtxData.getUserId(),fdCtxData.getTarUserId()));
}
}

View File

@@ -0,0 +1,53 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.RoomCtxCache;
import com.ruoyi.cai.ws.cache.RoomDataCache;
import com.ruoyi.cai.ws.constant.HangUpEnums;
import com.ruoyi.cai.ws.service.RoomService;
import com.ruoyi.websocket.dto.WsR;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import com.ruoyi.websocket.util.RoomWebSocketUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 挂断处理
*/
@Component("hangup")
public class HangupMessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private RoomService roomService;
@Autowired
private RoomDataCache roomDataCache;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
if(StringUtils.isEmpty(room.getRoomId())){
return;
}
// 经测试app端挂断时可能会把旧的房间id传上来所以需要判断id与fd上下文的一致性
if(!room.getRoomId().equals(fdCtxData.getRoomId())){
return;
}
boolean b = roomDataCache.hangUp(room.getRoomId());
if(!b){
return;
}
// 触发结算 TODO
Integer type = fdCtxData.isCaller() ? HangUpEnums.FROM.getCode() : HangUpEnums.TO.getCode();
sendToCurrent(fdCtxData,WsRMsgGen.hangup("您已挂断",room.getRoomId(), type));
sendToTar(fdCtxData,WsRMsgGen.hangup("对方已挂断",room.getRoomId(), type));
roomService.closeAllFd(room.getRoomId());
}
}

View File

@@ -0,0 +1,34 @@
package com.ruoyi.websocket.handler.message;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.UserDataCache;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 心跳处理
*/
@Component("heartbeat")
public class HeartbeatMessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private UserDataCache userDataCache;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
if(!room.isCanCall()){
return;
}
Map<String,Object> update = new HashMap<>();
update.put("heartTime", DateUtil.currentSeconds());
userDataCache.hMSet(room.getRoomId(),fdCtxData.getUserType(),update);
sendToCurrent(fdCtxData, WsRMsgGen.heartbeat());
}
}

View File

@@ -0,0 +1,25 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
/**
* 聊天消息处理
*/
@Component("message")
public class MessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
String txt = map.getString("txt");
if(StringUtils.isEmpty(txt) || !room.isOnline()){
return;
}
sendToAll(room.getRoomId(),WsRMsgGen.chatData(txt,fdCtxData.getUserId(),fdCtxData.getTarUserId()));
}
}

View File

@@ -0,0 +1,54 @@
package com.ruoyi.websocket.handler.message;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.cai.domain.CaiUserCall;
import com.ruoyi.cai.service.CaiUserCallService;
import com.ruoyi.cai.ws.bean.FdCtxData;
import com.ruoyi.cai.ws.bean.Room;
import com.ruoyi.cai.ws.cache.RoomCtxCache;
import com.ruoyi.cai.ws.cache.RoomDataCache;
import com.ruoyi.cai.ws.constant.HangUpEnums;
import com.ruoyi.cai.ws.constant.RoomStatusEnums;
import com.ruoyi.cai.ws.service.RoomService;
import com.ruoyi.websocket.dto.WsRMsgGen;
import com.ruoyi.websocket.handler.AbstractMessageHandle;
import com.ruoyi.websocket.handler.IMessageHandler;
import com.ruoyi.websocket.util.RoomWebSocketUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 被叫方拒绝通话
*/
@Component("cancalltime")
public class RefuseMessageHandler extends AbstractMessageHandle implements IMessageHandler {
@Autowired
private RoomDataCache roomDataCache;
@Autowired
private RoomCtxCache roomCtxCache;
@Autowired
private RoomService roomService;
@Autowired
private CaiUserCallService userCallService;
@Override
public void processOn(Room room, FdCtxData fdCtxData, JSONObject map) {
if(!fdCtxData.isReceiver() || !RoomStatusEnums.STATUS_RECEIVER_CONNECT.getCode().equals(room.getStatus())){
return;
}
boolean b = roomDataCache.hangUp(room.getRoomId());
if(!b){
return;
}
sendToCurrent(fdCtxData, WsRMsgGen.hangup("已拒绝",room.getRoomId(), HangUpEnums.REFUSE.getCode()));
sendToTar(fdCtxData,WsRMsgGen.hangup("对方已拒绝",room.getRoomId(), HangUpEnums.REFUSE.getCode()));
roomService.closeAllFd(room.getRoomId());
//发送IM通知 TODO
// 更新房间状态
userCallService.update(Wrappers.lambdaUpdate(CaiUserCall.class)
.eq(CaiUserCall::getId,room.getRoomId())
.set(CaiUserCall::getStatus,RoomStatusEnums.STATUS_REFUSE.getCode()));
}
}