通话逻辑
This commit is contained in:
@@ -162,3 +162,12 @@ sms:
|
||||
sdkAppId: appid
|
||||
#地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
|
||||
territory: ap-guangzhou
|
||||
spring:
|
||||
rabbitmq:
|
||||
addresses: 127.0.0.1 #ip地址
|
||||
username: admin # 账号
|
||||
password: admin # 密码
|
||||
agora:
|
||||
app-id: app
|
||||
key: key
|
||||
secret: secret
|
||||
|
||||
@@ -165,3 +165,12 @@ sms:
|
||||
sdkAppId: appid
|
||||
#地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
|
||||
territory: ap-guangzhou
|
||||
spring:
|
||||
rabbitmq:
|
||||
addresses: 127.0.0.1 #ip地址
|
||||
username: admin # 账号
|
||||
password: admin # 密码
|
||||
agora:
|
||||
app-id: app
|
||||
key: key
|
||||
secret: secret
|
||||
|
||||
@@ -250,8 +250,3 @@ management:
|
||||
show-details: ALWAYS
|
||||
logfile:
|
||||
external-file: ./logs/sys-console.log
|
||||
spring:
|
||||
rabbitmq:
|
||||
addresses: 127.0.0.1 #ip地址
|
||||
username: admin # 账号
|
||||
password: admin # 密码
|
||||
|
||||
@@ -2,44 +2,39 @@ package com.ruoyi.cai.agora;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.cai.util.RestTemplateUtil;
|
||||
import com.ruoyi.websocket.config.AgoraProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Component
|
||||
public class Agora {
|
||||
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
private final String APP_ID = "appId";
|
||||
@Autowired
|
||||
private AgoraProperties agoraProperties;
|
||||
|
||||
public String getAuthorizationHeader(){
|
||||
// 客户 ID
|
||||
final String customerKey = "Your customer key";
|
||||
// 客户密钥
|
||||
final String customerSecret = "Your customer secret";
|
||||
|
||||
// 拼接客户 ID 和客户密钥并使用 base64 编码
|
||||
String plainCredentials = customerKey + ":" + customerSecret;
|
||||
String plainCredentials = agoraProperties.getKey() + ":" + agoraProperties.getSecret();
|
||||
String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes()));
|
||||
// 创建 authorization header
|
||||
String authorizationHeader = "Basic " + base64Credentials;
|
||||
return authorizationHeader;
|
||||
return "Basic " + base64Credentials;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getChannelUsers(String roomId){
|
||||
String url = "http://api.sd-rtn.com/dev/v1/channel/user/%s/%s";
|
||||
url = String.format(url, APP_ID, roomId);
|
||||
url = String.format(url, agoraProperties.getAppId(), roomId);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("Authorization", getAuthorizationHeader());
|
||||
HttpEntity httpEntity = new HttpEntity<>(headers);
|
||||
JSONObject jsonobject = restTemplate.getForObject(url,JSONObject.class,httpEntity);
|
||||
JSONObject jsonobject = RestTemplateUtil.restTemplate.getForObject(url,JSONObject.class,httpEntity);
|
||||
// "success":true,"data":{"channel_exist":true,"mode":2,"broadcasters":[1001,1025],"audience":[],"audience_total":0}}
|
||||
if(jsonobject == null){
|
||||
return Collections.emptyList();
|
||||
@@ -51,7 +46,7 @@ public class Agora {
|
||||
public void closeChannel(String roomId){
|
||||
String url = "http://api.sd-rtn.com/dev/v1/kicking-rule";
|
||||
Map<String,Object> param = new HashMap<>();
|
||||
param.put("appid",APP_ID);
|
||||
param.put("appid",agoraProperties.getAppId());
|
||||
param.put("cname",roomId);
|
||||
param.put("time",0);
|
||||
param.put("privileges",Collections.emptyList());
|
||||
@@ -59,7 +54,7 @@ public class Agora {
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("Authorization", getAuthorizationHeader());
|
||||
HttpEntity httpEntity = new HttpEntity<>(param, headers);
|
||||
restTemplate.postForObject(url, httpEntity, JSONObject.class);
|
||||
RestTemplateUtil.restTemplate.postForObject(url, httpEntity, JSONObject.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ExecutorConstant {
|
||||
CPU_NUM << 2,
|
||||
5,
|
||||
TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(50),
|
||||
new ArrayBlockingQueue<>(5),
|
||||
init("roomThreadPoll-%d"),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
ROOM_EXECUTOR = TtlExecutors.getTtlExecutor(roomExecutor);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ruoyi.cai.util;
|
||||
|
||||
import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class RestTemplateUtil {
|
||||
|
||||
public static RestTemplate restTemplate = null;
|
||||
|
||||
static {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
requestFactory.setConnectTimeout(3000);
|
||||
requestFactory.setReadTimeout(3000);
|
||||
restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory));
|
||||
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
|
||||
//添加转换器
|
||||
for (HttpMessageConverter<?> messageConverter : messageConverters) {
|
||||
if (messageConverter instanceof StringHttpMessageConverter) {
|
||||
StringHttpMessageConverter converter = (StringHttpMessageConverter) messageConverter;
|
||||
converter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ruoyi.cai.ws.bean;
|
||||
|
||||
import com.ruoyi.cai.ws.constant.UserDataConstant;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@@ -11,4 +12,12 @@ public class FdCtxData {
|
||||
private Integer userType;
|
||||
private Long tarUserId;
|
||||
private Integer tarUserType;
|
||||
|
||||
public boolean isReceiver(){
|
||||
return userType == UserDataConstant.TYPE_RECEIVER;
|
||||
}
|
||||
|
||||
public boolean isCaller(){
|
||||
return userType == UserDataConstant.TYPE_CALLER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
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 {
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ public class RoomData {
|
||||
private String skillName;
|
||||
private Integer status;
|
||||
private BigDecimal videoDivide;
|
||||
private Integer payCoin = 0;
|
||||
private Integer payIncome = 0;
|
||||
private Long hangUpTime;
|
||||
|
||||
private Long beginTime;
|
||||
|
||||
@@ -3,6 +3,7 @@ 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.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -24,4 +25,13 @@ public class FdCtxDataCache {
|
||||
redisTemplate.opsForValue().set(getKey(fdCtxData.getSessionKey()),str,5, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
public FdCtxData getByRoomId(String sessionKey){
|
||||
String key = getKey(sessionKey);
|
||||
String s = redisTemplate.opsForValue().get(key);
|
||||
if(StringUtils.isEmpty(s)){
|
||||
return null;
|
||||
}
|
||||
return JSON.parseObject(s,FdCtxData.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.ruoyi.cai.ws.cache;
|
||||
|
||||
import com.ruoyi.cai.ws.constant.RedisConstant;
|
||||
import com.ruoyi.cai.ws.constant.UserDataConstant;
|
||||
import com.ruoyi.websocket.holder.WebSocketSessionHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -24,6 +27,16 @@ public class RoomCtxCache {
|
||||
redisTemplate.expire(key,7, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
public List<String> getSessionKeysByRoomId(String roomId){
|
||||
String key = getKey(roomId);
|
||||
Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
|
||||
List<String> res = new ArrayList<>();
|
||||
for (Object o : entries.keySet()) {
|
||||
res.add(String.valueOf(o));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public String getSessionKeyByRoomIdAndUserType(String roomId,Integer userType){
|
||||
String key = getKey(roomId);
|
||||
Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
|
||||
@@ -38,6 +51,15 @@ public class RoomCtxCache {
|
||||
}
|
||||
|
||||
public String getSessionKeyReceiverByRoomId(String roomId){
|
||||
return getSessionKeyByRoomIdAndUserType(roomId,UserDataCache.TYPE_RECEIVER);
|
||||
return getSessionKeyByRoomIdAndUserType(roomId, UserDataConstant.TYPE_RECEIVER);
|
||||
}
|
||||
|
||||
public String getSessionKeyCallerByRoomId(String roomId){
|
||||
return getSessionKeyByRoomIdAndUserType(roomId, UserDataConstant.TYPE_CALLER);
|
||||
}
|
||||
|
||||
public void del(String roomId) {
|
||||
String key = getKey(roomId);
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,17 +22,6 @@ 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
|
||||
@@ -65,10 +54,11 @@ public class RoomDataCache {
|
||||
"end\n" +
|
||||
"return redis.call('hMSet', KEYS[1], 'status', 8, 'hangupTime', ARGV[1])";
|
||||
|
||||
public void hangUp(String roomId) {
|
||||
public boolean hangUp(String roomId) {
|
||||
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(HANG_UP,Boolean.class);
|
||||
String currentTime = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)), currentTime);
|
||||
Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)), currentTime);
|
||||
return BooleanUtils.isTrue(execute);
|
||||
}
|
||||
|
||||
public void setStatus(String roomId, RoomStatusEnums status) {
|
||||
@@ -87,4 +77,19 @@ public class RoomDataCache {
|
||||
Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)));
|
||||
return BooleanUtils.isTrue(execute);
|
||||
}
|
||||
|
||||
private final static String SET_STATUS_AGREE =
|
||||
"local status = tonumber(redis.call('hget', KEYS[1], 'status'))\n" +
|
||||
"local beginTime = tonumber(redis.call('hget', KEYS[1], 'beginTime'))\n" +
|
||||
"if status ~= 3 or beginTime > 0 then\n" +
|
||||
" return 0\n" +
|
||||
"end\n" +
|
||||
"return redis.call('hmset', KEYS[1], 'status', 7, 'beginTime', ARGV[1])";
|
||||
|
||||
public boolean setStatusAgree(String roomId) {
|
||||
DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(SET_STATUS_AGREE,Boolean.class);
|
||||
String currentTime = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
Boolean execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(getKey(roomId)),currentTime);
|
||||
return BooleanUtils.isTrue(execute);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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.constant.UserDataConstant;
|
||||
import com.ruoyi.cai.ws.util.MapGetUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -12,21 +13,19 @@ 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");
|
||||
return String.format(RedisConstant.USER_ROOM_DATA,roomId,type== UserDataConstant.TYPE_CALLER?"caller":"receiver");
|
||||
}
|
||||
|
||||
public UserData getCallerUserDataByRoom(String roomId){
|
||||
return getUserDataByRoom(roomId,TYPE_CALLER);
|
||||
return getUserDataByRoom(roomId,UserDataConstant.TYPE_CALLER);
|
||||
}
|
||||
|
||||
public UserData getReceiverUserDataByRoom(String roomId){
|
||||
return getUserDataByRoom(roomId,TYPE_RECEIVER);
|
||||
return getUserDataByRoom(roomId,UserDataConstant.TYPE_RECEIVER);
|
||||
}
|
||||
|
||||
public UserData getUserDataByRoom(String roomId,int type){
|
||||
@@ -58,11 +57,11 @@ public class UserDataCache {
|
||||
}
|
||||
|
||||
public void initCaller(UserData callerUserData) {
|
||||
init(callerUserData,TYPE_CALLER);
|
||||
init(callerUserData,UserDataConstant.TYPE_CALLER);
|
||||
}
|
||||
|
||||
public void initReceiver(UserData callerUserData) {
|
||||
init(callerUserData,TYPE_RECEIVER);
|
||||
init(callerUserData,UserDataConstant.TYPE_RECEIVER);
|
||||
}
|
||||
|
||||
public void hMSet(String roomId,Integer userType,Map<String,Object> data) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ruoyi.cai.ws.constant;
|
||||
|
||||
public class UserDataConstant {
|
||||
|
||||
public final static int TYPE_CALLER = 1; // 视频发起者
|
||||
public final static int TYPE_RECEIVER = 2; // 视频接收者
|
||||
|
||||
}
|
||||
@@ -10,11 +10,12 @@ 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.constant.UserDataConstant;
|
||||
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.dto.WsRMsgGen;
|
||||
import com.ruoyi.websocket.handle.IOpenLogic;
|
||||
import com.ruoyi.websocket.handler.IOpenLogic;
|
||||
import com.ruoyi.websocket.util.RoomWebSocketUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -80,13 +81,13 @@ public class OpenLogic implements IOpenLogic {
|
||||
fdCtxData.setRoomId(room.getRoomId());
|
||||
fdCtxData.setUserId(userId);
|
||||
if(userId.equals(room.getCallUserData().getId())){
|
||||
fdCtxData.setUserType(UserDataCache.TYPE_CALLER);
|
||||
fdCtxData.setUserType(UserDataConstant.TYPE_CALLER);
|
||||
fdCtxData.setTarUserId(room.getReceiverUserData().getId());
|
||||
fdCtxData.setTarUserType(UserDataCache.TYPE_RECEIVER);
|
||||
fdCtxData.setTarUserType(UserDataConstant.TYPE_RECEIVER);
|
||||
} else {
|
||||
fdCtxData.setUserType(UserDataCache.TYPE_RECEIVER);
|
||||
fdCtxData.setUserType(UserDataConstant.TYPE_RECEIVER);
|
||||
fdCtxData.setTarUserId(room.getCallUserData().getId());
|
||||
fdCtxData.setTarUserType(UserDataCache.TYPE_CALLER);
|
||||
fdCtxData.setTarUserType(UserDataConstant.TYPE_CALLER);
|
||||
}
|
||||
fdCtxDataCache.save(fdCtxData);
|
||||
roomCtxCache.addFd(sessionKey,roomId,fdCtxData.getUserType());
|
||||
@@ -101,7 +102,7 @@ public class OpenLogic implements IOpenLogic {
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("connectTime", DateUtil.currentSeconds());
|
||||
map.put("heartTime",DateUtil.currentSeconds());
|
||||
userDataCache.hMSet(room.getRoomId(), UserDataCache.TYPE_CALLER,map);
|
||||
userDataCache.hMSet(room.getRoomId(), UserDataConstant.TYPE_CALLER,map);
|
||||
roomDataCache.setStatus(room.getRoomId(),RoomStatusEnums.STATUS_CALLER_CONNECT);
|
||||
onlineDataCache.add(room.getRoomId());
|
||||
userService.updateVideoStatus(userId,1);
|
||||
@@ -142,7 +143,7 @@ public class OpenLogic implements IOpenLogic {
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("connectTime", DateUtil.currentSeconds());
|
||||
map.put("heartTime",DateUtil.currentSeconds());
|
||||
userDataCache.hMSet(room.getRoomId(), UserDataCache.TYPE_RECEIVER,map);
|
||||
userDataCache.hMSet(room.getRoomId(), UserDataConstant.TYPE_RECEIVER,map);
|
||||
boolean res = roomDataCache.setStatusReceiverConnection(room.getRoomId());
|
||||
if(!res){
|
||||
return;
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
package com.ruoyi.cai.ws.service;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.ruoyi.cai.domain.CaiAccount;
|
||||
import com.ruoyi.cai.service.CaiAccountService;
|
||||
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.cache.*;
|
||||
import com.ruoyi.cai.ws.constant.HangUpEnums;
|
||||
import com.ruoyi.cai.ws.constant.RoomStatusEnums;
|
||||
import com.ruoyi.cai.ws.util.WsExceptionUtil;
|
||||
import com.ruoyi.websocket.util.WebSocketUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RoomService {
|
||||
@Autowired
|
||||
private RoomDataCache roomDataCache;
|
||||
@@ -24,6 +27,12 @@ public class RoomService {
|
||||
private UserDataCache userDataCache;
|
||||
@Autowired
|
||||
private CallerRoomCache callerRoomCache;
|
||||
@Autowired
|
||||
private CaiAccountService accountService;
|
||||
@Autowired
|
||||
private FdCtxDataCache fdCtxDataCache;
|
||||
@Autowired
|
||||
private RoomCtxCache roomCtxCache;
|
||||
|
||||
public Room load(String roomId){
|
||||
Room room = new Room();
|
||||
@@ -65,6 +74,15 @@ public class RoomService {
|
||||
}
|
||||
}
|
||||
|
||||
public void closeAllFd(String roomId){
|
||||
List<String> sessionKeysByRoomId = roomCtxCache.getSessionKeysByRoomId(roomId);
|
||||
for (String sessionKey : sessionKeysByRoomId) {
|
||||
WebSocketUtils.close(sessionKey);
|
||||
}
|
||||
// 删除房间FD,避免重连
|
||||
roomCtxCache.del(roomId);
|
||||
}
|
||||
|
||||
public void delCallRoom(Long fromUid) {
|
||||
callerRoomCache.del(fromUid);
|
||||
}
|
||||
@@ -100,4 +118,26 @@ public class RoomService {
|
||||
return DateUtil.currentSeconds() - beginTime;
|
||||
|
||||
}
|
||||
|
||||
public Long canCallTime(Room room) {
|
||||
try {
|
||||
Long callId = room.getCallUserData().getId();
|
||||
CaiAccount account = accountService.getByUserId(callId);
|
||||
if(account == null){
|
||||
return 0L;
|
||||
}
|
||||
RoomData roomData = room.getRoomData();
|
||||
int blockAmount = roomData.getPayCoin() + roomData.getPayIncome();
|
||||
long totalAmount = account.getTotalCoin()+account.getIncomeCoin() + blockAmount;
|
||||
long totalSecond = (totalAmount / roomData.getCallPrice()) / 60;
|
||||
long useTime = 0;
|
||||
if(roomData.getBeginTime() != null){
|
||||
useTime = DateUtil.currentSeconds() - roomData.getBeginTime();
|
||||
}
|
||||
return totalSecond - useTime;
|
||||
}catch (Exception e){
|
||||
log.error("计算可通话时间失败!",e);
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-cai</artifactId>
|
||||
<version>4.8.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.ruoyi.websocket.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "agora")
|
||||
public class AgoraProperties {
|
||||
private String appId;
|
||||
private String key;
|
||||
private String secret;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ruoyi.websocket.dto;
|
||||
|
||||
import org.apache.poi.hssf.record.OldCellRecord;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ruoyi.cai.domain.CaiGift;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -32,9 +33,9 @@ public class WsRMsgGen {
|
||||
map.put("content",content);
|
||||
map.put("linkType",0);
|
||||
map.put("linkUrl",null);
|
||||
map.put("fromUid",0);
|
||||
map.put("toUid",0);
|
||||
map.put("cancalltime",0);
|
||||
map.put("fromUid",null);
|
||||
map.put("toUid",null);
|
||||
map.put("cancalltime",null);
|
||||
WsR<Map<String, Object>> ok = WsR.ok(map);
|
||||
ok.setMethod("notice");
|
||||
ok.setMsg("提示!");
|
||||
@@ -59,4 +60,71 @@ public class WsRMsgGen {
|
||||
ok.setMsg(message);
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static WsR canCallTime(long time) {
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("tip",time);
|
||||
WsR<Map<String, Object>> ok = WsR.ok(map);
|
||||
ok.setMethod("cancalltime");
|
||||
ok.setMsg("提示!");
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static WsR rechargeNotice(String content) {
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("type",1);
|
||||
map.put("content",content);
|
||||
map.put("linkType",2);
|
||||
map.put("linkUrl","rechargeCoin");
|
||||
map.put("fromUid",null);
|
||||
map.put("toUid",null);
|
||||
map.put("cancalltime",null);
|
||||
WsR<Map<String, Object>> ok = WsR.ok(map);
|
||||
ok.setMethod("notice");
|
||||
ok.setMsg("提示!");
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static WsR gift(CaiGift gift, Long callerId, Long receiverId) {
|
||||
Map<String,Object> content = new HashMap<>();
|
||||
content.put("giftid",gift.getId());
|
||||
content.put("giftname",gift.getName());
|
||||
content.put("gifticon",gift.getImg());
|
||||
content.put("giftsvga",gift.getSvga());
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("type",3);
|
||||
map.put("content", JSON.toJSONString(content));
|
||||
map.put("linkType",null);
|
||||
map.put("linkUrl",null);
|
||||
map.put("fromUid",callerId);
|
||||
map.put("toUid",receiverId);
|
||||
map.put("cancalltime",null);
|
||||
WsR<Map<String, Object>> ok = WsR.ok(map);
|
||||
ok.setMethod("notice");
|
||||
ok.setMsg("提示!");
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static WsR heartbeat() {
|
||||
Map<String,Object> content = new HashMap<>();
|
||||
WsR<Map<String, Object>> ok = WsR.ok(content);
|
||||
ok.setMethod("heartbeat");
|
||||
ok.setMsg("检测成功!");
|
||||
return ok;
|
||||
}
|
||||
|
||||
public static WsR chatData(String txt, Long from, Long to) {
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("type",2);
|
||||
map.put("content", txt);
|
||||
map.put("linkType",null);
|
||||
map.put("linkUrl",null);
|
||||
map.put("fromUid",from);
|
||||
map.put("toUid",to);
|
||||
map.put("cancalltime",null);
|
||||
WsR<Map<String, Object>> ok = WsR.ok(map);
|
||||
ok.setMethod("notice");
|
||||
ok.setMsg("提示!");
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ruoyi.websocket.handle;
|
||||
package com.ruoyi.websocket.handler;
|
||||
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,19 @@
|
||||
package com.ruoyi.websocket.util;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.websocket.dto.WsR;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
public class RoomWebSocketUtil {
|
||||
public static void sendSendMessage(String sessionKey,WsR r){
|
||||
WebSocketUtils.sendMessage(sessionKey, JSON.toJSONString(r));
|
||||
}
|
||||
|
||||
public static void sendSendMessage(List<String> sessionKey, WsR r){
|
||||
for (String s : sessionKey) {
|
||||
WebSocketUtils.sendMessage(s, JSON.toJSONString(r));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user