package com.ruoyi.job; import cn.hutool.core.date.DateUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.cai.domain.UserCall; import com.ruoyi.cai.notice.YunxinWsServiceV2; import com.ruoyi.cai.service.UserCallService; import com.ruoyi.cai.ws.bean.Room; import com.ruoyi.cai.ws.bean.UserData; import com.ruoyi.cai.ws.cache.RoomCtxCache; import com.ruoyi.cai.ws.constant.HangUpEnums; import com.ruoyi.cai.ws.constant.RoomStatusEnums; import com.ruoyi.cai.ws.dto.WsR; import com.ruoyi.cai.ws.dto.WsRMsgGen; import com.ruoyi.cai.ws.job.JobResp; import com.ruoyi.cai.ws.service.RoomService; import com.ruoyi.cai.ws.service.SettleResp; import com.ruoyi.cai.ws.service.SettleService; import com.ruoyi.cai.ws.util.RoomWebSocketUtil; import com.ruoyi.yunxin.Yunxin; import com.ruoyi.cai.notice.enums.CallNoticeEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @Component @Slf4j public class RoomCheckJobService { @Autowired private RoomService roomService; @Autowired private UserCallService userCallService; @Autowired private Yunxin yunxin; @Autowired private SettleService settleService; @Autowired private RoomCtxCache roomCtxCache; public JobResp checkRoom(Long roomId){ Room room = roomService.load(roomId); log.info("调试日志:开始检查房间 room={}" , JSON.toJSONString(room)); if(room == null){ return JobResp.builder().nextCreateJob(false).build(); } // 检查是否三分钟没有接听 log.info("调试日志:检查是否三分钟没有接听 roomId={}" , roomId); JobResp resp = this.checkRoomCallerTimeOut(room); if(!resp.isNextCreateJob()){ log.info("调试日志:三分钟没有接听,可能关闭了 roomId={}" , roomId); return resp; } // 检查心跳 log.info("调试日志:检查心跳是否超时 roomId={}" , roomId); JobResp heartbeat = checkRoomHeartbeat(room); if(!heartbeat.isNextCreateJob()){ log.info("调试日志:心跳超时了,可能关闭了 roomId={}" , roomId); return heartbeat; } this.checkCanCallTime(room); // 尝试结算一下 log.info("调试日志:开始尝试结算 roomId={}" , roomId); SettleResp settleResp = settleService.processOn(roomId); JobResp build = JobResp.builder().nextCreateJob(settleResp.isNextRun()).build(); if(!build.isNextCreateJob()){ log.info("调试日志:结算成功了,可能关闭了 roomId={}" , roomId); } return build; } private void checkCanCallTime(Room room){ Long time = roomService.canCallTime(room); if(time < 150 && time > 60){ // 提示余额不足 String sessionKey = roomCtxCache.getSessionKeyCallerByRoomId(room.getRoomId()); RoomWebSocketUtil.sendSendMessage(sessionKey, WsRMsgGen.rechargeNotice("您的余额不足,点此充值")); } } private JobResp checkRoomHeartbeat(Room room){ if(!room.isCanCall()){ return JobResp.builder().nextCreateJob(true).build(); } Long roomId = room.getRoomId(); UserData callUserData = room.getCallUserData(); UserData receiverUserData = room.getReceiverUserData(); boolean timeOut = false; WsR hangup = null; if(isHeartTimeout(callUserData)){ timeOut = true; hangup = WsRMsgGen.hangup("呼叫方连接中断", roomId, HangUpEnums.FROM.getCode()); }else if(isHeartTimeout(receiverUserData)){ timeOut = true; hangup = WsRMsgGen.hangup("接听方连接中断", roomId, HangUpEnums.TO.getCode()); } if(timeOut){ boolean nextCreateJob = false; if(roomService.hangUp(roomId)){ userCallService.update(Wrappers.lambdaUpdate(UserCall.class) .eq(UserCall::getId,roomId) .set(UserCall::getStatus, RoomStatusEnums.STATUS_TIMEOUT_CANCEL.getCode())); SettleResp settleResp = settleService.processOn(roomId); nextCreateJob = settleResp.isNextRun(); } List keys = roomCtxCache.getSessionKeysByRoomId(roomId); RoomWebSocketUtil.sendSendMessage(keys, hangup); roomService.closeAllFd(roomId); return JobResp.builder().nextCreateJob(nextCreateJob).build(); } return JobResp.builder().nextCreateJob(true).build(); } // 检测是不是3分钟没有接听 private JobResp checkRoomCallerTimeOut(Room room){ if(!RoomStatusEnums.STATUS_CALLER_CONNECT.getCode().equals(room.getStatus()) && !RoomStatusEnums.STATUS_RECEIVER_CONNECT.getCode().equals(room.getStatus())) { return JobResp.builder().nextCreateJob(true).build(); } UserData callUserData = room.getCallUserData(); UserData receiverUserData = room.getReceiverUserData(); Long connectTimeCaller = callUserData.getConnectTime(); Long connectTimeReceiver = receiverUserData.getConnectTime(); boolean timeOut = false; if(connectTimeCaller != null && DateUtil.currentSeconds() - connectTimeCaller > 180){ timeOut = true; }else if(connectTimeReceiver != null && DateUtil.currentSeconds() - connectTimeReceiver > 180){ timeOut = true; } if(timeOut){ Long roomId = room.getRoomId(); boolean nextCreateJob = false; if(roomService.hangUp(roomId)){ userCallService.update(Wrappers.lambdaUpdate(UserCall.class) .eq(UserCall::getId,roomId) .set(UserCall::getStatus, RoomStatusEnums.STATUS_TIMEOUT_CANCEL.getCode())); List keys = roomCtxCache.getSessionKeysByRoomId(roomId); WsR hangUp = WsRMsgGen.hangup("接听超时", roomId, HangUpEnums.TIMEOUT.getCode()); RoomWebSocketUtil.sendSendMessage(keys, hangUp); SettleResp settleResp = settleService.processOn(roomId); nextCreateJob = settleResp.isNextRun(); } roomService.closeAllFd(roomId); if(!nextCreateJob){ yunxinWsService.sendToCallNotify(callUserData.getId(),receiverUserData.getId(), CallNoticeEnum.TIMEOUT,0L); } return JobResp.builder().nextCreateJob(nextCreateJob).build(); } return JobResp.builder().nextCreateJob(true).build(); } @Autowired private YunxinWsServiceV2 yunxinWsService; /** * 是否心跳超时 * @param userData * @return */ private boolean isHeartTimeout(UserData userData){ if(userData.getConnectTime() == null){ return false; } if(DateUtil.currentSeconds() - userData.getHeartTime() < 117){ return false; } return true; } }