mirror of
https://gitee.com/xchao/j-im.git
synced 2024-11-29 18:37:36 +08:00
增加jim-client及demo项目
This commit is contained in:
parent
cc13b48ac2
commit
6c329ec736
6
jim-client-demo/.gitignore
vendored
Normal file
6
jim-client-demo/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.settings/
|
||||
/target/
|
||||
.idea/
|
||||
*.iml
|
||||
*.classpath
|
||||
*.project
|
31
jim-client-demo/pom.xml
Normal file
31
jim-client-demo/pom.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jim-client-demo</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>jim-client-demo</name>
|
||||
<parent>
|
||||
<groupId>org.j-im</groupId>
|
||||
<artifactId>jim</artifactId>
|
||||
<version>3.0.0.v20200101-RELEASE</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.j-im</groupId>
|
||||
<artifactId>jim-client</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin-version}</version>
|
||||
<configuration>
|
||||
<source>${jdk.version}</source>
|
||||
<target>${jdk.version}</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,61 @@
|
||||
package org.jim.client;
|
||||
|
||||
import org.jim.client.config.ImClientConfig;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.packets.ChatBody;
|
||||
import org.jim.core.packets.ChatType;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.LoginReqBody;
|
||||
import org.jim.core.tcp.TcpPacket;
|
||||
import org.tio.core.Node;
|
||||
/**
|
||||
*
|
||||
* 版本: [1.0]
|
||||
* 功能说明:
|
||||
* 作者: WChao 创建时间: 2017年8月30日 下午1:05:17
|
||||
*/
|
||||
public class HelloClientStarter{
|
||||
|
||||
public static ImClientChannelContext imClientChannelContext = null;
|
||||
|
||||
/**
|
||||
* 启动程序入口
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
//服务器节点
|
||||
Node serverNode = new Node("localhost", ImConst.SERVER_PORT);
|
||||
//构建客户端配置信息
|
||||
ImClientConfig imClientConfig = ImClientConfig.newBuilder()
|
||||
//客户端业务回调器,不可以为NULL
|
||||
.clientHandler(new HelloImClientHandler())
|
||||
//客户端事件监听器,可以为null,但建议自己实现该接口
|
||||
.clientListener(new HelloImClientListener())
|
||||
//心跳时长不设置,就不发送心跳包
|
||||
//.heartbeatTimeout(5000)
|
||||
//断链后自动连接的,不想自动连接请设为null
|
||||
//.reConnConf(new ReconnConf(5000L))
|
||||
.build();
|
||||
//生成客户端对象;
|
||||
JimClient jimClient = new JimClient(imClientConfig);
|
||||
//连接服务端
|
||||
imClientChannelContext = jimClient.connect(serverNode);
|
||||
//连上后,发条消息玩玩
|
||||
send();
|
||||
}
|
||||
|
||||
private static void send() throws Exception {
|
||||
byte[] loginBody = new LoginReqBody("hello_client","123").toByte();
|
||||
TcpPacket loginPacket = new TcpPacket(Command.COMMAND_LOGIN_REQ,loginBody);
|
||||
//先登录;
|
||||
JimClientAPI.send(imClientChannelContext, loginPacket);
|
||||
ChatBody chatBody = ChatBody.newBuilder()
|
||||
.from("hello_client")
|
||||
.to("admin")
|
||||
.msgType(0)
|
||||
.chatType(ChatType.CHAT_TYPE_PUBLIC.getNumber())
|
||||
.groupId("100")
|
||||
.content("Socket普通客户端消息测试!").build();
|
||||
TcpPacket chatPacket = new TcpPacket(Command.COMMAND_CHAT_REQ,chatBody.toByte());
|
||||
JimClientAPI.send(imClientChannelContext, chatPacket);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package org.jim.client;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.jim.client.handler.ImClientHandler;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImDecodeException;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.tcp.TcpPacket;
|
||||
import org.jim.core.tcp.TcpServerDecoder;
|
||||
import org.jim.core.tcp.TcpServerEncoder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* 版本: [1.0]
|
||||
* 功能说明:
|
||||
* 作者: WChao 创建时间: 2017年8月30日 下午1:10:28
|
||||
*/
|
||||
public class HelloImClientHandler implements ImClientHandler, ImConst
|
||||
{
|
||||
private static Logger logger = LoggerFactory.getLogger(HelloImClientHandler.class);
|
||||
|
||||
/**
|
||||
* 处理消息
|
||||
*/
|
||||
@Override
|
||||
public void handler(ImPacket imPacket, ImChannelContext channelContext){
|
||||
TcpPacket helloPacket = (TcpPacket)imPacket;
|
||||
byte[] body = helloPacket.getBody();
|
||||
if (body != null)
|
||||
{
|
||||
try {
|
||||
String str = new String(body, ImConst.CHARSET);
|
||||
logger.info("demo客户端收到消息:{}", str);
|
||||
}catch (Exception e){
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码:把业务消息包编码为可以发送的ByteBuffer
|
||||
* 总的消息结构:消息头 + 消息体
|
||||
* 消息头结构: 4个字节,存储消息体的长度
|
||||
* 消息体结构: 对象的json串的byte[]
|
||||
*/
|
||||
@Override
|
||||
public ByteBuffer encode(ImPacket imPacket, ImConfig imConfig, ImChannelContext imChannelContext)
|
||||
{
|
||||
TcpPacket tcpPacket = (TcpPacket)imPacket;
|
||||
return TcpServerEncoder.encode(tcpPacket, imConfig, imChannelContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TcpPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ImChannelContext imChannelContext) throws ImDecodeException {
|
||||
TcpPacket tcpPacket = TcpServerDecoder.decode(buffer, imChannelContext);
|
||||
return tcpPacket;
|
||||
}
|
||||
|
||||
private static TcpPacket heartbeatPacket = new TcpPacket(Command.COMMAND_HEARTBEAT_REQ,new byte[]{Protocol.HEARTBEAT_BYTE});
|
||||
|
||||
/**
|
||||
* 此方法如果返回null,框架层面则不会发心跳;如果返回非null,框架层面会定时发本方法返回的消息包
|
||||
*/
|
||||
@Override
|
||||
public TcpPacket heartbeatPacket(ImChannelContext imChannelContext)
|
||||
{
|
||||
return heartbeatPacket;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.jim.client;
|
||||
|
||||
import org.jim.client.listener.ImClientListener;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImPacket;
|
||||
|
||||
/**
|
||||
* @author WChao
|
||||
* @Desc
|
||||
* @date 2020-05-04 07:33
|
||||
*/
|
||||
public class HelloImClientListener implements ImClientListener {
|
||||
@Override
|
||||
public void onAfterConnected(ImChannelContext imChannelContext, boolean isConnected, boolean isReconnect) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterDecoded(ImChannelContext imChannelContext, ImPacket packet, int packetSize) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterReceivedBytes(ImChannelContext imChannelContext, int receivedBytes) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterSent(ImChannelContext imChannelContext, ImPacket packet, boolean isSentSuccess) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterHandled(ImChannelContext imChannelContext, ImPacket packet, long cost) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeClose(ImChannelContext imChannelContext, Throwable throwable, String remark, boolean isRemove) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
}
|
16
jim-client-demo/src/main/resources/logback.properties
Normal file
16
jim-client-demo/src/main/resources/logback.properties
Normal file
@ -0,0 +1,16 @@
|
||||
#http://logback.qos.ch/manual/configuration.html
|
||||
#<include resource="includedConfig.xml"/> resource, file, url (\u88AB\u5305\u542B\u7684\u6587\u4EF6\u9700\u8981\u6EE1\u8DB3\u4E00\u5B9A\u683C\u5F0F)
|
||||
|
||||
context.name=jim-client
|
||||
|
||||
log.dir=logs
|
||||
|
||||
rolling.policy.file.name.pattern=yyyy-MM-dd
|
||||
max.file.size=100MB
|
||||
max.history=50
|
||||
|
||||
conversion.pattern=%d %-5level %logger{30}[%line]: %m%n
|
||||
root.level=info
|
||||
|
||||
|
||||
|
90
jim-client-demo/src/main/resources/logback.xml
Normal file
90
jim-client-demo/src/main/resources/logback.xml
Normal file
@ -0,0 +1,90 @@
|
||||
<configuration scan="true" scanPeriod="10 seconds" debug="true">
|
||||
<property resource="logback.properties" />
|
||||
|
||||
<contextName>${context.name}</contextName> <!-- 本项目的名字 -->
|
||||
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- root file 日志 -->
|
||||
<appender name="root-file-error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/error.%d{${rolling.policy.file.name.pattern}}.%i.log.zip</fileNamePattern>
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="root-file-warn"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/warn.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/warn.%d{${rolling.policy.file.name.pattern}}.%i.log.zip</fileNamePattern>
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>warn</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="root-file-info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/info.%d{${rolling.policy.file.name.pattern}}.%i.log.zip</fileNamePattern>
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="root-file-debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/debug.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/debug.%d{${rolling.policy.file.name.pattern}}.%i.log.zip</fileNamePattern>
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>debug</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<root level="${root.level}">
|
||||
<appender-ref ref="console" />
|
||||
<appender-ref ref="root-file-error"/>
|
||||
<appender-ref ref="root-file-warn"/>
|
||||
<appender-ref ref="root-file-info"/>
|
||||
<appender-ref ref="root-file-debug"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
@ -23,17 +23,17 @@ public class SslDemoStarter {
|
||||
|
||||
NioSslClient client = new NioSslClient("TLSv1.2", "localhost", 9222,"./src/main/resources/keystore.jks","214323428310224");
|
||||
client.connect();
|
||||
byte[] loginBody = new LoginReqBody("hello_client","123").toByte();
|
||||
byte[] loginBody = new LoginReqBody("ssl_hello_client","123").toByte();
|
||||
TcpPacket loginPacket = new TcpPacket(Command.COMMAND_LOGIN_REQ,loginBody);
|
||||
ByteBuffer loginByteBuffer = TcpServerEncoder.encode(loginPacket, null, null);
|
||||
client.write(loginByteBuffer.array());
|
||||
ChatBody chatBody = ChatBody.newBuilder()
|
||||
.setFrom("hello_client")
|
||||
.setTo("admin")
|
||||
.setMsgType(0)
|
||||
.setChatType(1)
|
||||
.setGroup_id("100")
|
||||
.setContent("Socket普通客户端消息测试!").build();
|
||||
.from("ssl_hello_client")
|
||||
.to("admin")
|
||||
.msgType(0)
|
||||
.chatType(1)
|
||||
.groupId("100")
|
||||
.content("SSL-Socket普通客户端消息测试!").build();
|
||||
TcpPacket chatPacket = new TcpPacket(Command.COMMAND_CHAT_REQ,chatBody.toByte());
|
||||
ByteBuffer chatByteBuffer = TcpServerEncoder.encode(chatPacket,null, null);
|
||||
client.write(chatByteBuffer.array());
|
@ -11,7 +11,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.j-im</groupId>
|
||||
<artifactId>jim-common</artifactId>
|
||||
<artifactId>jim-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
@ -19,7 +19,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<version>${maven-compiler-plugin-version}</version>
|
||||
<configuration>
|
||||
<source>${jdk.version}</source>
|
||||
<target>${jdk.version}</target>
|
||||
|
@ -1,69 +0,0 @@
|
||||
package org.jim.client;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.jim.core.ImConst;
|
||||
import org.tio.client.intf.ClientAioHandler;
|
||||
import org.tio.core.ChannelContext;
|
||||
import org.tio.core.GroupContext;
|
||||
import org.tio.core.exception.ImDecodeException;
|
||||
import org.tio.core.intf.AioHandler;
|
||||
import org.tio.core.intf.Packet;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.tcp.TcpPacket;
|
||||
import org.jim.core.tcp.TcpServerDecoder;
|
||||
import org.jim.core.tcp.TcpServerEncoder;
|
||||
/**
|
||||
*
|
||||
* 版本: [1.0]
|
||||
* 功能说明:
|
||||
* 作者: WChao 创建时间: 2017年8月30日 下午1:10:28
|
||||
*/
|
||||
public class HelloClientAioHandler implements AioHandler,ClientAioHandler
|
||||
{
|
||||
/**
|
||||
* 处理消息
|
||||
*/
|
||||
@Override
|
||||
public void handler(Packet packet, ChannelContext channelContext) throws Exception
|
||||
{
|
||||
TcpPacket helloPacket = (TcpPacket)packet;
|
||||
byte[] body = helloPacket.getBody();
|
||||
if (body != null)
|
||||
{
|
||||
String str = new String(body, ImConst.CHARSET);
|
||||
System.out.println("收到消息:" + str);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* 编码:把业务消息包编码为可以发送的ByteBuffer
|
||||
* 总的消息结构:消息头 + 消息体
|
||||
* 消息头结构: 4个字节,存储消息体的长度
|
||||
* 消息体结构: 对象的json串的byte[]
|
||||
*/
|
||||
@Override
|
||||
public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext)
|
||||
{
|
||||
TcpPacket tcpPacket = (TcpPacket)packet;
|
||||
return TcpServerEncoder.encode(tcpPacket, groupContext, channelContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TcpPacket decode(ByteBuffer buffer,int limit, int position, int readableLength,ChannelContext channelContext) throws ImDecodeException {
|
||||
TcpPacket tcpPacket = TcpServerDecoder.decode(buffer, channelContext);
|
||||
return tcpPacket;
|
||||
}
|
||||
|
||||
private static TcpPacket heartbeatPacket = new TcpPacket(Command.COMMAND_HEARTBEAT_REQ,new byte[]{Protocol.HEARTBEAT_BYTE});
|
||||
|
||||
/**
|
||||
* 此方法如果返回null,框架层面则不会发心跳;如果返回非null,框架层面会定时发本方法返回的消息包
|
||||
*/
|
||||
@Override
|
||||
public TcpPacket heartbeatPacket()
|
||||
{
|
||||
return heartbeatPacket;
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package org.jim.client;
|
||||
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.packets.ChatBody;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.LoginReqBody;
|
||||
import org.jim.core.tcp.TcpPacket;
|
||||
import org.tio.client.AioClient;
|
||||
import org.tio.client.ClientChannelContext;
|
||||
import org.tio.client.ClientGroupContext;
|
||||
import org.tio.client.ReconnConf;
|
||||
import org.tio.client.intf.ClientAioHandler;
|
||||
import org.tio.client.intf.ClientAioListener;
|
||||
import org.tio.core.Node;
|
||||
/**
|
||||
*
|
||||
* 版本: [1.0]
|
||||
* 功能说明:
|
||||
* 作者: WChao 创建时间: 2017年8月30日 下午1:05:17
|
||||
*/
|
||||
public class HelloClientStarter {
|
||||
/**
|
||||
* 服务器节点
|
||||
*/
|
||||
public static Node serverNode = new Node("localhost", ImConst.SERVER_PORT);
|
||||
/**
|
||||
* handler, 包括编码、解码、消息处理
|
||||
*/
|
||||
public static ClientAioHandler aioClientHandler = new HelloClientAioHandler();
|
||||
|
||||
/**
|
||||
* 事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口
|
||||
*/
|
||||
public static ClientAioListener aioListener = null;
|
||||
|
||||
/**
|
||||
* 断链后自动连接的,不想自动连接请设为null
|
||||
*/
|
||||
private static ReconnConf reconnConf = new ReconnConf(5000L);
|
||||
|
||||
/**
|
||||
* 一组连接共用的上下文对象
|
||||
*/
|
||||
public static ClientGroupContext clientGroupContext = new ClientGroupContext(aioClientHandler, aioListener, reconnConf);
|
||||
|
||||
public static AioClient aioClient = null;
|
||||
public static ClientChannelContext clientChannelContext = null;
|
||||
|
||||
/**
|
||||
* 启动程序入口
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
//clientGroupContext.setHeartbeatTimeout(org.tio.examples.helloworld.common.Const.TIMEOUT);
|
||||
clientGroupContext.setHeartbeatTimeout(0);
|
||||
aioClient = new AioClient(clientGroupContext);
|
||||
clientChannelContext = aioClient.connect(serverNode);
|
||||
//连上后,发条消息玩玩
|
||||
send();
|
||||
}
|
||||
|
||||
private static void send() throws Exception {
|
||||
byte[] loginBody = new LoginReqBody("hello_client","123").toByte();
|
||||
TcpPacket loginPacket = new TcpPacket(Command.COMMAND_LOGIN_REQ,loginBody);
|
||||
//先登录;
|
||||
Jim.send(clientChannelContext, loginPacket);
|
||||
ChatBody chatBody = ChatBody.newBuilder()
|
||||
.setFrom("hello_client")
|
||||
.setTo("admin")
|
||||
.setMsgType(0)
|
||||
.setChatType(1)
|
||||
.setGroup_id("100")
|
||||
.setContent("Socket普通客户端消息测试!").build();
|
||||
TcpPacket chatPacket = new TcpPacket(Command.COMMAND_CHAT_REQ,chatBody.toByte());
|
||||
Jim.send(clientChannelContext, chatPacket);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.jim.client;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.tio.core.ChannelContext;
|
||||
|
||||
/**
|
||||
* @ClassName ImClientChannelContext
|
||||
* @Description 客户端通道上下文
|
||||
* @Author WChao
|
||||
* @Date 2020/1/5 23:56
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class ImClientChannelContext extends ImChannelContext {
|
||||
|
||||
public ImClientChannelContext(ImConfig imConfig, ChannelContext tioChannelContext) {
|
||||
super(imConfig, tioChannelContext);
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package org.jim.client;
|
||||
|
||||
import org.jim.core.ImHandler;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.listener.ImListener;
|
||||
|
||||
/**
|
||||
* @ClassName ImClientConfig
|
||||
* @Description TODO
|
||||
* @Author WChao
|
||||
* @Date 2020/1/4 10:42
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class ImClientConfig extends ImConfig {
|
||||
|
||||
@Override
|
||||
public ImHandler getImHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImListener getImListener() {
|
||||
return null;
|
||||
}
|
||||
}
|
51
jim-client/src/main/java/org/jim/client/JimClient.java
Normal file
51
jim-client/src/main/java/org/jim/client/JimClient.java
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.jim.client;
|
||||
|
||||
import org.jim.client.config.ImClientConfig;
|
||||
import org.jim.core.ImConst;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tio.client.ClientChannelContext;
|
||||
import org.tio.client.ClientTioConfig;
|
||||
import org.tio.client.TioClient;
|
||||
import org.tio.core.Node;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* J-IM客户端连接类
|
||||
* @author WChao
|
||||
*
|
||||
*/
|
||||
public class JimClient {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(JimClient.class);
|
||||
|
||||
private TioClient tioClient = null;
|
||||
private ImClientConfig imClientConfig;
|
||||
|
||||
public JimClient(ImClientConfig imClientConfig){
|
||||
this.imClientConfig = imClientConfig;
|
||||
}
|
||||
|
||||
public ImClientChannelContext connect(Node serverNode) throws Exception {
|
||||
return connect(serverNode, null);
|
||||
}
|
||||
|
||||
public ImClientChannelContext connect(Node serverNode, Integer timeout) throws Exception {
|
||||
log.warn("J-IM client connect");
|
||||
tioClient = new TioClient((ClientTioConfig) imClientConfig.getTioConfig());
|
||||
ClientChannelContext clientChannelContext = tioClient.connect(serverNode, imClientConfig.getBindIp(), imClientConfig.getBindPort(), timeout);
|
||||
if(Objects.nonNull(clientChannelContext)){
|
||||
log.warn("J-IM client connected success at serverAddress:[{}], bind localAddress:[{}]", serverNode.toString(), imClientConfig.toBindAddressString());
|
||||
return (ImClientChannelContext)clientChannelContext.get(ImConst.Key.IM_CHANNEL_CONTEXT_KEY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
tioClient.stop();
|
||||
}
|
||||
|
||||
}
|
63
jim-client/src/main/java/org/jim/client/JimClientAPI.java
Normal file
63
jim-client/src/main/java/org/jim/client/JimClientAPI.java
Normal file
@ -0,0 +1,63 @@
|
||||
package org.jim.client;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tio.core.Tio;
|
||||
/**
|
||||
* 版本: [1.0]
|
||||
* 功能说明: JIM
|
||||
* @author : WChao 创建时间: 2017年9月22日 上午9:07:18
|
||||
*/
|
||||
public class JimClientAPI implements ImConst{
|
||||
|
||||
public static ImConfig imConfig = ImConfig.Global.get();
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(JimClientAPI.class);
|
||||
|
||||
/**
|
||||
* 功能描述:发送到群组
|
||||
* @param groupId 群组ID
|
||||
* @param packet 消息包
|
||||
*/
|
||||
public static void sendToGroup(String groupId, ImPacket packet){
|
||||
Tio.sendToGroup(imConfig.getTioConfig(), groupId, packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送到指定通道;
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param imPacket 消息包
|
||||
*/
|
||||
public static boolean send(ImChannelContext imChannelContext, ImPacket imPacket){
|
||||
if(imChannelContext == null){
|
||||
return false;
|
||||
}
|
||||
return Tio.send(imChannelContext.getTioChannelContext(),imPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阻塞发送(确认把packet发送到对端后再返回)
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param packet 消息包
|
||||
* @return
|
||||
*/
|
||||
public static boolean bSend(ImChannelContext imChannelContext , ImPacket packet){
|
||||
if(imChannelContext == null){
|
||||
return false;
|
||||
}
|
||||
return Tio.bSend(imChannelContext.getTioChannelContext(), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
* @param imChannelContext
|
||||
* @param remark
|
||||
*/
|
||||
public static void close(ImChannelContext imChannelContext, String remark){
|
||||
Tio.close(imChannelContext.getTioChannelContext(), remark);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package org.jim.client.config;
|
||||
|
||||
import org.jim.client.handler.DefaultImClientHandler;
|
||||
import org.jim.client.handler.ImClientHandler;
|
||||
import org.jim.client.handler.ImClientHandlerAdapter;
|
||||
import org.jim.client.listener.DefaultImClientListener;
|
||||
import org.jim.client.listener.ImClientListener;
|
||||
import org.jim.client.listener.ImClientListenerAdapter;
|
||||
import org.jim.core.ImHandler;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.listener.ImListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tio.client.ClientTioConfig;
|
||||
import org.tio.client.ReconnConf;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @ClassName ImServerConfig
|
||||
* @Description Im客户端配置
|
||||
* @Author WChao
|
||||
* @Date 2020/1/4 10:40
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class ImClientConfig extends ImConfig {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(ImClientConfig.class);
|
||||
/**
|
||||
* 客户端消息处理器
|
||||
*/
|
||||
private ImClientHandler imClientHandler;
|
||||
/**
|
||||
* 客户端消息监听器
|
||||
*/
|
||||
private ImClientListener imClientListener;
|
||||
/**
|
||||
* 重连配置
|
||||
*/
|
||||
protected ReconnConf reconnConf;
|
||||
|
||||
|
||||
private ImClientConfig(ImClientHandler imClientHandler, ImClientListener imClientListener){
|
||||
setImClientHandler(imClientHandler);
|
||||
setImClientListener(imClientListener);
|
||||
this.tioConfig = new ClientTioConfig(new ImClientHandlerAdapter(this.imClientHandler), new ImClientListenerAdapter(this.imClientListener), reconnConf);
|
||||
Global.set(this);
|
||||
}
|
||||
|
||||
public static Builder newBuilder(){
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImHandler getImHandler() {
|
||||
return getImClientHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImListener getImListener() {
|
||||
return getImClientListener();
|
||||
}
|
||||
|
||||
public static class Builder extends ImConfig.Builder<ImClientConfig, Builder>{
|
||||
|
||||
private ImClientListener imClientListener;
|
||||
|
||||
private ImClientHandler imClientHandler;
|
||||
|
||||
protected ReconnConf reconnConf;
|
||||
|
||||
@Override
|
||||
protected Builder getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder clientListener(ImClientListener imClientListener){
|
||||
this.imClientListener = imClientListener;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public Builder clientHandler(ImClientHandler imClientHandler){
|
||||
this.imClientHandler = imClientHandler;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public Builder reConnConf(ReconnConf reconnConf){
|
||||
this.reconnConf = reconnConf;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImClientConfig build(){
|
||||
ImClientConfig imClientConfig = new ImClientConfig(this.imClientHandler, this.imClientListener);
|
||||
imClientConfig.setBindIp(this.bindIp);
|
||||
imClientConfig.setBindPort(this.bindPort);
|
||||
imClientConfig.setReadBufferSize(this.readBufferSize);
|
||||
imClientConfig.setSslConfig(this.sslConfig);
|
||||
imClientConfig.setReConnConf(this.reconnConf);
|
||||
imClientConfig.setHeartbeatTimeout(this.heartbeatTimeout);
|
||||
imClientConfig.setImGroupListener(this.imGroupListener);
|
||||
imClientConfig.setImUserListener(this.imUserListener);
|
||||
return imClientConfig;
|
||||
}
|
||||
}
|
||||
|
||||
public ImClientHandler getImClientHandler() {
|
||||
return imClientHandler;
|
||||
}
|
||||
|
||||
public void setImClientHandler(ImClientHandler imClientHandler) {
|
||||
this.imClientHandler = imClientHandler;
|
||||
if(Objects.isNull(this.imClientHandler)){
|
||||
this.imClientHandler = new DefaultImClientHandler();
|
||||
}
|
||||
}
|
||||
|
||||
public ImClientListener getImClientListener() {
|
||||
return imClientListener;
|
||||
}
|
||||
|
||||
public void setImClientListener(ImClientListener imClientListener) {
|
||||
this.imClientListener = imClientListener;
|
||||
if(Objects.isNull(this.imClientListener)){
|
||||
this.imClientListener = new DefaultImClientListener();
|
||||
}
|
||||
}
|
||||
|
||||
public ReconnConf getReConnConf() {
|
||||
return reconnConf;
|
||||
}
|
||||
|
||||
public void setReConnConf(ReconnConf reconnConf) {
|
||||
this.reconnConf = reconnConf;
|
||||
ClientTioConfig clientTioConfig = (ClientTioConfig)this.tioConfig;
|
||||
clientTioConfig.setReconnConf(reconnConf);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.jim.client.handler;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImDecodeException;
|
||||
import org.jim.core.exception.ImException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @ClassName DefaultImClientHandler
|
||||
* @Description 默认的IM客户端回调
|
||||
* @Author WChao
|
||||
* @Date 2020/1/6 2:25
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class DefaultImClientHandler implements ImClientHandler {
|
||||
|
||||
@Override
|
||||
public void handler(ImPacket imPacket, ImChannelContext imChannelContext) throws ImException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer encode(ImPacket imPacket, ImConfig imConfig, ImChannelContext imChannelContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ImChannelContext imChannelContext) throws ImDecodeException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket heartbeatPacket(ImChannelContext imChannelContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.jim.client.handler;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImHandler;
|
||||
import org.jim.core.ImPacket;
|
||||
|
||||
/**
|
||||
*
|
||||
* 客户端回调
|
||||
* @author WChao
|
||||
*
|
||||
*/
|
||||
public interface ImClientHandler extends ImHandler {
|
||||
/**
|
||||
* 心跳包接口
|
||||
* @param imChannelContext
|
||||
* @return
|
||||
*/
|
||||
ImPacket heartbeatPacket(ImChannelContext imChannelContext);
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.jim.client.handler;
|
||||
|
||||
import org.jim.client.ImClientChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImDecodeException;
|
||||
import org.tio.client.intf.ClientAioHandler;
|
||||
import org.tio.core.ChannelContext;
|
||||
import org.tio.core.TioConfig;
|
||||
import org.tio.core.exception.AioDecodeException;
|
||||
import org.tio.core.intf.Packet;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @ClassName ImClientHandlerAdapter
|
||||
* @Description IM客户端回调适配器
|
||||
* @Author WChao
|
||||
* @Date 2020/1/6 2:30
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class ImClientHandlerAdapter implements ClientAioHandler, ImConst{
|
||||
|
||||
private ImClientHandler imClientHandler;
|
||||
|
||||
public ImClientHandlerAdapter(ImClientHandler imClientHandler){
|
||||
this.imClientHandler = imClientHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException {
|
||||
ImPacket imPacket;
|
||||
try {
|
||||
imPacket = this.imClientHandler.decode(buffer, limit, position, readableLength, (ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY));
|
||||
}catch (ImDecodeException e) {
|
||||
throw new AioDecodeException(e);
|
||||
}
|
||||
return imPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {
|
||||
return this.imClientHandler.encode((ImPacket)packet, ImConfig.Global.get(), (ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handler(Packet packet, ChannelContext channelContext) throws Exception {
|
||||
this.imClientHandler.handler((ImPacket)packet, (ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet heartbeatPacket(ChannelContext channelContext) {
|
||||
return this.imClientHandler.heartbeatPacket((ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package org.jim.client.listener;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImPacket;
|
||||
|
||||
/**
|
||||
* @ClassName DefaultImClientListener
|
||||
* @Description 默认IM客户端连接监听器
|
||||
* @Author WChao
|
||||
* @Date 2020/1/4 11:15
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class DefaultImClientListener implements ImClientListener {
|
||||
|
||||
|
||||
@Override
|
||||
public void onAfterConnected(ImChannelContext channelContext, boolean isConnected, boolean isReconnect) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterDecoded(ImChannelContext channelContext, ImPacket packet, int packetSize) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterReceivedBytes(ImChannelContext channelContext, int receivedBytes) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterSent(ImChannelContext channelContext, ImPacket packet, boolean isSentSuccess) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterHandled(ImChannelContext channelContext, ImPacket packet, long cost) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeClose(ImChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) throws Exception {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.jim.client.listener;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.listener.ImListener;
|
||||
|
||||
/**
|
||||
* @ClassName ImClientListener
|
||||
* @Description IM客户端连接监听器接口
|
||||
* @Author WChao
|
||||
* @Date 2020/1/4 9:35
|
||||
* @Version 1.0
|
||||
**/
|
||||
public interface ImClientListener extends ImListener {
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package org.jim.client.listener;
|
||||
|
||||
import org.jim.client.ImClientChannelContext;
|
||||
import org.jim.client.config.ImClientConfig;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.tio.client.intf.ClientAioListener;
|
||||
import org.tio.core.ChannelContext;
|
||||
import org.tio.core.intf.Packet;
|
||||
/**
|
||||
* @ClassName ImClientListenerAdapter
|
||||
* @Description IM客户端连接监听适配器
|
||||
* @Author WChao
|
||||
* @Date 2020/1/4 9:35
|
||||
* @Version 1.0
|
||||
**/
|
||||
public class ImClientListenerAdapter implements ClientAioListener, ImConst{
|
||||
/**
|
||||
* 客户端端监听器
|
||||
*/
|
||||
private ImClientListener imClientListener;
|
||||
|
||||
public ImClientListenerAdapter(ImClientListener imClientListener) {
|
||||
this.imClientListener = imClientListener == null ? new DefaultImClientListener(): imClientListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterConnected(ChannelContext channelContext, boolean isConnected, boolean isReconnect)throws Exception{
|
||||
ImClientChannelContext imClientChannelContext = new ImClientChannelContext(ImClientConfig.Global.get(), channelContext);
|
||||
channelContext.set(Key.IM_CHANNEL_CONTEXT_KEY, imClientChannelContext);
|
||||
imClientListener.onAfterConnected(imClientChannelContext, isConnected, isReconnect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess)throws Exception{
|
||||
imClientListener.onAfterSent((ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY), (ImPacket)packet, isSentSuccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove)throws Exception{
|
||||
imClientListener.onBeforeClose((ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY), throwable, remark, isRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterDecoded(ChannelContext channelContext, Packet packet,int packetSize) throws Exception {
|
||||
imClientListener.onAfterDecoded((ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY), (ImPacket)packet, packetSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterReceivedBytes(ChannelContext channelContext,int receivedBytes) throws Exception {
|
||||
imClientListener.onAfterReceivedBytes((ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY), receivedBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterHandled(ChannelContext channelContext, Packet packet,long cost) throws Exception {
|
||||
imClientListener.onAfterHandled((ImClientChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY), (ImPacket)packet, cost);
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#http://logback.qos.ch/manual/configuration.html
|
||||
#<include resource="includedConfig.xml"/> resource, file, url (被包含的文件需要满足一定格式)
|
||||
|
||||
context.name=jim-client
|
||||
|
||||
log.dir=/logs/jim-client
|
||||
|
||||
rolling.policy.file.name.pattern=yyyy-MM-dd HH
|
||||
max.file.size=100MB
|
||||
max.history=50
|
||||
|
||||
conversion.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{30}[%line]: %m%n
|
||||
root.level=debug
|
||||
|
||||
|
||||
|
@ -1,129 +0,0 @@
|
||||
<configuration scan="true" scanPeriod="10 seconds" debug="true">
|
||||
<property resource="logback.properties" />
|
||||
|
||||
<contextName>${context.name}</contextName> <!-- 本项目的名字 -->
|
||||
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- root file 日志 -->
|
||||
<appender name="root-file-error"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/error.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/error.%d{${rolling.policy.file.name.pattern}}%d{mmss}.%i.log.zip</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
<appender name="root-file-warn"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/warn.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/warn.%d{${rolling.policy.file.name.pattern}}%d{mmss}.%i.log.zip</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>warn</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
<appender name="root-file-info"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/info.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/info.%d{${rolling.policy.file.name.pattern}}%d{mmss}.%i.log.zip</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>INFO</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
<appender name="root-file-debug"
|
||||
class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/debug.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/debug.%d{${rolling.policy.file.name.pattern}}%d{mmss}.%i.log.zip</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>${max.file.size}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<maxHistory>${max.history}</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${conversion.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>debug</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
<root level="${root.level}">
|
||||
<appender-ref ref="console" />
|
||||
<appender-ref ref="root-file-error"/>
|
||||
<appender-ref ref="root-file-warn"/>
|
||||
<appender-ref ref="root-file-info"/>
|
||||
<appender-ref ref="root-file-debug"/>
|
||||
</root>
|
||||
|
||||
|
||||
|
||||
<!-- 跟踪客户端行为 -->
|
||||
<appender name="tio-client-trace-log-appender" class="ch.qos.logback.classic.sift.SiftingAppender">
|
||||
<discriminator>
|
||||
<Key>tio_client</Key>
|
||||
<DefaultValue>unknown</DefaultValue>
|
||||
</discriminator>
|
||||
|
||||
<sift>
|
||||
<appender name="${tio_client}" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/tio/client-trace/${tio_client}_%d{yyyyMMdd}.log</fileNamePattern>
|
||||
<maxFileSize>20MB</maxFileSize>
|
||||
</rollingPolicy>
|
||||
<Append>false</Append>
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>%m%n</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
</sift>
|
||||
</appender>
|
||||
|
||||
<logger name="tio-client-trace-log" additivity="false">
|
||||
<level value="info"/>
|
||||
<appender-ref ref="tio-client-trace-log-appender"/>
|
||||
</logger>
|
||||
|
||||
</configuration>
|
@ -287,10 +287,6 @@ public interface ImConst
|
||||
|
||||
String FRIENDS = "friends";
|
||||
|
||||
String ONLINE = "online";
|
||||
|
||||
String OFFLINE = "offline";
|
||||
|
||||
String JIM = "J-IM";
|
||||
|
||||
}
|
||||
|
@ -24,13 +24,13 @@ public interface ImHandler {
|
||||
* @return
|
||||
* @throws ImDecodeException
|
||||
*/
|
||||
ImPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ImChannelContext imChannelContext) throws ImDecodeException;
|
||||
ImPacket decode(ByteBuffer buffer, int limit, int position, int readableLength, ImChannelContext imChannelContext) throws ImDecodeException, ImDecodeException;
|
||||
|
||||
/**
|
||||
* 编码
|
||||
* @param imPacket
|
||||
* @param imConfig
|
||||
* @param imChannelContext
|
||||
* 将业务包编码为网络byte字节传输
|
||||
* @param imPacket 业务消息包
|
||||
* @param imConfig IM配置
|
||||
* @param imChannelContext 通道上下文
|
||||
* @return
|
||||
* @author: WChao
|
||||
*/
|
||||
@ -38,8 +38,8 @@ public interface ImHandler {
|
||||
|
||||
/**
|
||||
* 处理消息包
|
||||
* @param imPacket
|
||||
* @param imChannelContext
|
||||
* @param imPacket 业务消息包
|
||||
* @param imChannelContext 通道上下文
|
||||
* @throws ImException
|
||||
* @author: WChao
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.JimVersion;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
/**
|
||||
@ -87,7 +87,7 @@ public class RedisConfigurationFactory {
|
||||
url = standardClassloader.getResource(DEFAULT_CLASSPATH_CONFIGURATION_FILE);
|
||||
}
|
||||
if (url == null) {
|
||||
url = Jim.class.getResource(DEFAULT_CLASSPATH_CONFIGURATION_FILE);
|
||||
url = JimVersion.class.getResource(DEFAULT_CLASSPATH_CONFIGURATION_FILE);
|
||||
}
|
||||
if (url != null) {
|
||||
LOG.debug("Configuring redis from jim.properties found in the classpath: " + url);
|
||||
|
@ -9,12 +9,12 @@ package org.jim.core.cluster;
|
||||
* @author WChao
|
||||
* @date 2020-04-29
|
||||
*/
|
||||
public abstract class ImCluster implements ICluster{
|
||||
public abstract class ImCluster implements ICluster {
|
||||
/**
|
||||
* IM集群配置
|
||||
*/
|
||||
protected ImClusterConfig clusterConfig;
|
||||
|
||||
|
||||
public ImCluster(ImClusterConfig clusterConfig){
|
||||
this.clusterConfig = clusterConfig;
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package org.jim.core.cluster;
|
||||
|
||||
import org.jim.core.ImPacket;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jim.core.ImPacket;
|
||||
/**
|
||||
* 成员变量group, userId, ip谁有值就发给谁,toAll为true则发给所有<br>
|
||||
* packet是不允许为null的
|
||||
|
@ -12,6 +12,7 @@ import org.jim.core.listener.ImGroupListenerAdapter;
|
||||
import org.jim.core.listener.ImListener;
|
||||
import org.jim.core.listener.ImUserListener;
|
||||
import org.tio.core.TioConfig;
|
||||
import org.tio.core.ssl.SslConfig;
|
||||
import org.tio.utils.Threads;
|
||||
import org.tio.utils.prop.MapWithLockPropSupport;
|
||||
import org.tio.utils.thread.pool.DefaultThreadFactory;
|
||||
@ -28,11 +29,11 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
/**
|
||||
* IP地址
|
||||
*/
|
||||
protected String bindIp;
|
||||
protected String bindIp = "0.0.0.0";
|
||||
/**
|
||||
* 监听端口
|
||||
*/
|
||||
protected Integer bindPort = 80;
|
||||
protected Integer bindPort = 0;
|
||||
|
||||
/**
|
||||
* 默认的接收数据的buffer size
|
||||
@ -41,7 +42,7 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
/**
|
||||
* 配置名称
|
||||
*/
|
||||
protected String name = "j-im";
|
||||
protected String name = "J-IM";
|
||||
/**
|
||||
* 集群配置
|
||||
* 如果此值不为null,就表示要集群
|
||||
@ -51,12 +52,17 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
* tio相关配置信息
|
||||
*/
|
||||
protected TioConfig tioConfig;
|
||||
|
||||
/**
|
||||
* SSL配置
|
||||
*/
|
||||
protected SslConfig sslConfig;
|
||||
/**
|
||||
* 心跳包发送时长heartbeatTimeout/2
|
||||
*/
|
||||
protected long heartbeatTimeout = 0;
|
||||
|
||||
/**
|
||||
* J-IM内部线程池
|
||||
*/
|
||||
protected SynThreadPoolExecutor jimExecutor;
|
||||
/**
|
||||
* 群组绑定监听器
|
||||
@ -116,15 +122,15 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
/**
|
||||
* IP地址
|
||||
*/
|
||||
protected String bindIp;
|
||||
protected String bindIp = "0.0.0.0";
|
||||
/**
|
||||
* 监听端口
|
||||
*/
|
||||
protected Integer bindPort = 80;
|
||||
protected Integer bindPort = 0;
|
||||
/**
|
||||
* 配置名称
|
||||
*/
|
||||
protected String name = "j-im";
|
||||
protected String name = "J-IM";
|
||||
|
||||
/**
|
||||
* 默认的接收数据的buffer size
|
||||
@ -141,10 +147,9 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
*/
|
||||
protected ImCluster cluster;
|
||||
/**
|
||||
* tio相关配置信息
|
||||
* SSL配置
|
||||
*/
|
||||
protected TioConfig tioConfig;
|
||||
|
||||
protected SslConfig sslConfig;
|
||||
/**
|
||||
* 群组绑定监听器
|
||||
*/
|
||||
@ -191,8 +196,8 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
this.cluster = cluster;
|
||||
return theBuilder;
|
||||
}
|
||||
public B tioConfig(TioConfig tioConfig){
|
||||
this.tioConfig = tioConfig;
|
||||
public B sslConfig(SslConfig sslConfig){
|
||||
this.sslConfig = sslConfig;
|
||||
return theBuilder;
|
||||
}
|
||||
public B groupListener(ImGroupListener imGroupListener){
|
||||
@ -291,6 +296,21 @@ public abstract class ImConfig extends MapWithLockPropSupport implements ImConst
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
public SslConfig getSslConfig() {
|
||||
return sslConfig;
|
||||
}
|
||||
|
||||
public void setSslConfig(SslConfig sslConfig) {
|
||||
this.sslConfig = sslConfig;
|
||||
this.tioConfig.setSslConfig(sslConfig);
|
||||
}
|
||||
|
||||
public String toBindAddressString(){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(bindIp).append(":").append(bindPort);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
static {
|
||||
JimBanner banner = new JimBanner();
|
||||
banner.printBanner(System.out);
|
||||
|
@ -34,6 +34,17 @@ public class HttpConvertPacket implements IProtocolConverter {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket RespPacket(ImPacket imPacket, Command command, ImChannelContext imChannelContext) {
|
||||
ImSessionContext sessionContext = imChannelContext.getSessionContext();
|
||||
if(sessionContext instanceof HttpSession){
|
||||
HttpResponse response = (HttpResponse)imPacket;
|
||||
response.setCommand(command);
|
||||
return response;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket ReqPacket(byte[] body, Command command, ImChannelContext channelContext) {
|
||||
|
||||
|
@ -70,8 +70,8 @@ public class HttpResponseEncoder implements ImConst {
|
||||
sb.append(Http.ResponseHeaderKey.Set_Cookie).append(": ");
|
||||
sb.append(cookie.toString());
|
||||
sb.append("\r\n");
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("{}, set-cookie:{}", channelContext, cookie.toString());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("{}, set-cookie:{}", channelContext, cookie.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class User extends Message implements Serializable{
|
||||
/**
|
||||
* 在线状态(online、offline)
|
||||
*/
|
||||
private String status = ImConst.OFFLINE;
|
||||
private String status = UserStatusType.OFFLINE.getStatus();
|
||||
/**
|
||||
* 个性签名;
|
||||
*/
|
||||
@ -151,7 +151,7 @@ public class User extends Message implements Serializable{
|
||||
/**
|
||||
* 在线状态(online、offline)
|
||||
*/
|
||||
private String status = ImConst.OFFLINE;
|
||||
private String status = UserStatusType.OFFLINE.getStatus();
|
||||
/**
|
||||
* 个性签名;
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@ public enum UserStatusType {
|
||||
*
|
||||
* <code>ONLINE = 0;</code>
|
||||
*/
|
||||
ONLINE(0),
|
||||
ONLINE(0, "online", "在线"),
|
||||
/**
|
||||
* <pre>
|
||||
*离线
|
||||
@ -16,7 +16,7 @@ public enum UserStatusType {
|
||||
*
|
||||
* <code>OFFLINE = 1;</code>
|
||||
*/
|
||||
OFFLINE(1),
|
||||
OFFLINE(1, "offline", "离线"),
|
||||
/**
|
||||
* <pre>
|
||||
* ALL所有(在线+离线)
|
||||
@ -24,7 +24,7 @@ public enum UserStatusType {
|
||||
*
|
||||
* <code>ALL = 2;</code>
|
||||
*/
|
||||
ALL(2);
|
||||
ALL(2, "all", "所有");
|
||||
|
||||
|
||||
public final int getNumber() {
|
||||
@ -45,7 +45,22 @@ public enum UserStatusType {
|
||||
}
|
||||
private final int value;
|
||||
|
||||
UserStatusType(int value) {
|
||||
private final String status;
|
||||
|
||||
private final String desc;
|
||||
|
||||
UserStatusType(int value, String status, String desc) {
|
||||
this.value = value;
|
||||
this.status = status;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,4 +29,13 @@ public interface IProtocolConverter {
|
||||
* @return
|
||||
*/
|
||||
ImPacket RespPacket(byte[] body,Command command, ImChannelContext imChannelContext);
|
||||
|
||||
/**
|
||||
* 转化响应包
|
||||
* @param imPacket
|
||||
* @param command
|
||||
* @param imChannelContext
|
||||
* @return
|
||||
*/
|
||||
ImPacket RespPacket(ImPacket imPacket, Command command, ImChannelContext imChannelContext);
|
||||
}
|
||||
|
@ -30,6 +30,13 @@ public class TcpConvertPacket implements IProtocolConverter {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket RespPacket(ImPacket imPacket, Command command, ImChannelContext imChannelContext) {
|
||||
|
||||
return this.RespPacket(imPacket.getBody(), command, imChannelContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转TCP协议请求包;
|
||||
*/
|
||||
|
@ -63,7 +63,7 @@ public class TcpServerDecoder implements ImConst {
|
||||
}catch(Exception e){
|
||||
logger.error(e.toString());
|
||||
}
|
||||
logger.info("TCP解码成功...");
|
||||
logger.debug("TCP解码成功...");
|
||||
//byteBuffer的总长度是 = 1byte协议版本号+1byte消息标志位+4byte同步序列号(如果是同步发送则多4byte同步序列号,否则无4byte序列号)+1byte命令码+4byte消息的长度+消息体的长度
|
||||
TcpPacket tcpPacket = new TcpPacket(Command.forNumber(cmdByte), body);
|
||||
tcpPacket.setVersion(version);
|
||||
|
@ -3,17 +3,12 @@
|
||||
*/
|
||||
package org.jim.core.utils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImSessionContext;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.packets.ImClientNode;
|
||||
import org.jim.core.packets.User;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* IM工具类;
|
||||
@ -24,41 +19,6 @@ public class ImKit {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ImKit.class);
|
||||
|
||||
/**
|
||||
* 根据群组获取所有用户;
|
||||
* @param groupId 群组ID
|
||||
* @return 群组用户集合列表
|
||||
*/
|
||||
public static List<User> getUsersByGroup(String groupId){
|
||||
List<ImChannelContext> channelContexts = Jim.getByGroup(groupId);
|
||||
List<User> users = Lists.newArrayList();
|
||||
if(CollectionUtils.isEmpty(channelContexts)){
|
||||
return users;
|
||||
}
|
||||
Map<String,User> userMap = new HashMap<>();
|
||||
channelContexts.forEach(imChannelContext -> {
|
||||
User user = imChannelContext.getSessionContext().getImClientNode().getUser();
|
||||
if(Objects.nonNull(user) && Objects.isNull(userMap.get(user.getUserId()))){
|
||||
userMap.put(user.getUserId(), user);
|
||||
users.add(user);
|
||||
}
|
||||
});
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取用户信息(一个用户ID会有多端通道,默认取第一个)
|
||||
* @param userId 用户ID
|
||||
* @return user信息
|
||||
*/
|
||||
public static User getUser(String userId){
|
||||
List<ImChannelContext> imChannelContexts = Jim.getByUserId(userId);
|
||||
if(CollectionUtils.isEmpty(imChannelContexts)) {
|
||||
return null;
|
||||
}
|
||||
return imChannelContexts.get(0).getSessionContext().getImClientNode().getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Client对象到ImSessionContext中
|
||||
* @param channelContext 通道上下文
|
||||
|
@ -33,6 +33,12 @@ public class WsConvertPacket implements IProtocolConverter {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket RespPacket(ImPacket imPacket, Command command, ImChannelContext imChannelContext) {
|
||||
|
||||
return this.RespPacket(imPacket.getBody(), command, imChannelContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImPacket ReqPacket(byte[] body, Command command, ImChannelContext channelContext) {
|
||||
|
||||
|
@ -4,11 +4,9 @@
|
||||
package org.jim.server.demo;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.utils.PropUtil;
|
||||
import org.jim.server.ImServerStarter;
|
||||
import org.jim.server.JimServer;
|
||||
import org.jim.server.command.CommandManager;
|
||||
import org.jim.server.command.handler.ChatReqHandler;
|
||||
import org.jim.server.command.handler.HandshakeReqHandler;
|
||||
@ -37,7 +35,7 @@ public class ImServerDemoStart {
|
||||
imServerConfig.setImGroupListener(new ImDemoGroupListener());
|
||||
//设置绑定用户监听器,非必须,根据需要自己选择性实现;
|
||||
imServerConfig.setImUserListener(new ImDemoUserListener());
|
||||
ImServerStarter imServerStarter = new ImServerStarter(imServerConfig);
|
||||
JimServer jimServer = new JimServer(imServerConfig);
|
||||
|
||||
/*****************start 以下处理器根据业务需要自行添加与扩展,每个Command都可以添加扩展,此处为demo中处理**********************************/
|
||||
|
||||
@ -51,7 +49,7 @@ public class ImServerDemoStart {
|
||||
ChatReqHandler chatReqHandler = CommandManager.getCommand(Command.COMMAND_CHAT_REQ, ChatReqHandler.class);
|
||||
chatReqHandler.setSingleProcessor(new DefaultAsyncChatMessageProcessor());
|
||||
/*****************end *******************************************************************************************/
|
||||
imServerStarter.start();
|
||||
jimServer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,13 +5,13 @@ package org.jim.server.demo.command;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.core.http.HttpRequest;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.LoginReqBody;
|
||||
import org.jim.core.utils.JsonKit;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.CommandManager;
|
||||
import org.jim.server.command.handler.LoginReqHandler;
|
||||
import org.jim.server.processor.handshake.WsHandshakeProcessor;
|
||||
@ -38,7 +38,7 @@ public class DemoWsHandshakeProcessor extends WsHandshakeProcessor {
|
||||
}
|
||||
ImPacket loginRespPacket = loginHandler.handler(request, imChannelContext);
|
||||
if(loginRespPacket != null){
|
||||
Jim.send(imChannelContext, loginRespPacket);
|
||||
JimServerAPI.send(imChannelContext, loginRespPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,22 @@ package org.jim.server.demo.listener;
|
||||
|
||||
import org.jim.core.*;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.core.listener.ImGroupListener;
|
||||
import org.jim.core.packets.*;
|
||||
import org.jim.core.utils.JsonKit;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.listener.AbstractImGroupListener;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 群组绑定监听器
|
||||
* @author WChao
|
||||
* 2017年5月13日 下午10:38:36
|
||||
*/
|
||||
public class ImDemoGroupListener extends AbstractImGroupListener {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ImGroupListener.class);
|
||||
private static Logger logger = LoggerFactory.getLogger(ImDemoGroupListener.class);
|
||||
|
||||
@Override
|
||||
public void doAfterBind(ImChannelContext imChannelContext, Group group) throws ImException {
|
||||
@ -50,7 +51,7 @@ public class ImDemoGroupListener extends AbstractImGroupListener {
|
||||
|
||||
RespBody respBody = new RespBody(Command.COMMAND_EXIT_GROUP_NOTIFY_RESP,exitGroupNotifyRespBody);
|
||||
ImPacket imPacket = new ImPacket(Command.COMMAND_EXIT_GROUP_NOTIFY_RESP, respBody.toByte());
|
||||
Jim.sendToGroup(group.getGroupId(), ProtocolManager.Converter.respPacket(imPacket, imChannelContext));
|
||||
JimServerAPI.sendToGroup(group.getGroupId(), imPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,12 +62,12 @@ public class ImDemoGroupListener extends AbstractImGroupListener {
|
||||
public void joinGroupNotify(Group group, ImChannelContext imChannelContext)throws ImException{
|
||||
ImSessionContext imSessionContext = imChannelContext.getSessionContext();
|
||||
User clientUser = imSessionContext.getImClientNode().getUser();
|
||||
User notifyUser = User.newBuilder().userId(clientUser.getUserId()).nick(clientUser.getNick()).build();
|
||||
User notifyUser = User.newBuilder().userId(clientUser.getUserId()).nick(clientUser.getNick()).status(UserStatusType.ONLINE.getStatus()).build();
|
||||
String groupId = group.getGroupId();
|
||||
//发进房间通知 COMMAND_JOIN_GROUP_NOTIFY_RESP
|
||||
JoinGroupNotifyRespBody joinGroupNotifyRespBody = JoinGroupNotifyRespBody.success();
|
||||
joinGroupNotifyRespBody.setGroup(groupId).setUser(notifyUser);
|
||||
Jim.sendToGroup(groupId, ProtocolManager.Converter.respPacket(joinGroupNotifyRespBody,imChannelContext));
|
||||
JimServerAPI.sendToGroup(groupId, ProtocolManager.Converter.respPacket(joinGroupNotifyRespBody,imChannelContext));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,10 +5,7 @@ package org.jim.server.demo.service;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import org.jim.core.*;
|
||||
import org.jim.core.packets.Group;
|
||||
import org.jim.core.packets.LoginReqBody;
|
||||
import org.jim.core.packets.LoginRespBody;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.core.packets.*;
|
||||
import org.jim.core.session.id.impl.UUIDSessionIdGenerator;
|
||||
import org.jim.core.utils.Md5;
|
||||
import org.jim.server.processor.login.LoginCmdProcessor;
|
||||
@ -70,7 +67,7 @@ public class LoginServiceProcessor extends AbstractProtocolCmdProcessor implemen
|
||||
.addGroup(Group.newBuilder().groupId("100").name("J-IM朋友圈").build());
|
||||
//模拟的用户好友,正式根据业务去查数据库或者缓存;
|
||||
initFriends(builder);
|
||||
builder.avatar(nextImg()).status(ONLINE);
|
||||
builder.avatar(nextImg()).status(UserStatusType.ONLINE.getStatus());
|
||||
user = builder.build();
|
||||
if (tokenMap.size() > 10000) {
|
||||
tokenMap.clear();
|
||||
|
@ -1,6 +0,0 @@
|
||||
_____ _____ ____ ____
|
||||
|_ _| |_ _||_ \ / _|
|
||||
| | ______ | | | \/ |
|
||||
_ | ||______|| | | |\ /| |
|
||||
| |__' | _| |_ _| |_\/_| |_
|
||||
`.____.' |_____||_____||_____|
|
@ -6,9 +6,8 @@ package org.jim.server;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.cache.redis.RedissonTemplate;
|
||||
import org.jim.core.cluster.redis.RedisCluster;
|
||||
import org.jim.core.cluster.redis.RedisClusterConfig;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.server.cluster.redis.RedisCluster;
|
||||
import org.jim.server.cluster.redis.RedisClusterConfig;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
import org.jim.server.helper.redis.RedisMessageHelper;
|
||||
@ -24,13 +23,13 @@ import java.util.concurrent.TimeUnit;
|
||||
* @author WChao
|
||||
*
|
||||
*/
|
||||
public class ImServerStarter {
|
||||
public class JimServer {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(ImServerStarter.class);
|
||||
private static Logger log = LoggerFactory.getLogger(JimServer.class);
|
||||
private TioServer tioServer = null;
|
||||
private ImServerConfig imServerConfig;
|
||||
|
||||
public ImServerStarter(ImServerConfig imServerConfig){
|
||||
public JimServer(ImServerConfig imServerConfig){
|
||||
this.imServerConfig = imServerConfig;
|
||||
}
|
||||
|
||||
@ -55,10 +54,10 @@ public class ImServerStarter {
|
||||
|
||||
public void start() throws IOException {
|
||||
Stopwatch timeWatch = Stopwatch.createStarted();
|
||||
log.warn("J-IM server start");
|
||||
log.warn("J-IM Server start");
|
||||
init(imServerConfig);
|
||||
tioServer.start(this.imServerConfig.getBindIp(), this.imServerConfig.getBindPort());
|
||||
log.warn("J-IM server started at address: {} time:{}ms", imServerConfig.getBindIp()+":"+imServerConfig.getBindPort(), timeWatch.elapsed(TimeUnit.MILLISECONDS));
|
||||
log.warn("J-IM Server started at address: {} time:{}ms", imServerConfig.getBindIp()+":"+imServerConfig.getBindPort(), timeWatch.elapsed(TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
public void stop(){
|
@ -1,36 +1,42 @@
|
||||
package org.jim.core;
|
||||
package org.jim.server;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.cluster.ImCluster;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.core.listener.ImGroupListener;
|
||||
import org.jim.core.listener.ImUserListener;
|
||||
import org.jim.core.packets.Group;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.core.packets.UserStatusType;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tio.core.Tio;
|
||||
import org.tio.core.ChannelContext;
|
||||
import org.tio.core.ChannelContextFilter;
|
||||
import org.tio.core.Tio;
|
||||
import org.tio.core.TioConfig;
|
||||
import org.tio.utils.lock.SetWithLock;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
|
||||
/**
|
||||
* 版本: [1.0]
|
||||
* 功能说明: JIM
|
||||
* @author : WChao 创建时间: 2017年9月22日 上午9:07:18
|
||||
*/
|
||||
public class Jim implements ImConst{
|
||||
|
||||
public class JimServerAPI implements ImConst{
|
||||
|
||||
public static ImConfig imConfig = ImConfig.Global.get();
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(Jim.class);
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(JimServerAPI.class);
|
||||
|
||||
/**
|
||||
* 根据群组ID获取该群组下所有Channel
|
||||
@ -39,17 +45,42 @@ public class Jim implements ImConst{
|
||||
*/
|
||||
public static List<ImChannelContext> getByGroup(String groupId){
|
||||
SetWithLock<ChannelContext> channelContextSetWithLock = Tio.getByGroup(imConfig.getTioConfig(), groupId);
|
||||
return convertChannelToImChannel(channelContextSetWithLock);
|
||||
List<ImChannelContext> imChannelContextList = convertChannelToImChannel(channelContextSetWithLock);
|
||||
if (CollectionUtils.isEmpty(imChannelContextList)) {
|
||||
//log.info("{}, there is no bind channel with groupId[{}]", imConfig.getName(), groupId);
|
||||
return imChannelContextList;
|
||||
}
|
||||
return imChannelContextList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取用户下所有Channel
|
||||
* 根据用户ID获取用户下所有channel
|
||||
* @param userId 用户ID
|
||||
* @return 用户所有通道集合
|
||||
* @return 用户绑定所有通道集合
|
||||
*/
|
||||
public static List<ImChannelContext> getByUserId(String userId){
|
||||
SetWithLock<ChannelContext> channelContextSetWithLock = Tio.getByUserid(imConfig.getTioConfig(), userId);
|
||||
return convertChannelToImChannel(channelContextSetWithLock);
|
||||
List<ImChannelContext> imChannelContextList = convertChannelToImChannel(channelContextSetWithLock);
|
||||
if (CollectionUtils.isEmpty(imChannelContextList)) {
|
||||
//log.info("{}, there is no bind channel with userId[{}]", imConfig.getName(), userId);
|
||||
return imChannelContextList;
|
||||
}
|
||||
return imChannelContextList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指定IP获取所有绑定的channel
|
||||
* @param ip 指定IP地址
|
||||
* @return 所有绑定ip的通道集合
|
||||
*/
|
||||
public static List<ImChannelContext> getByIp(String ip){
|
||||
SetWithLock<ChannelContext> channelContextSetWithLock = imConfig.getTioConfig().ips.clients(imConfig.getTioConfig(), ip);
|
||||
List<ImChannelContext> imChannelContextList = convertChannelToImChannel(channelContextSetWithLock);
|
||||
if (CollectionUtils.isEmpty(imChannelContextList)) {
|
||||
//log.info("{}, there is no bind channel with ip[{}]", imConfig.getName(), ip);
|
||||
return imChannelContextList;
|
||||
}
|
||||
return imChannelContextList;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,9 +88,20 @@ public class Jim implements ImConst{
|
||||
* @param groupId 群组ID
|
||||
* @param packet 消息包
|
||||
*/
|
||||
public static void sendToGroup(String groupId, ImPacket packet){
|
||||
public static Boolean sendToGroup(String groupId, ImPacket packet){
|
||||
List<ImChannelContext> imChannelContextList = getByGroup(groupId);
|
||||
if(CollectionUtils.isEmpty(imChannelContextList)){
|
||||
ImCluster cluster = imConfig.getCluster();
|
||||
if (cluster != null && !packet.isFromCluster()) {
|
||||
cluster.clusterToGroup(groupId, packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Tio.sendToGroup(imConfig.getTioConfig(), groupId, packet);
|
||||
imChannelContextList.forEach(imChannelContext -> {
|
||||
send(imChannelContext,packet);
|
||||
});
|
||||
return true;
|
||||
}finally {
|
||||
ImCluster cluster = imConfig.getCluster();
|
||||
if (Objects.nonNull(cluster) && !packet.isFromCluster()) {
|
||||
@ -69,7 +111,7 @@ public class Jim implements ImConst{
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送到指定通道;
|
||||
* 发送到指定通道
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param imPacket 消息包
|
||||
*/
|
||||
@ -77,30 +119,52 @@ public class Jim implements ImConst{
|
||||
if(imChannelContext == null){
|
||||
return false;
|
||||
}
|
||||
return Tio.send(imChannelContext.getTioChannelContext(),imPacket);
|
||||
ImPacket convertPacket = convertPacket(imChannelContext , imPacket);
|
||||
if(convertPacket == null){
|
||||
return false;
|
||||
}
|
||||
return Tio.send(imChannelContext.getTioChannelContext(), convertPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阻塞发送(确认把packet发送到对端后再返回)
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param packet 消息包
|
||||
* @param imPacket 消息包
|
||||
* @return
|
||||
*/
|
||||
public static boolean bSend(ImChannelContext imChannelContext , ImPacket packet){
|
||||
public static boolean bSend(ImChannelContext imChannelContext , ImPacket imPacket){
|
||||
if(imChannelContext == null){
|
||||
return false;
|
||||
}
|
||||
return Tio.bSend(imChannelContext.getTioChannelContext(), packet);
|
||||
ImPacket convertPacket = convertPacket(imChannelContext , imPacket);
|
||||
if(convertPacket == null){
|
||||
return false;
|
||||
}
|
||||
return Tio.bSend(imChannelContext.getTioChannelContext(), convertPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送到指定用户;
|
||||
* 发送到指定用户(所有不同协议端)
|
||||
* @param userId 用户ID
|
||||
* @param packet 消息包
|
||||
*/
|
||||
public static void sendToUser(String userId,ImPacket packet){
|
||||
public static boolean sendToUser(String userId, ImPacket packet){
|
||||
List<ImChannelContext> imChannelContexts = getByUserId(userId);
|
||||
if(CollectionUtils.isEmpty(imChannelContexts)){
|
||||
ImCluster cluster = imConfig.getCluster();
|
||||
if (cluster != null && !packet.isFromCluster()) {
|
||||
cluster.clusterToUser(userId, packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Tio.sendToUser(imConfig.getTioConfig(), userId, packet);
|
||||
imChannelContexts.forEach(imChannelContext -> {
|
||||
send(imChannelContext, packet);
|
||||
});
|
||||
return true;
|
||||
}catch (Exception e){
|
||||
log.error("an exception occurred when sending to the specified user", e);
|
||||
return false;
|
||||
}finally {
|
||||
ImCluster cluster = imConfig.getCluster();
|
||||
if (Objects.nonNull(cluster) && !packet.isFromCluster()) {
|
||||
@ -114,8 +178,8 @@ public class Jim implements ImConst{
|
||||
* @param ip 客户端IP地址
|
||||
* @param packet 消息包
|
||||
*/
|
||||
public static void sendToIp( String ip, ImPacket packet) {
|
||||
sendToIp(ip, packet, null);
|
||||
public static Boolean sendToIp( String ip, ImPacket packet) {
|
||||
return sendToIp(ip, packet, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,9 +188,23 @@ public class Jim implements ImConst{
|
||||
* @param packet 消息包
|
||||
* @param channelContextFilter 通道过滤器
|
||||
*/
|
||||
public static void sendToIp(String ip, ImPacket packet, ChannelContextFilter channelContextFilter) {
|
||||
public static Boolean sendToIp(String ip, ImPacket packet, ChannelContextFilter channelContextFilter) {
|
||||
List<ImChannelContext> imChannelContexts = getByIp(ip);
|
||||
if (CollectionUtils.isEmpty(imChannelContexts)) {
|
||||
ImCluster cluster = imConfig.getCluster();
|
||||
if (cluster != null && !packet.isFromCluster()) {
|
||||
cluster.clusterToIp(ip, packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
try{
|
||||
Tio.sendToIp(imConfig.getTioConfig(), ip, packet, channelContextFilter);
|
||||
imChannelContexts.forEach(imChannelContext -> {
|
||||
send(imChannelContext, packet);
|
||||
});
|
||||
return true;
|
||||
}catch (Exception e){
|
||||
log.error("an exception occurred when sending to the specified ip:[{}]", ip, e);
|
||||
return false;
|
||||
}finally {
|
||||
ImCluster cluster = imConfig.getCluster();
|
||||
if (Objects.nonNull(cluster) && !packet.isFromCluster()) {
|
||||
@ -143,7 +221,7 @@ public class Jim implements ImConst{
|
||||
public static boolean bindUser(ImChannelContext imChannelContext, String userId){
|
||||
User user = imChannelContext.getSessionContext().getImClientNode().getUser();
|
||||
if(Objects.isNull(user)){
|
||||
user = User.newBuilder().userId(userId).status(ONLINE).build();
|
||||
user = User.newBuilder().userId(userId).status(UserStatusType.ONLINE.getStatus()).build();
|
||||
}
|
||||
return bindUser(imChannelContext, user);
|
||||
}
|
||||
@ -154,11 +232,11 @@ public class Jim implements ImConst{
|
||||
* @param user 绑定用户信息
|
||||
*/
|
||||
public static boolean bindUser(ImChannelContext imChannelContext, User user){
|
||||
String userId = user.getUserId();
|
||||
if(StringUtils.isEmpty(userId)){
|
||||
log.error("userId is null");
|
||||
if(Objects.isNull(user)|| StringUtils.isEmpty(user.getUserId())){
|
||||
log.error("user or userId is null");
|
||||
return false;
|
||||
}
|
||||
String userId = user.getUserId();
|
||||
Tio.bindUser(imChannelContext.getTioChannelContext(), userId);
|
||||
SetWithLock<ChannelContext> channelContextSetWithLock = Tio.getByUserid(imConfig.getTioConfig(), userId);
|
||||
ReadLock lock = channelContextSetWithLock.getLock().readLock();
|
||||
@ -196,11 +274,11 @@ public class Jim implements ImConst{
|
||||
* @author: WChao
|
||||
*/
|
||||
public static boolean unbindUser(User user){
|
||||
String userId = user.getUserId();
|
||||
if(StringUtils.isEmpty(userId)){
|
||||
log.error("userId is null");
|
||||
if(Objects.isNull(user)|| StringUtils.isEmpty(user.getUserId())){
|
||||
log.error("user or userId is null");
|
||||
return false;
|
||||
}
|
||||
String userId = user.getUserId();
|
||||
TioConfig tioConfig = imConfig.getTioConfig();
|
||||
SetWithLock<ChannelContext> userChannels = Tio.getByUserid(tioConfig, userId);
|
||||
Set<ChannelContext> channelContexts = userChannels.getObj();
|
||||
@ -211,7 +289,7 @@ public class Jim implements ImConst{
|
||||
try{
|
||||
readLock.lock();
|
||||
for (ChannelContext channelContext : channelContexts){
|
||||
ImChannelContext imChannelContext = (ImChannelContext)channelContext.get(ImConst.Key.IM_CHANNEL_CONTEXT_KEY);
|
||||
ImChannelContext imChannelContext = (ImChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY);
|
||||
ImUserListener imUserListener = imConfig.getImUserListener();
|
||||
if(Objects.isNull(imUserListener))continue;
|
||||
User existUser = imChannelContext.getSessionContext().getImClientNode().getUser();
|
||||
@ -226,6 +304,7 @@ public class Jim implements ImConst{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定群组(如果配置了群组监听器,执行回调)
|
||||
* @param imChannelContext IM通道上下文
|
||||
@ -241,37 +320,52 @@ public class Jim implements ImConst{
|
||||
* @param group 绑定群组对象
|
||||
*/
|
||||
public static boolean bindGroup(ImChannelContext imChannelContext, Group group){
|
||||
String groupId = group.getGroupId();
|
||||
if(StringUtils.isEmpty(groupId)){
|
||||
log.error("groupId is null");
|
||||
try {
|
||||
String groupId = group.getGroupId();
|
||||
if(StringUtils.isEmpty(groupId)){
|
||||
log.error("groupId is null");
|
||||
return false;
|
||||
}
|
||||
Tio.bindGroup(imChannelContext.getTioChannelContext(), group.getGroupId());
|
||||
}catch (Exception e){
|
||||
log.error("an exception occurred in the binding group", e);
|
||||
return false;
|
||||
}
|
||||
Tio.bindGroup(imChannelContext.getTioChannelContext(), group.getGroupId());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与指定组解除绑定关系
|
||||
* @param groupId
|
||||
* @param imChannelContext
|
||||
* @param groupId 解绑群组ID
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @author WChao
|
||||
*/
|
||||
public static boolean unbindGroup(String groupId, ImChannelContext imChannelContext){
|
||||
if(StringUtils.isEmpty(groupId)){
|
||||
log.error("groupId is null");
|
||||
try{
|
||||
if(StringUtils.isEmpty(groupId)){
|
||||
log.error("groupId is null");
|
||||
return false;
|
||||
}
|
||||
Tio.unbindGroup(groupId, imChannelContext.getTioChannelContext());
|
||||
}catch (Exception e){
|
||||
log.error("an exception occurred in the unBinding group", e);
|
||||
return false;
|
||||
}
|
||||
Tio.unbindGroup(groupId, imChannelContext.getTioChannelContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与所有组解除解绑关系
|
||||
* @param imChannelContext
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @author WChao
|
||||
*/
|
||||
public static boolean unbindGroup(ImChannelContext imChannelContext){
|
||||
Tio.unbindGroup(imChannelContext.getTioChannelContext());
|
||||
try{
|
||||
Tio.unbindGroup(imChannelContext.getTioChannelContext());
|
||||
}catch (Exception e){
|
||||
log.error("an exception occurred in the unBinding group", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -285,7 +379,12 @@ public class Jim implements ImConst{
|
||||
log.error("groupId or userId is null");
|
||||
return false;
|
||||
}
|
||||
Tio.unbindGroup(imConfig.getTioConfig(), userId, groupId);
|
||||
try {
|
||||
Tio.unbindGroup(imConfig.getTioConfig(), userId, groupId);
|
||||
}catch (Exception e){
|
||||
log.error("an exception occurred in the unBinding group", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -304,7 +403,7 @@ public class Jim implements ImConst{
|
||||
try{
|
||||
readLock.lock();
|
||||
for(ChannelContext channelContext : channels){
|
||||
ImChannelContext imChannelContext = (ImChannelContext)channelContext.get(ImConst.Key.IM_CHANNEL_CONTEXT_KEY);
|
||||
ImChannelContext imChannelContext = (ImChannelContext)channelContext.get(Key.IM_CHANNEL_CONTEXT_KEY);
|
||||
remove(imChannelContext, remark);
|
||||
}
|
||||
}finally{
|
||||
@ -314,8 +413,8 @@ public class Jim implements ImConst{
|
||||
|
||||
/**
|
||||
* 移除指定channel, 和close方法一样,只不过不再进行重连等维护性的操作
|
||||
* @param imChannelContext
|
||||
* @param remark
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param remark 移除描述
|
||||
*/
|
||||
public static void remove(ImChannelContext imChannelContext, String remark){
|
||||
Tio.remove(imChannelContext.getTioChannelContext(), remark);
|
||||
@ -323,8 +422,8 @@ public class Jim implements ImConst{
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
* @param imChannelContext
|
||||
* @param remark
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param remark 移除描述
|
||||
*/
|
||||
public static void close(ImChannelContext imChannelContext, String remark){
|
||||
Tio.close(imChannelContext.getTioChannelContext(), remark);
|
||||
@ -360,4 +459,28 @@ public class Jim implements ImConst{
|
||||
return imChannelContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换协议包同时设置Packet包信息;
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @param packet 消息包
|
||||
* @return
|
||||
*/
|
||||
private static ImPacket convertPacket(ImChannelContext imChannelContext ,ImPacket packet){
|
||||
if(Objects.isNull(imChannelContext) || Objects.isNull(packet)) {
|
||||
return null;
|
||||
}
|
||||
try{
|
||||
ImPacket respPacket = ProtocolManager.Converter.respPacket(packet, packet.getCommand(), imChannelContext);
|
||||
if(respPacket == null){
|
||||
log.error("convert protocol package is empty, please check the protocol");
|
||||
return null;
|
||||
}
|
||||
respPacket.setSynSeq(packet.getSynSeq());
|
||||
return respPacket;
|
||||
}catch (ImException e){
|
||||
log.error("convert protocol packet is abnormal, please check the protocol");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.jim.core.cluster.redis;
|
||||
package org.jim.server.cluster.redis;
|
||||
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.cluster.ImCluster;
|
@ -1,28 +1,24 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.jim.core.cluster.redis;
|
||||
package org.jim.server.cluster.redis;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.cache.redis.JedisTemplate;
|
||||
import org.jim.core.cluster.ImClusterConfig;
|
||||
import org.jim.core.cluster.ImClusterVO;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.redisson.api.RTopic;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.api.listener.MessageListener;
|
||||
import org.redisson.api.listener.StatusListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tio.core.Tio;
|
||||
import org.tio.utils.json.Json;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* @desc Redis集群配置
|
||||
* @author WChao
|
||||
@ -91,12 +87,12 @@ public class RedisClusterConfig extends ImClusterConfig implements ImConst {
|
||||
//发送给指定组
|
||||
String group = imClusterVo.getGroup();
|
||||
if (StringUtils.isNotBlank(group)) {
|
||||
Jim.sendToGroup(group, packet);
|
||||
JimServerAPI.sendToGroup(group, packet);
|
||||
}
|
||||
//发送给指定用户
|
||||
String userId = imClusterVo.getUserId();
|
||||
if (StringUtils.isNotBlank(userId)) {
|
||||
Jim.sendToUser(userId, packet);
|
||||
JimServerAPI.sendToUser(userId, packet);
|
||||
}
|
||||
//发送给指定token
|
||||
String token = imClusterVo.getToken();
|
||||
@ -106,7 +102,7 @@ public class RedisClusterConfig extends ImClusterConfig implements ImConst {
|
||||
//发送给指定ip
|
||||
String ip = imClusterVo.getIp();
|
||||
if (StringUtils.isNotBlank(ip)) {
|
||||
//Jim.sendToIp(me.groupContext, ip, packet);
|
||||
JimServerAPI.sendToIp(ip, packet);
|
||||
}
|
||||
});
|
||||
return me;
|
@ -2,7 +2,6 @@ package org.jim.server.command.handler;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.core.packets.ChatBody;
|
||||
@ -10,6 +9,7 @@ import org.jim.core.packets.ChatType;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.RespBody;
|
||||
import org.jim.server.ImServerChannelContext;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.AbstractCmdHandler;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
@ -53,7 +53,7 @@ public class ChatReqHandler extends AbstractCmdHandler {
|
||||
if(ChatType.CHAT_TYPE_PRIVATE.getNumber() == chatBody.getChatType()){
|
||||
String toId = chatBody.getTo();
|
||||
if(ChatKit.isOnline(toId, isStore)){
|
||||
Jim.sendToUser(toId, ProtocolManager.Converter.respPacket(chatPacket, imServerChannelContext));
|
||||
JimServerAPI.sendToUser(toId, chatPacket);
|
||||
//发送成功响应包
|
||||
return ProtocolManager.Packet.success(channelContext);
|
||||
}else{
|
||||
@ -63,7 +63,7 @@ public class ChatReqHandler extends AbstractCmdHandler {
|
||||
//群聊
|
||||
}else if(ChatType.CHAT_TYPE_PUBLIC.getNumber() == chatBody.getChatType()){
|
||||
String groupId = chatBody.getGroupId();
|
||||
Jim.sendToGroup(groupId, ProtocolManager.Converter.respPacket(chatPacket, imServerChannelContext));
|
||||
JimServerAPI.sendToGroup(groupId, chatPacket);
|
||||
//发送成功响应包
|
||||
return ProtocolManager.Packet.success(channelContext);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.jim.server.command.handler;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.ImStatus;
|
||||
import org.jim.core.exception.ImException;
|
||||
@ -9,6 +8,7 @@ import org.jim.core.packets.CloseReqBody;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.RespBody;
|
||||
import org.jim.core.utils.JsonKit;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.AbstractCmdHandler;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
|
||||
@ -29,12 +29,12 @@ public class CloseReqHandler extends AbstractCmdHandler
|
||||
//关闭请求消息格式不正确
|
||||
return ProtocolManager.Converter.respPacket(new RespBody(Command.COMMAND_CLOSE_REQ, ImStatus.C10020), imChannelContext);
|
||||
}
|
||||
Jim.bSend(imChannelContext, ProtocolManager.Converter.respPacket(new RespBody(Command.COMMAND_CLOSE_REQ, ImStatus.C10021), imChannelContext));
|
||||
JimServerAPI.bSend(imChannelContext, ProtocolManager.Converter.respPacket(new RespBody(Command.COMMAND_CLOSE_REQ, ImStatus.C10021), imChannelContext));
|
||||
if(closeReqBody == null || closeReqBody.getUserId() == null){
|
||||
Jim.remove(imChannelContext, "收到关闭请求");
|
||||
JimServerAPI.remove(imChannelContext, "收到关闭请求");
|
||||
}else{
|
||||
String userId = closeReqBody.getUserId();
|
||||
Jim.remove(userId, "收到关闭请求!");
|
||||
JimServerAPI.remove(userId, "收到关闭请求!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package org.jim.server.command.handler;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.core.http.HttpRequest;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.ws.WsSessionContext;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.AbstractCmdHandler;
|
||||
import org.jim.server.processor.handshake.HandshakeCmdProcessor;
|
||||
|
||||
@ -24,15 +24,15 @@ public class HandshakeReqHandler extends AbstractCmdHandler {
|
||||
|
||||
HandshakeCmdProcessor handshakeProcessor = this.getMultiProcessor(channelContext,HandshakeCmdProcessor.class);
|
||||
if(Objects.isNull(handshakeProcessor)){
|
||||
Jim.remove(channelContext, "没有对应的握手协议处理器HandshakeCmdProcessor...");
|
||||
JimServerAPI.remove(channelContext, "没有对应的握手协议处理器HandshakeCmdProcessor...");
|
||||
return null;
|
||||
}
|
||||
ImPacket handShakePacket = handshakeProcessor.handshake(packet, channelContext);
|
||||
if (handShakePacket == null) {
|
||||
Jim.remove(channelContext, "业务层不同意握手");
|
||||
JimServerAPI.remove(channelContext, "业务层不同意握手");
|
||||
return null;
|
||||
}
|
||||
Jim.send(channelContext, handShakePacket);
|
||||
JimServerAPI.send(channelContext, handShakePacket);
|
||||
WsSessionContext wsSessionContext = (WsSessionContext) channelContext.getSessionContext();
|
||||
HttpRequest request = wsSessionContext.getHandshakeRequestPacket();
|
||||
handshakeProcessor.onAfterHandshake(request, channelContext);
|
||||
|
@ -3,6 +3,7 @@ package org.jim.server.command.handler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jim.core.*;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.processor.group.GroupCmdProcessor;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
import org.slf4j.Logger;
|
||||
@ -32,7 +33,7 @@ public class JoinGroupReqHandler extends AbstractCmdHandler {
|
||||
String groupId = joinGroup.getGroupId();
|
||||
if (StringUtils.isBlank(groupId)) {
|
||||
log.error("group is null,{}", imChannelContext);
|
||||
Jim.close(imChannelContext, "group is null when join group");
|
||||
JimServerAPI.close(imChannelContext, "group is null when join group");
|
||||
return null;
|
||||
}
|
||||
//实际绑定之前执行处理器动作
|
||||
@ -48,7 +49,7 @@ public class JoinGroupReqHandler extends AbstractCmdHandler {
|
||||
}
|
||||
}
|
||||
//处理完处理器内容后
|
||||
Jim.bindGroup(imChannelContext, joinGroup);
|
||||
JimServerAPI.bindGroup(imChannelContext, joinGroup);
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
|
@ -5,14 +5,11 @@ import org.jim.core.*;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImException;
|
||||
import org.jim.core.message.MessageHelper;
|
||||
import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.Group;
|
||||
import org.jim.core.packets.LoginReqBody;
|
||||
import org.jim.core.packets.LoginRespBody;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.core.packets.*;
|
||||
import org.jim.core.protocol.IProtocol;
|
||||
import org.jim.core.utils.JsonKit;
|
||||
import org.jim.server.ImServerChannelContext;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.AbstractCmdHandler;
|
||||
import org.jim.server.command.CommandManager;
|
||||
import org.jim.server.processor.login.LoginCmdProcessor;
|
||||
@ -41,7 +38,7 @@ public class LoginReqHandler extends AbstractCmdHandler {
|
||||
User user = getUserByProcessor(imChannelContext, loginProcessor, loginReqBody, loginRespBody);
|
||||
IProtocol protocol = imServerChannelContext.getProtocolHandler().getProtocol();
|
||||
user.setTerminal(Objects.isNull(protocol) ? Protocol.UNKNOWN : protocol.name());
|
||||
Jim.bindUser(imServerChannelContext, user);
|
||||
JimServerAPI.bindUser(imServerChannelContext, user);
|
||||
//初始化绑定或者解绑群组;
|
||||
initGroup(imChannelContext, user);
|
||||
loginProcessor.onSuccess(user, imChannelContext);
|
||||
@ -59,15 +56,15 @@ public class LoginReqHandler extends AbstractCmdHandler {
|
||||
*/
|
||||
private User getUserByProcessor(ImChannelContext imChannelContext, LoginCmdProcessor loginProcessor, LoginReqBody loginReqBody, LoginRespBody loginRespBody)throws ImException{
|
||||
if(Objects.isNull(loginProcessor)){
|
||||
User user = User.newBuilder().userId(loginReqBody.getUserId()).status(ONLINE).build();
|
||||
User user = User.newBuilder().userId(loginReqBody.getUserId()).status(UserStatusType.ONLINE.getStatus()).build();
|
||||
return user;
|
||||
}
|
||||
loginRespBody = loginProcessor.doLogin(loginReqBody, imChannelContext);
|
||||
if (Objects.isNull(loginRespBody) || loginRespBody.getCode() != ImStatus.C10007.getCode()) {
|
||||
log.error("login failed, userId:{}, password:{}", loginReqBody.getUserId(), loginReqBody.getPassword());
|
||||
loginProcessor.onFailed(imChannelContext);
|
||||
Jim.bSend(imChannelContext, ProtocolManager.Converter.respPacket(loginRespBody, imChannelContext));
|
||||
Jim.remove(imChannelContext, "userId or token is incorrect");
|
||||
JimServerAPI.bSend(imChannelContext, ProtocolManager.Converter.respPacket(loginRespBody, imChannelContext));
|
||||
JimServerAPI.remove(imChannelContext, "userId or token is incorrect");
|
||||
return null;
|
||||
}
|
||||
return loginProcessor.getUser(loginReqBody, imChannelContext);
|
||||
|
@ -6,7 +6,7 @@ import org.jim.core.packets.Group;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.core.packets.UserReqBody;
|
||||
import org.jim.core.packets.UserStatusType;
|
||||
import org.jim.core.utils.ImKit;
|
||||
import org.jim.server.util.ImServerKit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -71,13 +71,13 @@ public class NonPersistentUserInfo implements IUserInfo {
|
||||
if(FRIEND_GROUP_FLAG == flag){
|
||||
users = group.getUsers();
|
||||
}else if(GROUP_FLAG == flag){
|
||||
users = ImKit.getUsersByGroup(group.getGroupId());
|
||||
users = ImServerKit.getUsersByGroup(group.getGroupId());
|
||||
}
|
||||
resultGroups.add(cloneGroup);
|
||||
if(CollectionUtils.isEmpty(users))return;
|
||||
List<User> cloneUsers = new ArrayList<User>();
|
||||
users.forEach(user -> {
|
||||
User onlineUser = ImKit.getUser(user.getUserId());
|
||||
User onlineUser = ImServerKit.getUser(user.getUserId());
|
||||
//在线
|
||||
if(onlineUser != null && UserStatusType.ONLINE.getNumber() == type){
|
||||
cloneUsers.add(onlineUser.clone());
|
||||
|
@ -42,10 +42,6 @@ public class ImServerConfig extends ImConfig {
|
||||
* 用户消息持久化助手;
|
||||
*/
|
||||
private MessageHelper messageHelper;
|
||||
/**
|
||||
* SSL配置
|
||||
*/
|
||||
private SslConfig sslConfig;
|
||||
/**
|
||||
* http相关配置;
|
||||
*/
|
||||
@ -108,8 +104,6 @@ public class ImServerConfig extends ImConfig {
|
||||
|
||||
private String isSSL = OFF;
|
||||
|
||||
private SslConfig sslConfig;
|
||||
|
||||
private HttpConfig httpConfig;
|
||||
|
||||
private WsConfig wsConfig;
|
||||
@ -144,11 +138,6 @@ public class ImServerConfig extends ImConfig {
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public Builder sslConfig(SslConfig sslConfig){
|
||||
this.sslConfig = sslConfig;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public Builder httConfig(HttpConfig httpConfig){
|
||||
this.httpConfig = httpConfig;
|
||||
return getThis();
|
||||
|
@ -12,6 +12,7 @@ import org.jim.core.listener.AbstractImStoreBindListener;
|
||||
import org.jim.core.message.MessageHelper;
|
||||
import org.jim.core.packets.Group;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.core.packets.UserStatusType;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -63,7 +64,7 @@ public class RedisImStoreBindListener extends AbstractImStoreBindListener {
|
||||
if(!isStore() || Objects.isNull(user)) {
|
||||
return;
|
||||
}
|
||||
user.setStatus(ONLINE);
|
||||
user.setStatus(UserStatusType.ONLINE.getStatus());
|
||||
this.messageHelper.updateUserTerminal(user);
|
||||
initUserInfo(user);
|
||||
}
|
||||
@ -73,7 +74,7 @@ public class RedisImStoreBindListener extends AbstractImStoreBindListener {
|
||||
if(!isStore() || Objects.isNull(user)) {
|
||||
return;
|
||||
}
|
||||
user.setStatus(OFFLINE);
|
||||
user.setStatus(UserStatusType.OFFLINE.getStatus());
|
||||
this.messageHelper.updateUserTerminal(user);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class RedisMessageHelper extends AbstractMessageHelper{
|
||||
String terminalKey = terminalKeyIterator.next();
|
||||
terminalKey = terminalKey.substring(terminalKey.indexOf(userId));
|
||||
String isOnline = RedisCacheManager.getCache(USER).get(terminalKey, String.class);
|
||||
if(ONLINE.equals(isOnline)){
|
||||
if(UserStatusType.ONLINE.getStatus().equals(isOnline)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -275,9 +275,9 @@ public class RedisMessageHelper extends AbstractMessageHelper{
|
||||
*/
|
||||
private void validateStatusByType(Integer type, List<User> users, User user) {
|
||||
String status = user.getStatus();
|
||||
if(UserStatusType.ONLINE.getNumber() == type && ONLINE.equals(status)){
|
||||
if(UserStatusType.ONLINE.getNumber() == type && UserStatusType.ONLINE.getStatus().equals(status)){
|
||||
users.add(user);
|
||||
}else if(UserStatusType.OFFLINE.getNumber() == type && OFFLINE.equals(status)){
|
||||
}else if(UserStatusType.OFFLINE.getNumber() == type && UserStatusType.OFFLINE.getStatus().equals(status)){
|
||||
users.add(user);
|
||||
}else if(UserStatusType.ALL.getNumber() == type){
|
||||
users.add(user);
|
||||
@ -291,7 +291,7 @@ public class RedisMessageHelper extends AbstractMessageHelper{
|
||||
return null;
|
||||
}
|
||||
boolean isOnline = this.isOnline(userId);
|
||||
String status = isOnline ? ONLINE : OFFLINE;
|
||||
String status = isOnline ? UserStatusType.ONLINE.getStatus() : UserStatusType.OFFLINE.getStatus();
|
||||
if( UserStatusType.ONLINE.getNumber() == type && isOnline){
|
||||
user.setStatus(status);
|
||||
return user;
|
||||
@ -344,9 +344,9 @@ public class RedisMessageHelper extends AbstractMessageHelper{
|
||||
String userId = user.getUserId();
|
||||
boolean isOnline = this.isOnline(userId);
|
||||
if(isOnline){
|
||||
user.setStatus(ONLINE);
|
||||
user.setStatus(UserStatusType.ONLINE.getStatus());
|
||||
}else{
|
||||
user.setStatus(OFFLINE);
|
||||
user.setStatus(UserStatusType.OFFLINE.getStatus());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -110,48 +110,74 @@ public class ProtocolManager implements ImConst{
|
||||
/**
|
||||
* 功能描述:[转换不同协议响应包]
|
||||
* @author:WChao 创建时间: 2017年9月21日 下午3:21:54
|
||||
* @param respBody
|
||||
* @param channelContext
|
||||
* @param respBody 响应消息体
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public static ImPacket respPacket(RespBody respBody, ImChannelContext channelContext)throws ImException {
|
||||
public static ImPacket respPacket(RespBody respBody, ImChannelContext imChannelContext)throws ImException {
|
||||
if(Objects.isNull(respBody)) {
|
||||
throw new ImException("响应包体不能为空!");
|
||||
}
|
||||
return respPacket(respBody.toByte(), respBody.getCommand(), channelContext);
|
||||
return respPacket(respBody.toByte(), respBody.getCommand(), imChannelContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:[转换不同协议响应包]
|
||||
* @param body 消息体字节
|
||||
* @param command 命令码
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @return
|
||||
* @throws ImException
|
||||
*/
|
||||
public static ImPacket respPacket(byte[] body, Command command, ImChannelContext imChannelContext)throws ImException{
|
||||
return getProtocolConverter(imChannelContext).RespPacket(body, command, imChannelContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:[转换不同协议响应包]
|
||||
* @param imPacket 消息包
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @return
|
||||
* @throws ImException
|
||||
*/
|
||||
public static ImPacket respPacket(ImPacket imPacket, ImChannelContext imChannelContext)throws ImException{
|
||||
return respPacket(imPacket, imPacket.getCommand(), imChannelContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能描述:[转换不同协议响应包]
|
||||
* @author:WChao 创建时间: 2017年9月21日 下午3:21:54
|
||||
* @param body
|
||||
* @param channelContext
|
||||
* @param imPacket 消息包
|
||||
* @param command 命令码
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public static ImPacket respPacket(byte[] body, Command command, ImChannelContext channelContext)throws ImException{
|
||||
ImServerChannelContext serverChannelContext = (ImServerChannelContext)channelContext;
|
||||
public static ImPacket respPacket(ImPacket imPacket,Command command, ImChannelContext imChannelContext)throws ImException{
|
||||
return getProtocolConverter(imChannelContext).RespPacket(imPacket, command, imChannelContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过通道获取当前通道协议
|
||||
* @param imChannelContext IM通道上下文
|
||||
* @return
|
||||
* @throws ImException
|
||||
*/
|
||||
private static IProtocolConverter getProtocolConverter(ImChannelContext imChannelContext) throws ImException{
|
||||
ImServerChannelContext serverChannelContext = (ImServerChannelContext)imChannelContext;
|
||||
AbstractProtocolHandler protocolHandler = serverChannelContext.getProtocolHandler();
|
||||
if(Objects.isNull(protocolHandler)){
|
||||
throw new ImException("协议[ProtocolHandler]未初始化,协议包转化失败");
|
||||
}
|
||||
IProtocolConverter converter = protocolHandler.getProtocol().getConverter();
|
||||
if(converter != null){
|
||||
return converter.RespPacket(body, command, channelContext);
|
||||
return converter;
|
||||
}else {
|
||||
throw new ImException("未获取到协议转化器[ProtocolConverter]");
|
||||
}
|
||||
}
|
||||
|
||||
public static ImPacket respPacket(ImPacket imPacket, ImChannelContext channelContext)throws ImException{
|
||||
return respPacket(imPacket, imPacket.getCommand(), channelContext);
|
||||
}
|
||||
|
||||
public static ImPacket respPacket(ImPacket imPacket,Command command, ImChannelContext channelContext)throws ImException{
|
||||
return respPacket(imPacket.getBody(), command, channelContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Packet{
|
||||
|
@ -326,7 +326,9 @@ public class DefaultHttpRequestHandler implements IHttpRequestHandler,ImConst.Ht
|
||||
cookie = new Cookie(domain, name, sessionId, maxAge);
|
||||
httpResponse.addCookie(cookie);
|
||||
httpConfig.getSessionStore().put(sessionId, httpSession);
|
||||
log.info("{} 创建会话Cookie, {}", request.getImChannelContext(), cookie);
|
||||
if(log.isDebugEnabled()){
|
||||
log.info("{} 创建会话Cookie, {}", request.getImChannelContext(), cookie);
|
||||
}
|
||||
} else {
|
||||
sessionId = cookie.getValue();
|
||||
HttpSession httpSession1 = (HttpSession) httpConfig.getSessionStore().get(sessionId);
|
||||
|
@ -6,7 +6,6 @@ package org.jim.server.protocol.http;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.exception.ImDecodeException;
|
||||
import org.jim.core.exception.ImException;
|
||||
@ -14,7 +13,8 @@ import org.jim.core.http.*;
|
||||
import org.jim.core.http.handler.IHttpRequestHandler;
|
||||
import org.jim.core.protocol.AbstractProtocol;
|
||||
import org.jim.core.session.id.impl.UUIDSessionIdGenerator;
|
||||
import org.jim.server.ImServerStarter;
|
||||
import org.jim.server.JimServer;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
import org.jim.server.protocol.AbstractProtocolHandler;
|
||||
import org.jim.server.protocol.http.mvc.Routes;
|
||||
@ -59,11 +59,11 @@ public class HttpProtocolHandler extends AbstractProtocolHandler {
|
||||
}
|
||||
if(Objects.isNull(httpConfig.getScanPackages())){
|
||||
//J-IM MVC需要扫描的根目录包
|
||||
String[] scanPackages = new String[] { ImServerStarter.class.getPackage().getName() };
|
||||
String[] scanPackages = new String[] { JimServer.class.getPackage().getName() };
|
||||
httpConfig.setScanPackages(scanPackages);
|
||||
}else{
|
||||
String[] scanPackages = new String[httpConfig.getScanPackages().length+1];
|
||||
scanPackages[0] = ImServerStarter.class.getPackage().getName();
|
||||
scanPackages[0] = JimServer.class.getPackage().getName();
|
||||
System.arraycopy(httpConfig.getScanPackages(), 0, scanPackages, 1, httpConfig.getScanPackages().length);
|
||||
httpConfig.setScanPackages(scanPackages);
|
||||
}
|
||||
@ -84,7 +84,7 @@ public class HttpProtocolHandler extends AbstractProtocolHandler {
|
||||
public void handler(ImPacket imPacket, ImChannelContext imChannelContext)throws ImException {
|
||||
HttpRequest httpRequestPacket = (HttpRequest) imPacket;
|
||||
HttpResponse httpResponsePacket = httpRequestHandler.handler(httpRequestPacket, httpRequestPacket.getRequestLine());
|
||||
Jim.send(imChannelContext, httpResponsePacket);
|
||||
JimServerAPI.send(imChannelContext, httpResponsePacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,7 @@ import org.jim.core.packets.Command;
|
||||
import org.jim.core.packets.RespBody;
|
||||
import org.jim.core.protocol.AbstractProtocol;
|
||||
import org.jim.core.tcp.*;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.AbstractCmdHandler;
|
||||
import org.jim.server.command.CommandManager;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
@ -54,12 +55,12 @@ public class TcpProtocolHandler extends AbstractProtocolHandler {
|
||||
AbstractCmdHandler cmdHandler = CommandManager.getCommand(tcpPacket.getCommand());
|
||||
if(cmdHandler == null){
|
||||
ImPacket imPacket = new ImPacket(Command.COMMAND_UNKNOW, new RespBody(Command.COMMAND_UNKNOW,ImStatus.C10017).toByte());
|
||||
Jim.send(imChannelContext, imPacket);
|
||||
JimServerAPI.send(imChannelContext, imPacket);
|
||||
return;
|
||||
}
|
||||
ImPacket response = cmdHandler.handler(tcpPacket, imChannelContext);
|
||||
if(Objects.nonNull(response) && tcpPacket.getSynSeq() < 1){
|
||||
Jim.send(imChannelContext, response);
|
||||
JimServerAPI.send(imChannelContext, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,14 @@ package org.jim.server.protocol.ws;
|
||||
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.ImPacket;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.packets.ChatBody;
|
||||
import org.jim.core.ws.IWsMsgHandler;
|
||||
import org.jim.core.ws.Opcode;
|
||||
import org.jim.core.ws.WsRequestPacket;
|
||||
import org.jim.core.ws.WsResponsePacket;
|
||||
import org.jim.core.ws.WsConfig;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
import org.jim.server.protocol.ProtocolManager;
|
||||
import org.jim.server.util.ChatKit;
|
||||
@ -42,7 +41,7 @@ public class WsMsgHandler implements IWsMsgHandler{
|
||||
boolean isStore = ImServerConfig.ON.equals(imServerConfig.getIsStore());
|
||||
String toId = chatBody.getTo();
|
||||
if(ChatKit.isOnline(toId,isStore)){
|
||||
Jim.sendToUser(toId, wsRequestPacket);
|
||||
JimServerAPI.sendToUser(toId, wsRequestPacket);
|
||||
ImPacket sendSuccessPacket = ProtocolManager.Packet.success(imChannelContext);
|
||||
text = new String(sendSuccessPacket.getBody(), ImConst.Http.CHARSET_NAME);
|
||||
}else{
|
||||
@ -85,7 +84,7 @@ public class WsMsgHandler implements IWsMsgHandler{
|
||||
WsResponsePacket wsResponse = null;
|
||||
if (opcode == Opcode.TEXT) {
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
Jim.remove(imChannelContext, "错误的webSocket包,body为空");
|
||||
JimServerAPI.remove(imChannelContext, "错误的webSocket包,body为空");
|
||||
return null;
|
||||
}
|
||||
String text = new String(bytes, wsServerConfig.getCharset());
|
||||
@ -95,7 +94,7 @@ public class WsMsgHandler implements IWsMsgHandler{
|
||||
return wsResponse;
|
||||
} else if (opcode == Opcode.BINARY) {
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
Jim.remove(imChannelContext, "错误的webSocket包,body为空");
|
||||
JimServerAPI.remove(imChannelContext, "错误的webSocket包,body为空");
|
||||
return null;
|
||||
}
|
||||
Object retObj = this.onBytes(wsRequest, bytes, imChannelContext);
|
||||
@ -111,7 +110,7 @@ public class WsMsgHandler implements IWsMsgHandler{
|
||||
wsResponse = processRetObj(retObj, methodName, imChannelContext);
|
||||
return wsResponse;
|
||||
} else {
|
||||
Jim.remove(imChannelContext, "错误的webSocket包,错误的Opcode");
|
||||
JimServerAPI.remove(imChannelContext, "错误的webSocket包,错误的Opcode");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -149,7 +148,7 @@ public class WsMsgHandler implements IWsMsgHandler{
|
||||
}
|
||||
@Override
|
||||
public Object onClose(WsRequestPacket webSocketPacket, byte[] bytes, ImChannelContext imChannelContext) throws Exception {
|
||||
Jim.remove(imChannelContext, "receive close flag");
|
||||
JimServerAPI.remove(imChannelContext, "receive close flag");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import org.jim.core.packets.RespBody;
|
||||
import org.jim.core.protocol.AbstractProtocol;
|
||||
import org.jim.core.utils.JsonKit;
|
||||
import org.jim.core.ws.*;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.command.AbstractCmdHandler;
|
||||
import org.jim.server.command.CommandManager;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
@ -87,12 +88,12 @@ public class WsProtocolHandler extends AbstractProtocolHandler {
|
||||
return;
|
||||
}
|
||||
ImPacket wsPacket = new ImPacket(Command.COMMAND_UNKNOW, new RespBody(Command.COMMAND_UNKNOW,ImStatus.C10017).toByte());
|
||||
Jim.send(imChannelContext, wsPacket);
|
||||
JimServerAPI.send(imChannelContext, wsPacket);
|
||||
return;
|
||||
}
|
||||
ImPacket response = cmdHandler.handler(wsRequestPacket, imChannelContext);
|
||||
if(Objects.nonNull(response)){
|
||||
Jim.send(imChannelContext, response);
|
||||
JimServerAPI.send(imChannelContext, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,12 +9,12 @@ import org.apache.log4j.Logger;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.ImConst;
|
||||
import org.jim.core.ImSessionContext;
|
||||
import org.jim.core.Jim;
|
||||
import org.jim.core.config.ImConfig;
|
||||
import org.jim.core.packets.ChatBody;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.core.session.id.impl.UUIDSessionIdGenerator;
|
||||
import org.jim.core.utils.JsonKit;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.jim.server.config.ImServerConfig;
|
||||
import java.util.List;
|
||||
|
||||
@ -106,7 +106,7 @@ public class ChatKit {
|
||||
ImServerConfig imServerConfig = ImConfig.Global.get();
|
||||
return imServerConfig.getMessageHelper().isOnline(userId);
|
||||
}
|
||||
List<ImChannelContext> imChannelContexts = Jim.getByUserId(userId);
|
||||
List<ImChannelContext> imChannelContexts = JimServerAPI.getByUserId(userId);
|
||||
if(CollectionUtils.isNotEmpty(imChannelContexts)){
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.jim.server.util;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.jim.core.ImChannelContext;
|
||||
import org.jim.core.packets.User;
|
||||
import org.jim.server.JimServerAPI;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* IM工具类;
|
||||
* @author WChao
|
||||
*
|
||||
*/
|
||||
public class ImServerKit {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ImServerKit.class);
|
||||
|
||||
/**
|
||||
* 根据群组获取所有用户;
|
||||
* @param groupId 群组ID
|
||||
* @return 群组用户集合列表
|
||||
*/
|
||||
public static List<User> getUsersByGroup(String groupId){
|
||||
List<ImChannelContext> channelContexts = JimServerAPI.getByGroup(groupId);
|
||||
List<User> users = Lists.newArrayList();
|
||||
if(CollectionUtils.isEmpty(channelContexts)){
|
||||
return users;
|
||||
}
|
||||
Map<String,User> userMap = new HashMap<>();
|
||||
channelContexts.forEach(imChannelContext -> {
|
||||
User user = imChannelContext.getSessionContext().getImClientNode().getUser();
|
||||
if(Objects.nonNull(user) && Objects.isNull(userMap.get(user.getUserId()))){
|
||||
userMap.put(user.getUserId(), user);
|
||||
users.add(user);
|
||||
}
|
||||
});
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取用户信息(一个用户ID会有多端通道,默认取第一个)
|
||||
* @param userId 用户ID
|
||||
* @return user信息
|
||||
*/
|
||||
public static User getUser(String userId){
|
||||
List<ImChannelContext> imChannelContexts = JimServerAPI.getByUserId(userId);
|
||||
if(CollectionUtils.isEmpty(imChannelContexts)) {
|
||||
return null;
|
||||
}
|
||||
return imChannelContexts.get(0).getSessionContext().getImClientNode().getUser();
|
||||
}
|
||||
|
||||
}
|
9
pom.xml
9
pom.xml
@ -30,8 +30,9 @@
|
||||
<modules>
|
||||
<module>jim-core</module>
|
||||
<module>jim-server</module>
|
||||
<module>jim-client</module>
|
||||
<module>jim-server-demo</module>
|
||||
<!--<module>jim-client</module>-->
|
||||
<module>jim-client-demo</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<jim.version>3.0.0.v20200101-RELEASE</jim.version>
|
||||
@ -93,7 +94,11 @@
|
||||
<artifactId>jim-server</artifactId>
|
||||
<version>${jim.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.j-im</groupId>
|
||||
<artifactId>jim-client</artifactId>
|
||||
<version>${jim.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
|
Loading…
Reference in New Issue
Block a user