committed by
Gitee
561 changed files with 43937 additions and 2075 deletions
@ -1,10 +1,10 @@ |
|||||
package com.bx.imclient.listener; |
package com.bx.imclient.listener; |
||||
|
|
||||
|
|
||||
import com.bx.imcommon.model.SendResult; |
import com.bx.imcommon.model.IMSendResult; |
||||
|
|
||||
public interface MessageListener { |
public interface MessageListener<T> { |
||||
|
|
||||
void process(SendResult result); |
void process(IMSendResult<T> result); |
||||
|
|
||||
} |
} |
||||
|
|||||
@ -1,19 +1,18 @@ |
|||||
package com.bx.imcommon.contant; |
package com.bx.imcommon.contant; |
||||
|
|
||||
public class RedisKey { |
public class IMRedisKey { |
||||
|
|
||||
// im-server最大id,从0开始递增
|
// im-server最大id,从0开始递增
|
||||
public final static String IM_MAX_SERVER_ID = "im:max_server_id"; |
public final static String IM_MAX_SERVER_ID = "im:max_server_id"; |
||||
// 用户ID所连接的IM-server的ID
|
// 用户ID所连接的IM-server的ID
|
||||
public final static String IM_USER_SERVER_ID = "im:user:server_id:"; |
public final static String IM_USER_SERVER_ID = "im:user:server_id"; |
||||
// 未读私聊消息队列
|
// 未读私聊消息队列
|
||||
public final static String IM_UNREAD_PRIVATE_QUEUE = "im:unread:private:"; |
public final static String IM_UNREAD_PRIVATE_QUEUE = "im:unread:private"; |
||||
// 未读群聊消息队列
|
// 未读群聊消息队列
|
||||
public final static String IM_UNREAD_GROUP_QUEUE = "im:unread:group:"; |
public final static String IM_UNREAD_GROUP_QUEUE = "im:unread:group"; |
||||
// 私聊消息发送结果队列
|
// 私聊消息发送结果队列
|
||||
public final static String IM_RESULT_PRIVATE_QUEUE = "im:result:private"; |
public final static String IM_RESULT_PRIVATE_QUEUE = "im:result:private"; |
||||
// 群聊消息发送结果队列
|
// 群聊消息发送结果队列
|
||||
public final static String IM_RESULT_GROUP_QUEUE = "im:result:group"; |
public final static String IM_RESULT_GROUP_QUEUE = "im:result:group"; |
||||
|
|
||||
|
|
||||
} |
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
package com.bx.imcommon.enums; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
import java.util.List; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
public enum IMTerminalType { |
||||
|
|
||||
|
WEB(0,"web"), |
||||
|
APP(1,"app"); |
||||
|
|
||||
|
private Integer code; |
||||
|
|
||||
|
private String desc; |
||||
|
|
||||
|
IMTerminalType(Integer index, String desc) { |
||||
|
this.code =index; |
||||
|
this.desc=desc; |
||||
|
} |
||||
|
|
||||
|
public static IMTerminalType fromCode(Integer code){ |
||||
|
for (IMTerminalType typeEnum:values()) { |
||||
|
if (typeEnum.code.equals(code)) { |
||||
|
return typeEnum; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static List<Integer> codes(){ |
||||
|
return Arrays.stream(values()).map(IMTerminalType::code).collect(Collectors.toList()); |
||||
|
} |
||||
|
|
||||
|
public String description() { |
||||
|
return desc; |
||||
|
} |
||||
|
|
||||
|
public Integer code(){ |
||||
|
return this.code; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -1,42 +0,0 @@ |
|||||
package com.bx.imcommon.model; |
|
||||
|
|
||||
import com.bx.imcommon.serializer.DateToLongSerializer; |
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
|
||||
import lombok.Data; |
|
||||
|
|
||||
import java.util.Date; |
|
||||
|
|
||||
@Data |
|
||||
public class GroupMessageInfo { |
|
||||
|
|
||||
/* |
|
||||
* 消息id |
|
||||
*/ |
|
||||
private Long id; |
|
||||
|
|
||||
/* |
|
||||
* 群聊id |
|
||||
*/ |
|
||||
private Long groupId; |
|
||||
|
|
||||
/* |
|
||||
* 发送者id |
|
||||
*/ |
|
||||
private Long sendId; |
|
||||
|
|
||||
/* |
|
||||
* 消息内容 |
|
||||
*/ |
|
||||
private String content; |
|
||||
|
|
||||
/* |
|
||||
* 消息内容类型 具体枚举值由应用层定义 |
|
||||
*/ |
|
||||
private Integer type; |
|
||||
|
|
||||
/** |
|
||||
* 发送时间 |
|
||||
*/ |
|
||||
@JsonSerialize(using = DateToLongSerializer.class) |
|
||||
private Date sendTime; |
|
||||
} |
|
||||
@ -0,0 +1,43 @@ |
|||||
|
package com.bx.imcommon.model; |
||||
|
|
||||
|
import com.bx.imcommon.enums.IMTerminalType; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class IMGroupMessage<T> { |
||||
|
|
||||
|
/** |
||||
|
* 发送方 |
||||
|
*/ |
||||
|
private IMUserInfo sender; |
||||
|
|
||||
|
/** |
||||
|
* 接收者id列表(群成员列表) |
||||
|
*/ |
||||
|
private List<Long> recvIds; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 接收者终端类型,默认全部 |
||||
|
*/ |
||||
|
private List<Integer> recvTerminals = IMTerminalType.codes(); |
||||
|
|
||||
|
/** |
||||
|
* 是否发送给自己的其他终端,默认true |
||||
|
*/ |
||||
|
private Boolean sendToSelf = true; |
||||
|
|
||||
|
/** |
||||
|
* 是否需要回推发送结果,默认true |
||||
|
*/ |
||||
|
private Boolean sendResult = true; |
||||
|
|
||||
|
/** |
||||
|
* 消息内容 |
||||
|
*/ |
||||
|
private T data; |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
package com.bx.imcommon.model; |
||||
|
|
||||
|
import com.bx.imcommon.enums.IMTerminalType; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
|
||||
|
@Data |
||||
|
public class IMPrivateMessage<T> { |
||||
|
|
||||
|
/** |
||||
|
* 发送方 |
||||
|
*/ |
||||
|
private IMUserInfo sender; |
||||
|
|
||||
|
/** |
||||
|
* 接收者id |
||||
|
*/ |
||||
|
private Long recvId; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 接收者终端类型,默认全部 |
||||
|
*/ |
||||
|
private List<Integer> recvTerminals = IMTerminalType.codes(); |
||||
|
|
||||
|
/** |
||||
|
* 是否发送给自己的其他终端,默认true |
||||
|
*/ |
||||
|
private Boolean sendToSelf = true; |
||||
|
|
||||
|
/** |
||||
|
* 是否需要回推发送结果,默认true |
||||
|
*/ |
||||
|
private Boolean sendResult = true; |
||||
|
|
||||
|
/** |
||||
|
* 消息内容 |
||||
|
*/ |
||||
|
private T data; |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
package com.bx.imcommon.model; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class IMSendResult<T> { |
||||
|
|
||||
|
/** |
||||
|
* 发送方 |
||||
|
*/ |
||||
|
private IMUserInfo sender; |
||||
|
|
||||
|
/** |
||||
|
* 接收方 |
||||
|
*/ |
||||
|
private IMUserInfo receiver; |
||||
|
|
||||
|
/* |
||||
|
* 发送状态 IMCmdType |
||||
|
*/ |
||||
|
private Integer code; |
||||
|
|
||||
|
/* |
||||
|
* 消息内容 |
||||
|
*/ |
||||
|
private T data; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.bx.imcommon.model; |
||||
|
|
||||
|
import com.bx.imcommon.enums.IMTerminalType; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class IMSessionInfo { |
||||
|
/* |
||||
|
* 用户id |
||||
|
*/ |
||||
|
private Long userId; |
||||
|
|
||||
|
/* |
||||
|
* 终端类型 |
||||
|
*/ |
||||
|
private Integer terminal; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
package com.bx.imcommon.model; |
||||
|
|
||||
|
import lombok.AllArgsConstructor; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* @author: 谢绍许 |
||||
|
* @date: 2023-09-24 09:23:11 |
||||
|
* @version: 1.0 |
||||
|
*/ |
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
@AllArgsConstructor |
||||
|
public class IMUserInfo { |
||||
|
|
||||
|
/** |
||||
|
* 用户id |
||||
|
*/ |
||||
|
private Long id; |
||||
|
|
||||
|
/** |
||||
|
* 用户终端类型 IMTerminalType |
||||
|
*/ |
||||
|
private Integer terminal; |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -1,42 +0,0 @@ |
|||||
package com.bx.imcommon.model; |
|
||||
|
|
||||
import com.bx.imcommon.serializer.DateToLongSerializer; |
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
|
||||
import lombok.Data; |
|
||||
|
|
||||
import java.util.Date; |
|
||||
|
|
||||
@Data |
|
||||
public class PrivateMessageInfo { |
|
||||
|
|
||||
/* |
|
||||
* 消息id |
|
||||
*/ |
|
||||
private long id; |
|
||||
|
|
||||
/* |
|
||||
* 发送者id |
|
||||
*/ |
|
||||
private Long sendId; |
|
||||
|
|
||||
/* |
|
||||
* 接收者id |
|
||||
*/ |
|
||||
private Long recvId; |
|
||||
|
|
||||
/* |
|
||||
* 发送内容 |
|
||||
*/ |
|
||||
private String content; |
|
||||
|
|
||||
/* |
|
||||
* 消息内容类型 具体枚举值由应用层定义 |
|
||||
*/ |
|
||||
private Integer type; |
|
||||
|
|
||||
/** |
|
||||
* 发送时间 |
|
||||
*/ |
|
||||
@JsonSerialize(using = DateToLongSerializer.class) |
|
||||
private Date sendTime; |
|
||||
} |
|
||||
@ -1,24 +0,0 @@ |
|||||
package com.bx.imcommon.model; |
|
||||
|
|
||||
import com.bx.imcommon.enums.IMSendCode; |
|
||||
import lombok.Data; |
|
||||
|
|
||||
@Data |
|
||||
public class SendResult<T> { |
|
||||
|
|
||||
/* |
|
||||
* 接收者id |
|
||||
*/ |
|
||||
private Long recvId; |
|
||||
|
|
||||
/* |
|
||||
* 发送状态 |
|
||||
*/ |
|
||||
private IMSendCode code; |
|
||||
|
|
||||
/* |
|
||||
* 消息体(透传) |
|
||||
*/ |
|
||||
private T messageInfo; |
|
||||
|
|
||||
} |
|
||||
@ -0,0 +1,28 @@ |
|||||
|
package com.bx.implatform.dto; |
||||
|
|
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
import org.hibernate.validator.constraints.Length; |
||||
|
|
||||
|
import javax.validation.constraints.NotEmpty; |
||||
|
import javax.validation.constraints.NotNull; |
||||
|
|
||||
|
@Data |
||||
|
@ApiModel("群聊消息DTO") |
||||
|
public class GroupMessageDTO { |
||||
|
|
||||
|
@NotNull(message="群聊id不可为空") |
||||
|
@ApiModelProperty(value = "群聊id") |
||||
|
private Long groupId; |
||||
|
|
||||
|
|
||||
|
@Length(max=1024,message = "内容长度不得大于1024") |
||||
|
@NotEmpty(message="发送内容不可为空") |
||||
|
@ApiModelProperty(value = "发送内容") |
||||
|
private String content; |
||||
|
|
||||
|
@NotNull(message="消息类型不可为空") |
||||
|
@ApiModelProperty(value = "消息类型") |
||||
|
private Integer type; |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
package com.bx.implatform.dto; |
||||
|
|
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import javax.validation.constraints.NotEmpty; |
||||
|
|
||||
|
@Data |
||||
|
@ApiModel("修改密码DTO") |
||||
|
public class ModifyPwdDTO { |
||||
|
|
||||
|
@NotEmpty(message="旧用户密码不可为空") |
||||
|
@ApiModelProperty(value = "旧用户密码") |
||||
|
private String oldPassword; |
||||
|
|
||||
|
@NotEmpty(message="新用户密码不可为空") |
||||
|
@ApiModelProperty(value = "新用户密码") |
||||
|
private String newPassword; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
package com.bx.implatform.dto; |
||||
|
|
||||
|
|
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
import org.hibernate.validator.constraints.Length; |
||||
|
|
||||
|
import javax.validation.constraints.NotEmpty; |
||||
|
import javax.validation.constraints.NotNull; |
||||
|
|
||||
|
@Data |
||||
|
@ApiModel("私聊消息DTO") |
||||
|
public class PrivateMessageDTO { |
||||
|
|
||||
|
|
||||
|
@NotNull(message="接收用户id不可为空") |
||||
|
@ApiModelProperty(value = "接收用户id") |
||||
|
private Long recvId; |
||||
|
|
||||
|
|
||||
|
@Length(max=1024,message = "内容长度不得大于1024") |
||||
|
@NotEmpty(message="发送内容不可为空") |
||||
|
@ApiModelProperty(value = "发送内容") |
||||
|
private String content; |
||||
|
|
||||
|
@NotNull(message="消息类型不可为空") |
||||
|
@ApiModelProperty(value = "消息类型") |
||||
|
private Integer type; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
package com.bx.implatform.service; |
||||
|
|
||||
|
import com.bx.implatform.config.ICEServer; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import java.util.List; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* webrtc 通信服务 |
||||
|
* @author |
||||
|
*/ |
||||
|
public interface IWebrtcService { |
||||
|
|
||||
|
void call(Long uid, String offer); |
||||
|
|
||||
|
void accept( Long uid,@RequestBody String answer); |
||||
|
|
||||
|
void reject( Long uid); |
||||
|
|
||||
|
void cancel( Long uid); |
||||
|
|
||||
|
void failed( Long uid, String reason); |
||||
|
|
||||
|
void leave( Long uid) ; |
||||
|
|
||||
|
void candidate( Long uid, String candidate); |
||||
|
|
||||
|
List<ICEServer> getIceServers(); |
||||
|
|
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,245 @@ |
|||||
|
package com.bx.implatform.service.impl; |
||||
|
|
||||
|
import com.bx.imclient.IMClient; |
||||
|
import com.bx.imcommon.model.IMPrivateMessage; |
||||
|
import com.bx.imcommon.model.IMUserInfo; |
||||
|
import com.bx.implatform.vo.PrivateMessageVO; |
||||
|
import com.bx.implatform.config.ICEServer; |
||||
|
import com.bx.implatform.config.ICEServerConfig; |
||||
|
import com.bx.implatform.contant.RedisKey; |
||||
|
import com.bx.implatform.enums.MessageType; |
||||
|
import com.bx.implatform.exception.GlobalException; |
||||
|
import com.bx.implatform.service.IWebrtcService; |
||||
|
import com.bx.implatform.session.SessionContext; |
||||
|
import com.bx.implatform.session.UserSession; |
||||
|
import com.bx.implatform.session.WebrtcSession; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.data.redis.core.RedisTemplate; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
|
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class WebrtcServiceImpl implements IWebrtcService { |
||||
|
|
||||
|
@Autowired |
||||
|
private IMClient imClient; |
||||
|
@Autowired |
||||
|
private RedisTemplate<String, Object> redisTemplate; |
||||
|
@Autowired |
||||
|
private ICEServerConfig iceServerConfig; |
||||
|
|
||||
|
@Override |
||||
|
public void call(Long uid, String offer) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
if (!imClient.isOnline(uid)) { |
||||
|
throw new GlobalException("对方目前不在线"); |
||||
|
} |
||||
|
// 创建webrtc会话
|
||||
|
WebrtcSession webrtcSession = new WebrtcSession(); |
||||
|
webrtcSession.setCallerId(session.getUserId()); |
||||
|
webrtcSession.setCallerTerminal(session.getTerminal()); |
||||
|
String key = getSessionKey(session.getUserId(), uid); |
||||
|
redisTemplate.opsForValue().set(key, webrtcSession, 12, TimeUnit.HOURS); |
||||
|
// 向对方所有终端发起呼叫
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_CALL.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
messageInfo.setContent(offer); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
sendMessage.setSendToSelf(false); |
||||
|
sendMessage.setSendResult(false); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void accept(Long uid, @RequestBody String answer) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
// 查询webrtc会话
|
||||
|
WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); |
||||
|
// 更新接受者信息
|
||||
|
webrtcSession.setAcceptorId(session.getUserId()); |
||||
|
webrtcSession.setAcceptorTerminal(session.getTerminal()); |
||||
|
String key = getSessionKey(session.getUserId(), uid); |
||||
|
redisTemplate.opsForValue().set(key, webrtcSession, 12, TimeUnit.HOURS); |
||||
|
// 向发起人推送接受通话信令
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_ACCEPT.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
messageInfo.setContent(answer); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
// 告知其他终端已经接受会话,中止呼叫
|
||||
|
sendMessage.setSendToSelf(true); |
||||
|
sendMessage.setSendResult(false); |
||||
|
sendMessage.setRecvTerminals((Collections.singletonList(webrtcSession.getCallerTerminal()))); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void reject(Long uid) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
// 查询webrtc会话
|
||||
|
WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); |
||||
|
// 删除会话信息
|
||||
|
removeWebrtcSession(uid, session.getUserId()); |
||||
|
// 向发起人推送拒绝通话信令
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_REJECT.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
// 告知其他终端已经拒绝会话,中止呼叫
|
||||
|
sendMessage.setSendToSelf(true); |
||||
|
sendMessage.setSendResult(false); |
||||
|
sendMessage.setRecvTerminals(Collections.singletonList(webrtcSession.getCallerTerminal())); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void cancel(Long uid) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
// 删除会话信息
|
||||
|
removeWebrtcSession(session.getUserId(), uid); |
||||
|
// 向对方所有终端推送取消通话信令
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_ACCEPT.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
sendMessage.setSendToSelf(false); |
||||
|
sendMessage.setSendResult(false); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
// 通知对方取消会话
|
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void failed(Long uid, String reason) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
// 查询webrtc会话
|
||||
|
WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); |
||||
|
// 删除会话信息
|
||||
|
removeWebrtcSession(uid, session.getUserId()); |
||||
|
// 向发起方推送通话失败信令
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_FAILED.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
// 告知其他终端已经会话失败,中止呼叫
|
||||
|
sendMessage.setSendToSelf(true); |
||||
|
sendMessage.setSendResult(false); |
||||
|
sendMessage.setRecvTerminals(Collections.singletonList(webrtcSession.getCallerTerminal())); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
// 通知对方取消会话
|
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void leave(Long uid) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
// 查询webrtc会话
|
||||
|
WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); |
||||
|
// 删除会话信息
|
||||
|
removeWebrtcSession(uid, session.getUserId()); |
||||
|
// 向对方推送挂断通话信令
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_HANDUP.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
sendMessage.setSendToSelf(false); |
||||
|
sendMessage.setSendResult(false); |
||||
|
Integer terminal = getTerminalType(uid, webrtcSession); |
||||
|
sendMessage.setRecvTerminals(Collections.singletonList(terminal)); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
// 通知对方取消会话
|
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void candidate(Long uid, String candidate) { |
||||
|
UserSession session = SessionContext.getSession(); |
||||
|
// 查询webrtc会话
|
||||
|
WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); |
||||
|
// 向发起方推送同步candidate信令
|
||||
|
PrivateMessageVO messageInfo = new PrivateMessageVO(); |
||||
|
messageInfo.setType(MessageType.RTC_CANDIDATE.code()); |
||||
|
messageInfo.setRecvId(uid); |
||||
|
messageInfo.setSendId(session.getUserId()); |
||||
|
messageInfo.setContent(candidate); |
||||
|
|
||||
|
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); |
||||
|
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); |
||||
|
sendMessage.setRecvId(uid); |
||||
|
sendMessage.setSendToSelf(false); |
||||
|
sendMessage.setSendResult(false); |
||||
|
Integer terminal = getTerminalType(uid, webrtcSession); |
||||
|
sendMessage.setRecvTerminals(Collections.singletonList(terminal)); |
||||
|
sendMessage.setData(messageInfo); |
||||
|
imClient.sendPrivateMessage(sendMessage); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<ICEServer> getIceServers() { |
||||
|
return iceServerConfig.getIceServers(); |
||||
|
} |
||||
|
|
||||
|
private WebrtcSession getWebrtcSession(Long userId, Long uid) { |
||||
|
String key = getSessionKey(userId, uid); |
||||
|
WebrtcSession webrtcSession = (WebrtcSession)redisTemplate.opsForValue().get(key); |
||||
|
if (webrtcSession == null) { |
||||
|
throw new GlobalException("视频通话已结束"); |
||||
|
} |
||||
|
return webrtcSession; |
||||
|
} |
||||
|
|
||||
|
private void removeWebrtcSession(Long userId, Long uid) { |
||||
|
String key = getSessionKey(userId, uid); |
||||
|
redisTemplate.delete(key); |
||||
|
} |
||||
|
|
||||
|
private String getSessionKey(Long id1, Long id2) { |
||||
|
Long minId = id1 > id2 ? id2 : id1; |
||||
|
Long maxId = id1 > id2 ? id1 : id2; |
||||
|
return String.join(":", RedisKey.IM_WEBRTC_SESSION, minId.toString(), maxId.toString()); |
||||
|
} |
||||
|
|
||||
|
private Integer getTerminalType(Long uid, WebrtcSession webrtcSession) { |
||||
|
if (uid.equals(webrtcSession.getCallerId())) { |
||||
|
return webrtcSession.getCallerTerminal(); |
||||
|
} |
||||
|
return webrtcSession.getAcceptorTerminal(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -1,11 +1,20 @@ |
|||||
package com.bx.implatform.session; |
package com.bx.implatform.session; |
||||
|
|
||||
|
import com.bx.imcommon.model.IMSessionInfo; |
||||
import lombok.Data; |
import lombok.Data; |
||||
|
|
||||
|
|
||||
|
|
||||
@Data |
@Data |
||||
public class UserSession { |
public class UserSession extends IMSessionInfo { |
||||
|
|
||||
private Long id; |
/* |
||||
|
* 用户名称 |
||||
|
*/ |
||||
private String userName; |
private String userName; |
||||
|
|
||||
|
/* |
||||
|
* 用户昵称 |
||||
|
*/ |
||||
private String nickName; |
private String nickName; |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,32 @@ |
|||||
|
package com.bx.implatform.session; |
||||
|
|
||||
|
import com.bx.imcommon.enums.IMTerminalType; |
||||
|
import io.swagger.models.auth.In; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
/* |
||||
|
* webrtc 会话信息 |
||||
|
* @Author Blue |
||||
|
* @Date 2022/10/21 |
||||
|
*/ |
||||
|
@Data |
||||
|
public class WebrtcSession { |
||||
|
/** |
||||
|
* 发起者id |
||||
|
*/ |
||||
|
private Long callerId; |
||||
|
/** |
||||
|
* 发起者终端类型 |
||||
|
*/ |
||||
|
private Integer callerTerminal; |
||||
|
|
||||
|
/** |
||||
|
* 接受者id |
||||
|
*/ |
||||
|
private Long acceptorId; |
||||
|
|
||||
|
/** |
||||
|
* 接受者终端类型 |
||||
|
*/ |
||||
|
private Integer acceptorTerminal; |
||||
|
} |
||||
File diff suppressed because it is too large
@ -1,28 +1,42 @@ |
|||||
package com.bx.implatform.vo; |
package com.bx.implatform.vo; |
||||
|
|
||||
import io.swagger.annotations.ApiModel; |
import com.bx.imcommon.serializer.DateToLongSerializer; |
||||
import io.swagger.annotations.ApiModelProperty; |
import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
||||
import lombok.Data; |
import lombok.Data; |
||||
import org.hibernate.validator.constraints.Length; |
|
||||
|
|
||||
import javax.validation.constraints.NotEmpty; |
import java.util.Date; |
||||
import javax.validation.constraints.NotNull; |
|
||||
|
|
||||
@Data |
@Data |
||||
@ApiModel("群聊消息VO") |
|
||||
public class GroupMessageVO { |
public class GroupMessageVO { |
||||
|
|
||||
@NotNull(message="群聊id不可为空") |
/* |
||||
@ApiModelProperty(value = "群聊id") |
* 消息id |
||||
|
*/ |
||||
|
private Long id; |
||||
|
|
||||
|
/* |
||||
|
* 群聊id |
||||
|
*/ |
||||
private Long groupId; |
private Long groupId; |
||||
|
|
||||
|
/* |
||||
|
* 发送者id |
||||
|
*/ |
||||
|
private Long sendId; |
||||
|
|
||||
@Length(max=1024,message = "内容长度不得大于1024") |
/* |
||||
@NotEmpty(message="发送内容不可为空") |
* 消息内容 |
||||
@ApiModelProperty(value = "发送内容") |
*/ |
||||
private String content; |
private String content; |
||||
|
|
||||
@NotNull(message="消息类型不可为空") |
/* |
||||
@ApiModelProperty(value = "消息类型") |
* 消息内容类型 具体枚举值由应用层定义 |
||||
|
*/ |
||||
private Integer type; |
private Integer type; |
||||
|
|
||||
|
/** |
||||
|
* 发送时间 |
||||
|
*/ |
||||
|
@JsonSerialize(using = DateToLongSerializer.class) |
||||
|
private Date sendTime; |
||||
} |
} |
||||
|
|||||
@ -1,31 +1,42 @@ |
|||||
package com.bx.implatform.vo; |
package com.bx.implatform.vo; |
||||
|
|
||||
|
import com.bx.imcommon.serializer.DateToLongSerializer; |
||||
import io.swagger.annotations.ApiModel; |
import com.fasterxml.jackson.databind.annotation.JsonSerialize; |
||||
import io.swagger.annotations.ApiModelProperty; |
|
||||
import lombok.Data; |
import lombok.Data; |
||||
import org.hibernate.validator.constraints.Length; |
|
||||
|
|
||||
import javax.validation.constraints.NotEmpty; |
import java.util.Date; |
||||
import javax.validation.constraints.NotNull; |
|
||||
|
|
||||
@Data |
@Data |
||||
@ApiModel("私聊消息VO") |
|
||||
public class PrivateMessageVO { |
public class PrivateMessageVO { |
||||
|
|
||||
|
/* |
||||
|
* 消息id |
||||
|
*/ |
||||
|
private long id; |
||||
|
|
||||
@NotNull(message="接收用户id不可为空") |
/* |
||||
@ApiModelProperty(value = "接收用户id") |
* 发送者id |
||||
private Long recvId; |
*/ |
||||
|
private Long sendId; |
||||
|
|
||||
|
/* |
||||
|
* 接收者id |
||||
|
*/ |
||||
|
private Long recvId; |
||||
|
|
||||
@Length(max=1024,message = "内容长度不得大于1024") |
/* |
||||
@NotEmpty(message="发送内容不可为空") |
* 发送内容 |
||||
@ApiModelProperty(value = "发送内容") |
*/ |
||||
private String content; |
private String content; |
||||
|
|
||||
@NotNull(message="消息类型不可为空") |
/* |
||||
@ApiModelProperty(value = "消息类型") |
* 消息内容类型 IMCmdType |
||||
|
*/ |
||||
private Integer type; |
private Integer type; |
||||
|
|
||||
|
/** |
||||
|
* 发送时间 |
||||
|
*/ |
||||
|
@JsonSerialize(using = DateToLongSerializer.class) |
||||
|
private Date sendTime; |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,12 @@ |
|||||
|
package com.bx.imserver.constant; |
||||
|
|
||||
|
public class ChannelAttrKey { |
||||
|
|
||||
|
// 用户ID
|
||||
|
public static final String USER_ID = "USER_ID"; |
||||
|
// 终端类型
|
||||
|
public static final String TERMINAL_TYPE = "TERMINAL_TYPE"; |
||||
|
// 心跳次数
|
||||
|
public static final String HEARTBEAT_TIMES = "HEARTBEAt_TIMES"; |
||||
|
|
||||
|
} |
||||
@ -1,45 +1,35 @@ |
|||||
package com.bx.imserver.task; |
package com.bx.imserver.task; |
||||
|
|
||||
import com.bx.imcommon.contant.RedisKey; |
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.bx.imcommon.contant.IMRedisKey; |
||||
import com.bx.imcommon.enums.IMCmdType; |
import com.bx.imcommon.enums.IMCmdType; |
||||
import com.bx.imcommon.model.GroupMessageInfo; |
|
||||
import com.bx.imcommon.model.IMRecvInfo; |
import com.bx.imcommon.model.IMRecvInfo; |
||||
import com.bx.imserver.netty.IMServerGroup; |
import com.bx.imserver.netty.IMServerGroup; |
||||
import com.bx.imserver.netty.processor.MessageProcessor; |
import com.bx.imserver.netty.processor.AbstractMessageProcessor; |
||||
import com.bx.imserver.netty.processor.ProcessorFactory; |
import com.bx.imserver.netty.processor.ProcessorFactory; |
||||
import com.bx.imserver.netty.ws.WebSocketServer; |
|
||||
import lombok.extern.slf4j.Slf4j; |
import lombok.extern.slf4j.Slf4j; |
||||
import org.springframework.beans.factory.annotation.Autowired; |
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.data.redis.core.RedisTemplate; |
import org.springframework.data.redis.core.RedisTemplate; |
||||
import org.springframework.stereotype.Component; |
import org.springframework.stereotype.Component; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
import java.util.List; |
|
||||
|
|
||||
@Slf4j |
@Slf4j |
||||
@Component |
@Component |
||||
public class PullUnreadGroupMessageTask extends AbstractPullMessageTask { |
public class PullUnreadGroupMessageTask extends AbstractPullMessageTask { |
||||
|
|
||||
@Autowired |
|
||||
private WebSocketServer WSServer; |
|
||||
|
|
||||
@Autowired |
@Autowired |
||||
private RedisTemplate<String,Object> redisTemplate; |
private RedisTemplate<String,Object> redisTemplate; |
||||
|
|
||||
|
|
||||
|
|
||||
@Override |
@Override |
||||
public void pullMessage() { |
public void pullMessage() { |
||||
// 从redis拉取未读消息
|
// 从redis拉取未读消息
|
||||
String key = RedisKey.IM_UNREAD_GROUP_QUEUE + IMServerGroup.serverId; |
String key = String.join(":", IMRedisKey.IM_UNREAD_GROUP_QUEUE,IMServerGroup.serverId+""); |
||||
List messageInfos = redisTemplate.opsForList().range(key,0,-1); |
JSONObject jsonObject = (JSONObject)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); |
||||
for(Object o: messageInfos){ |
if(jsonObject != null){ |
||||
redisTemplate.opsForList().leftPop(key); |
IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class); |
||||
IMRecvInfo<GroupMessageInfo> recvInfo = (IMRecvInfo)o; |
AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE); |
||||
MessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE); |
|
||||
processor.process(recvInfo); |
processor.process(recvInfo); |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
|
||||
|
|
||||
} |
} |
||||
|
|||||
|
Before Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 62 KiB |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue