mirror of
https://gitee.com/farsunset/cim.git
synced 2025-07-14 20:31:17 +08:00
1 新增 Java版本客户端,可用于系统应用,桌面应用之间实时消息推送
2 FlashBridge 基于web版本的插件经过调试优化发布正式版,可以用于网页的消息推送 3 Netty版本修改了当消息断包时处理不当,导致消息丢失的问题
This commit is contained in:
parent
3585cf4eb2
commit
22e6284dac
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>CIMBridge</name>
|
||||
<name>CIMFlashBridge</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
BIN
CIMFlashBridge/bin-debug/CIMBridge.swf
Normal file
BIN
CIMFlashBridge/bin-debug/CIMBridge.swf
Normal file
Binary file not shown.
BIN
CIMFlashBridge/bin-release/CIMBridge.swf
Normal file
BIN
CIMFlashBridge/bin-release/CIMBridge.swf
Normal file
Binary file not shown.
@ -2,16 +2,12 @@ package
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.events.IOErrorEvent;
|
||||
import flash.events.ProgressEvent;
|
||||
import flash.events.SecurityErrorEvent;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.external.ExternalInterface;
|
||||
import flash.net.Socket;
|
||||
import flash.system.Security;
|
||||
import flash.utils.Timer;
|
||||
import flash.media.Sound;
|
||||
import flash.net.Socket;
|
||||
import flash.net.URLRequest;
|
||||
import flash.system.Security;
|
||||
|
||||
public class CIMBridge extends Sprite
|
||||
{
|
||||
@ -19,22 +15,23 @@ package
|
||||
internal var CIM_PORT:String = "23456";
|
||||
internal var socket:Socket;
|
||||
internal var froceOffline :Boolean = false;
|
||||
internal var _sound:Sound = new Sound(new URLRequest("dingdong.mp3"));
|
||||
|
||||
internal const MESSAGE_SEPARATE :String = '\b';
|
||||
/**
|
||||
* 服务端心跳请求命令 cmd_server_hb_request
|
||||
* 服务端心跳请求命令
|
||||
*/
|
||||
internal const CMD_HEARTBEAT_REQUEST:String="S_H_RQ";
|
||||
/**
|
||||
* 客户端心跳响应命令 cmd_client_hb_response
|
||||
* 客户端心跳响应命令
|
||||
*/
|
||||
internal const CMD_HEARTBEAT_RESPONSE:String ="C_H_RS";
|
||||
|
||||
internal var mBuffer :String = '\b';
|
||||
|
||||
public function CIMBridge()
|
||||
{
|
||||
|
||||
ExternalInterface.addCallback("connect",connect);
|
||||
ExternalInterface.addCallback("setAccount",setAccount);
|
||||
ExternalInterface.addCallback("bindAccount",bindAccount);
|
||||
ExternalInterface.addCallback("getOfflineMessage",getOfflineMessage);
|
||||
ExternalInterface.addCallback("logout",logout);
|
||||
ExternalInterface.addCallback("playSound",playSound);
|
||||
@ -47,20 +44,17 @@ package
|
||||
|
||||
CIM_HOST = host;
|
||||
var policyfile:String="xmlsocket://"+CIM_HOST+":"+CIM_PORT;
|
||||
Security.loadPolicyFile(policyfile);
|
||||
Security.loadPolicyFile(policyfile);//加载安全策略文件,得到相应的返回才会创建连接
|
||||
socket=new Socket();
|
||||
socket.addEventListener(Event.CONNECT,sessionCreated);//监听是否连接上服务器
|
||||
socket.addEventListener(Event.CLOSE,sessionClosed);//监听套接字连接是否关闭
|
||||
socket.addEventListener(IOErrorEvent.IO_ERROR,exceptionCaught);
|
||||
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityErrorFun);
|
||||
//监听服务器新信息
|
||||
socket.addEventListener(ProgressEvent.SOCKET_DATA,messageReceived);
|
||||
socket.addEventListener(ProgressEvent.SOCKET_DATA,messageReceived); //监听服务器消息
|
||||
|
||||
socket.connect(CIM_HOST,parseInt(CIM_PORT));//连接服务器
|
||||
|
||||
}
|
||||
|
||||
public function setAccount(account:String,deviceId:String):void
|
||||
public function bindAccount(account:String,deviceId:String):void
|
||||
{
|
||||
var xml:String="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
xml+="<sent>";
|
||||
@ -68,10 +62,10 @@ package
|
||||
xml+="<data>";
|
||||
xml+="<account>"+account+"</account>";
|
||||
xml+="<deviceId>"+deviceId+"</deviceId>";
|
||||
xml+="<channel>web</channel>";
|
||||
xml+="<device>flash</device>";
|
||||
xml+="<channel>browse</channel>";
|
||||
xml+="<device>Flash</device>";
|
||||
xml+="<version>2.0.0</version>";
|
||||
xml+="<osVersion>"+flash.system.Capabilities.version+"</osVersion>";
|
||||
xml+="<osVersion>"+flash.system.Capabilities.os+"</osVersion>";
|
||||
xml+="</data>";
|
||||
xml+="</sent>";
|
||||
|
||||
@ -118,44 +112,18 @@ package
|
||||
connect(CIM_HOST);
|
||||
}
|
||||
}
|
||||
private function exceptionCaught(event:Event):void{
|
||||
|
||||
//Alert.show("exceptionCaught","提示");
|
||||
}
|
||||
|
||||
|
||||
private function securityErrorFun(event:Event):void{
|
||||
|
||||
//Alert.show("securityErrorFun"+event.toString(),"提示");
|
||||
}
|
||||
internal function handleMessage(message:String):void{
|
||||
|
||||
|
||||
|
||||
/**接受服务器信息*/
|
||||
internal function messageReceived(event:ProgressEvent):void
|
||||
{
|
||||
var msg:String="";
|
||||
//循环读取数据
|
||||
while(socket.bytesAvailable)
|
||||
{
|
||||
msg+=socket.readUTFBytes(socket.bytesAvailable);
|
||||
}
|
||||
|
||||
var index:int = msg.indexOf("\b");
|
||||
if(msg.indexOf("\b")>=0)
|
||||
{
|
||||
msg = msg.substring(0,index);
|
||||
}
|
||||
|
||||
|
||||
if(msg.toUpperCase() == CMD_HEARTBEAT_REQUEST)
|
||||
if(message.toUpperCase() == CMD_HEARTBEAT_REQUEST)
|
||||
{
|
||||
send(CMD_HEARTBEAT_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var xml:XML=XML(msg);
|
||||
var data:Object = xml as Object;
|
||||
var xml:XML=XML(message);
|
||||
if(xml.name()=="reply"){
|
||||
ExternalInterface.call("onReplyReceived",ReplyBody.mappingToJSON(xml));
|
||||
}
|
||||
@ -167,7 +135,28 @@ package
|
||||
froceOffline = true;
|
||||
}
|
||||
|
||||
ExternalInterface.call("onMessageReceived",Message.mappingToJSON(xml),xml["content"].toString());
|
||||
ExternalInterface.call("onMessageReceived",Message.mappingToJSON(xml));
|
||||
}
|
||||
}
|
||||
|
||||
/**接受服务器信息*/
|
||||
internal function messageReceived(event:ProgressEvent):void
|
||||
{
|
||||
|
||||
mBuffer+=socket.readMultiByte(socket.bytesAvailable,"UTF-8");;
|
||||
if(mBuffer.charAt(mBuffer.length-1)!=MESSAGE_SEPARATE){
|
||||
|
||||
return ;
|
||||
|
||||
}else
|
||||
{
|
||||
var array:Array = mBuffer.split(MESSAGE_SEPARATE);
|
||||
for each(var message:String in array) {
|
||||
handleMessage(message);
|
||||
}
|
||||
|
||||
mBuffer = "";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -177,13 +166,14 @@ package
|
||||
internal function send(msg:String):void
|
||||
{
|
||||
//新建一个ByteArray来存放数据
|
||||
socket.writeUTFBytes(msg+"\b");
|
||||
socket.writeUTFBytes(msg+MESSAGE_SEPARATE);
|
||||
//调用flush方法发送信息
|
||||
socket.flush();
|
||||
}
|
||||
|
||||
public function playSound():void
|
||||
public function playSound(name:String):void
|
||||
{
|
||||
internal var _sound:Sound = new Sound(new URLRequest(name));
|
||||
_sound.play(1);
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ package
|
||||
message.file = xml["file"];
|
||||
message.fileType = xml["fileType"];
|
||||
message.timestamp = xml["timestamp"];
|
||||
message.content = "";
|
||||
message.content =xml["content"];
|
||||
return com.adobe.serialization.json.JSON.encode(message).toString();
|
||||
}
|
||||
|
@ -2,27 +2,30 @@
|
||||
package
|
||||
{
|
||||
import com.adobe.serialization.json.JSON;
|
||||
|
||||
|
||||
|
||||
public class ReplyBody
|
||||
{
|
||||
public var key:String;
|
||||
public var code:String;
|
||||
public var message:String;
|
||||
public var data:Object;
|
||||
public var data:Object = new Object();
|
||||
public var timestamp:Number;
|
||||
|
||||
|
||||
|
||||
public static function mappingToJSON(xml:XML):Object
|
||||
public static function mappingToJSON(xml:XML):String
|
||||
{
|
||||
var body:ReplyBody = new ReplyBody();
|
||||
body.key = xml["key"];
|
||||
body.code = xml["code"];
|
||||
body.timestamp = xml["timestamp"];
|
||||
var list:XMLList = xml.elements("data").children();
|
||||
for each(var item:XML in list) {
|
||||
body.data[item.name().toString()] =item.toString();
|
||||
}
|
||||
|
||||
return com.adobe.serialization.json.JSON.encode(body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
BIN
CIM客户端文档.doc
BIN
CIM客户端文档.doc
Binary file not shown.
BIN
JavaSDK使用文档.doc
Normal file
BIN
JavaSDK使用文档.doc
Normal file
Binary file not shown.
@ -175,19 +175,15 @@ class CIMConnectorManager extends IoHandlerAdapter implements KeepAliveMessageFa
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
android.os.Message msg = new android.os.Message();
|
||||
msg.getData().putSerializable("body", body);
|
||||
|
||||
IoSession session = getCurrentSession();
|
||||
if(session!=null && session.isConnected())
|
||||
{
|
||||
WriteFuture wf = session.write(body);
|
||||
// 消息发送超时 10秒
|
||||
wf.awaitUninterruptibly(5, TimeUnit.SECONDS);
|
||||
wf.awaitUninterruptibly(10, TimeUnit.SECONDS);
|
||||
|
||||
if (!wf.isWritten()) {
|
||||
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_FAILED);
|
||||
intent.putExtra("exception", new WriteToClosedSessionException());
|
||||
|
10
cim_for_mina/cim-java-sdk/.classpath
Normal file
10
cim_for_mina/cim-java-sdk/.classpath
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="libs/log4j.jar"/>
|
||||
<classpathentry kind="lib" path="libs/mina-core-2.0.13.jar"/>
|
||||
<classpathentry kind="lib" path="libs/slf4j-api-1.7.5.jar"/>
|
||||
<classpathentry kind="lib" path="libs/slf4j-nop-1.7.5.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
23
cim_for_mina/cim-java-sdk/.project
Normal file
23
cim_for_mina/cim-java-sdk/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>java-cim-sdk</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.genuitec.eclipse.ast.deploy.core.DeploymentBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.genuitec.eclipse.ast.deploy.core.deploymentnature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -0,0 +1,3 @@
|
||||
#Wed Oct 15 09:31:41 CST 2014
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
BIN
cim_for_mina/cim-java-sdk/libs/log4j.jar
Normal file
BIN
cim_for_mina/cim-java-sdk/libs/log4j.jar
Normal file
Binary file not shown.
BIN
cim_for_mina/cim-java-sdk/libs/mina-core-2.0.13.jar
Normal file
BIN
cim_for_mina/cim-java-sdk/libs/mina-core-2.0.13.jar
Normal file
Binary file not shown.
BIN
cim_for_mina/cim-java-sdk/libs/slf4j-api-1.7.5.jar
Normal file
BIN
cim_for_mina/cim-java-sdk/libs/slf4j-api-1.7.5.jar
Normal file
Binary file not shown.
BIN
cim_for_mina/cim-java-sdk/libs/slf4j-nop-1.7.5.jar
Normal file
BIN
cim_for_mina/cim-java-sdk/libs/slf4j-nop-1.7.5.jar
Normal file
Binary file not shown.
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
class CIMCacheToolkit {
|
||||
|
||||
private static HashMap<String,String> CIM_CONFIG_INFO = new HashMap<String,String>();
|
||||
|
||||
public static final String KEY_MANUAL_STOP = "KEY_MANUAL_STOP";
|
||||
|
||||
public static final String KEY_CIM_DESTROYED = "KEY_CIM_DESTROYED";
|
||||
|
||||
public static final String KEY_CIM_SERVIER_HOST = "KEY_CIM_SERVIER_HOST";
|
||||
|
||||
public static final String KEY_CIM_SERVIER_PORT = "KEY_CIM_SERVIER_PORT";
|
||||
|
||||
public static final String KEY_CIM_CONNECTION_STATE = "KEY_CIM_CONNECTION_STATE";
|
||||
|
||||
static CIMCacheToolkit toolkit;
|
||||
public static CIMCacheToolkit getInstance(){
|
||||
if (toolkit==null){
|
||||
toolkit = new CIMCacheToolkit();
|
||||
}
|
||||
return toolkit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void remove(String key)
|
||||
{
|
||||
CIM_CONFIG_INFO.remove(key);
|
||||
}
|
||||
|
||||
|
||||
public void putString(String key,String value)
|
||||
{
|
||||
CIM_CONFIG_INFO.put(key,value);
|
||||
|
||||
}
|
||||
|
||||
public String getString(String key)
|
||||
{
|
||||
return CIM_CONFIG_INFO.get(key);
|
||||
}
|
||||
|
||||
public void putBoolean(String key,boolean value)
|
||||
{
|
||||
putString(key,Boolean.toString(value));
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key)
|
||||
{
|
||||
String value = getString(key);
|
||||
return value == null?false:Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
|
||||
public void putInt(String key,int value)
|
||||
{
|
||||
putString(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public int getInt(String key)
|
||||
{
|
||||
String value = getString(key);
|
||||
return value == null?0:Integer.parseInt(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,382 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.mina.core.future.ConnectFuture;
|
||||
import org.apache.mina.core.future.WriteFuture;
|
||||
import org.apache.mina.core.service.IoHandler;
|
||||
import org.apache.mina.core.session.IdleStatus;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
||||
import org.apache.mina.filter.keepalive.KeepAliveFilter;
|
||||
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
|
||||
import org.apache.mina.transport.socket.nio.NioSocketConnector;
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.exception.CIMSessionDisableException;
|
||||
import com.farsunset.cim.sdk.client.exception.WriteToClosedSessionException;
|
||||
import com.farsunset.cim.sdk.client.filter.ClientMessageCodecFactory;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* 连接服务端管理,cim核心处理类,管理连接,以及消息处理
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
class CIMConnectorManager implements IoHandler , KeepAliveMessageFactory {
|
||||
protected final Logger logger = Logger.getLogger(CIMConnectorManager.class);
|
||||
private NioSocketConnector connector;
|
||||
private ConnectFuture connectFuture;
|
||||
|
||||
|
||||
private final int BOTH_IDLE_TIME = 120;//秒
|
||||
|
||||
private final int HEARBEAT_TIME_OUT = 330 * 1000;// 收到服务端心跳请求超时时间 毫秒
|
||||
|
||||
private final String KEY_LAST_HEART_TIME = "KEY_LAST_HEART_TIME" ;
|
||||
|
||||
static CIMConnectorManager manager;
|
||||
|
||||
// 消息广播action
|
||||
public static final String ACTION_MESSAGE_RECEIVED = "com.farsunset.cim.MESSAGE_RECEIVED";
|
||||
|
||||
// 发送sendbody失败广播
|
||||
public static final String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED";
|
||||
|
||||
// 发送sendbody成功广播
|
||||
public static final String ACTION_SENT_SUCCESSED = "com.farsunset.cim.SENT_SUCCESSED";
|
||||
// 链接意外关闭广播
|
||||
public static final String ACTION_CONNECTION_CLOSED = "com.farsunset.cim.CONNECTION_CLOSED";
|
||||
// 链接失败广播
|
||||
public static final String ACTION_CONNECTION_FAILED = "com.farsunset.cim.CONNECTION_FAILED";
|
||||
// 链接成功广播
|
||||
public static final String ACTION_CONNECTION_SUCCESSED = "com.farsunset.cim.CONNECTION_SUCCESSED";
|
||||
// 发送sendbody成功后获得replaybody回应广播
|
||||
public static final String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED";
|
||||
// 网络变化广播
|
||||
public static final String ACTION_NETWORK_CHANGED = "android.net.conn.CONNECTIVITY_CHANGE";
|
||||
|
||||
// 未知异常
|
||||
public static final String ACTION_UNCAUGHT_EXCEPTION = "com.farsunset.cim.UNCAUGHT_EXCEPTION";
|
||||
|
||||
//重试连接
|
||||
public final static String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
|
||||
|
||||
private ExecutorService executor = Executors.newCachedThreadPool();;
|
||||
private CIMConnectorManager() {
|
||||
|
||||
connector = new NioSocketConnector();
|
||||
connector.setConnectTimeoutMillis(10 * 1000);
|
||||
connector.getSessionConfig().setTcpNoDelay(true);
|
||||
connector.getSessionConfig().setBothIdleTime(BOTH_IDLE_TIME);
|
||||
connector.getSessionConfig().setReadBufferSize(2048);
|
||||
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ClientMessageCodecFactory()));
|
||||
|
||||
KeepAliveFilter keepAliveaHandler = new KeepAliveFilter(this, IdleStatus.BOTH_IDLE);
|
||||
keepAliveaHandler.setForwardEvent(true);
|
||||
connector.getFilterChain().addLast("heartbeat", keepAliveaHandler);
|
||||
connector.setHandler(this);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public synchronized static CIMConnectorManager getManager() {
|
||||
if (manager == null) {
|
||||
manager = new CIMConnectorManager();
|
||||
}
|
||||
return manager;
|
||||
|
||||
}
|
||||
|
||||
private synchronized void syncConnection(final String cimServerHost,final int cimServerPort) {
|
||||
try {
|
||||
|
||||
if(isConnected()){
|
||||
return ;
|
||||
}
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, false);
|
||||
InetSocketAddress remoteSocketAddress = new InetSocketAddress(cimServerHost, cimServerPort);
|
||||
connectFuture = connector.connect(remoteSocketAddress);
|
||||
connectFuture.awaitUninterruptibly();
|
||||
connectFuture.getSession();
|
||||
} catch (Exception e) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_CONNECTION_FAILED);
|
||||
intent.putExtra("exception", e);
|
||||
sendBroadcast(intent);
|
||||
|
||||
logger.error("******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendBroadcast(final Intent intent) {
|
||||
executor.execute(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
CIMEventBroadcastReceiver.getInstance().onReceive(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void connect(final String cimServerHost, final int cimServerPort) {
|
||||
|
||||
|
||||
Future<?> future = executor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
syncConnection(cimServerHost, cimServerPort);
|
||||
}
|
||||
});
|
||||
try {
|
||||
if(future.get()!=null)
|
||||
{
|
||||
connect(cimServerHost,cimServerPort);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
connect(cimServerHost,cimServerPort);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void send(final SentBody body) {
|
||||
|
||||
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
|
||||
IoSession session = getCurrentSession();
|
||||
if(session!=null && session.isConnected())
|
||||
{
|
||||
WriteFuture wf = session.write(body);
|
||||
// 消息发送超时 10秒
|
||||
wf.awaitUninterruptibly(10, TimeUnit.SECONDS);
|
||||
|
||||
if (!wf.isWritten()) {
|
||||
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_FAILED);
|
||||
intent.putExtra("exception", new WriteToClosedSessionException());
|
||||
intent.putExtra("sentBody", body);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}else
|
||||
{
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_FAILED);
|
||||
intent.putExtra("exception", new CIMSessionDisableException());
|
||||
intent.putExtra("sentBody", body);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
IoSession session = getCurrentSession();
|
||||
if (session != null) {
|
||||
session.closeNow();
|
||||
session.removeAttribute("account");
|
||||
}
|
||||
|
||||
if (connector != null && !connector.isDisposed()) {
|
||||
connector.dispose();
|
||||
}
|
||||
manager = null;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
IoSession session = getCurrentSession();
|
||||
if (session == null ) {
|
||||
return false;
|
||||
}
|
||||
return session.isConnected() ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void closeSession()
|
||||
{
|
||||
IoSession session = getCurrentSession();
|
||||
if(session!=null)
|
||||
{
|
||||
session.closeNow();
|
||||
}
|
||||
}
|
||||
|
||||
public IoSession getCurrentSession()
|
||||
{
|
||||
if(connector.getManagedSessionCount()>0)
|
||||
{
|
||||
for(Long key:connector.getManagedSessions().keySet())
|
||||
{
|
||||
return connector.getManagedSessions().get(key);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setLastHeartbeatTime(IoSession session)
|
||||
{
|
||||
session.setAttribute(KEY_LAST_HEART_TIME, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private long getLastHeartbeatTime(IoSession session)
|
||||
{
|
||||
long time = 0;
|
||||
Object value ;
|
||||
if((value = session.getAttribute(KEY_LAST_HEART_TIME)) !=null){
|
||||
time = Long.parseLong(value.toString());
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getRequest(IoSession arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getResponse(IoSession arg0, Object arg1) {
|
||||
return CIMConstant.CMD_HEARTBEAT_RESPONSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequest(IoSession session, Object data) {
|
||||
|
||||
setLastHeartbeatTime(session);
|
||||
|
||||
return CIMConstant.CMD_HEARTBEAT_REQUEST.equalsIgnoreCase(data.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResponse(IoSession arg0, Object arg1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sessionCreated(IoSession session) throws Exception {
|
||||
|
||||
|
||||
logger.debug("******************CIM连接服务器成功:"+session.getLocalAddress());
|
||||
|
||||
setLastHeartbeatTime(session);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_CONNECTION_SUCCESSED);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionOpened(IoSession session) throws Exception {
|
||||
session.getConfig().setBothIdleTime(180);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionClosed(IoSession session) throws Exception {
|
||||
|
||||
logger.debug("******************CIM与服务器断开连接:"+session.getLocalAddress());
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_CONNECTION_CLOSED);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionIdle(IoSession session, IdleStatus status)throws Exception {
|
||||
logger.debug("******************CIM与服务器连接空闲:"+session.getLocalAddress() + " isActive:" + session.isActive()+ " isConnected:" + session.isConnected());
|
||||
|
||||
/**
|
||||
* 用于解决,wifi情况下。偶而路由器与服务器断开连接时,客户端并没及时收到关闭事件
|
||||
* 导致这样的情况下当前连接无效也不会重连的问题
|
||||
*
|
||||
*/
|
||||
long lastHeartbeatTime = getLastHeartbeatTime(session);
|
||||
if(System.currentTimeMillis() - lastHeartbeatTime >= HEARBEAT_TIME_OUT)
|
||||
{
|
||||
session.closeNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(IoSession session, Throwable cause)
|
||||
throws Exception {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_UNCAUGHT_EXCEPTION);
|
||||
intent.putExtra("exception", cause);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(IoSession session, Object obj)
|
||||
throws Exception {
|
||||
|
||||
logger.info(obj);
|
||||
|
||||
if (obj instanceof Message) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_MESSAGE_RECEIVED);
|
||||
intent.putExtra("message", (Message) obj);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
if (obj instanceof ReplyBody) {
|
||||
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_REPLY_RECEIVED);
|
||||
intent.putExtra("replyBody", (ReplyBody) obj);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageSent(IoSession session, Object message) throws Exception {
|
||||
if(message instanceof SentBody)
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_SUCCESSED);
|
||||
intent.putExtra("sentBody", (SentBody) message);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
logger.info(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inputClosed(IoSession arg0) throws Exception {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.exception.CIMSessionDisableException;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* 消息入口,所有消息都会经过这里
|
||||
*/
|
||||
public class CIMEventBroadcastReceiver {
|
||||
Random random = new Random();
|
||||
private static CIMEventBroadcastReceiver recerver;
|
||||
private CIMEventListener listener;
|
||||
private Timer connectionHandler = new Timer();;
|
||||
public static CIMEventBroadcastReceiver getInstance(){
|
||||
if (recerver==null){
|
||||
recerver = new CIMEventBroadcastReceiver();
|
||||
}
|
||||
return recerver;
|
||||
}
|
||||
|
||||
public void setGlobalCIMEventListener(CIMEventListener ls){
|
||||
listener = ls;
|
||||
}
|
||||
|
||||
|
||||
public void onReceive(Intent intent) {
|
||||
|
||||
|
||||
/*
|
||||
* cim断开服务器事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED))
|
||||
{
|
||||
onInnerConnectionClosed();
|
||||
}
|
||||
|
||||
/*
|
||||
* cim连接服务器失败事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED))
|
||||
{
|
||||
onInnerConnectionFailed((Exception) intent.getExtra("exception"));
|
||||
}
|
||||
|
||||
/*
|
||||
* cim连接服务器成功事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESSED))
|
||||
{
|
||||
onInnerConnectionSuccessed();
|
||||
}
|
||||
|
||||
/*
|
||||
* 收到推送消息事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED))
|
||||
{
|
||||
onInnerMessageReceived((Message)intent.getExtra("message"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取收到replybody成功事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_REPLY_RECEIVED))
|
||||
{
|
||||
listener.onReplyReceived((ReplyBody)intent.getExtra("replyBody"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取sendbody发送失败事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_SENT_FAILED))
|
||||
{
|
||||
onSentFailed((Exception) intent.getExtra("exception"),(SentBody)intent.getExtra("sentBody"));
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取sendbody发送成功事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESSED))
|
||||
{
|
||||
onSentSucceed((SentBody)intent.getExtra("sentBody"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取cim数据传输异常事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_UNCAUGHT_EXCEPTION))
|
||||
{
|
||||
onUncaughtException((Exception)intent.getExtra("exception"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 重新连接,如果断开的话
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_RECOVERY))
|
||||
{
|
||||
CIMPushManager.connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onInnerConnectionClosed(){
|
||||
|
||||
listener.onConnectionClosed();
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, false);
|
||||
CIMPushManager.connect();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void onInnerConnectionFailed(Exception e){
|
||||
|
||||
connectionHandler.schedule(new ConnectionTask(),random.nextInt(CIMConstant.RECONN_INTERVAL_TIME) + 20 );
|
||||
|
||||
listener.onConnectionFailed(e);
|
||||
}
|
||||
|
||||
private void onInnerConnectionSuccessed(){
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, true);
|
||||
|
||||
boolean autoBind = CIMPushManager.autoBindDeviceId();
|
||||
|
||||
listener.onConnectionSuccessed(autoBind);
|
||||
}
|
||||
|
||||
private void onUncaughtException(Throwable arg0) {}
|
||||
|
||||
|
||||
|
||||
|
||||
private void onInnerMessageReceived(com.farsunset.cim.sdk.client.model.Message message)
|
||||
{
|
||||
listener.onMessageReceived(message);
|
||||
}
|
||||
|
||||
private void onSentFailed(Exception e, SentBody body){
|
||||
|
||||
//与服务端端开链接,重新连接
|
||||
if(e instanceof CIMSessionDisableException)
|
||||
{
|
||||
CIMPushManager.connect();
|
||||
}else
|
||||
{
|
||||
//发送失败 重新发送
|
||||
CIMPushManager.sendRequest( body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void onSentSucceed(SentBody body){}
|
||||
|
||||
|
||||
|
||||
class ConnectionTask extends TimerTask{
|
||||
|
||||
public void run(){
|
||||
CIMPushManager.connect();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
|
||||
/**
|
||||
*CIM 主要事件接口
|
||||
*/
|
||||
public interface CIMEventListener
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 当收到服务端推送过来的消息时调用
|
||||
* @param message
|
||||
*/
|
||||
public abstract void onMessageReceived(Message message);
|
||||
|
||||
/**
|
||||
* 当调用CIMPushManager.sendRequest()向服务端发送请求,获得相应时调用
|
||||
* @param replybody
|
||||
*/
|
||||
public abstract void onReplyReceived(ReplyBody replybody);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 当连接服务器成功时回调
|
||||
* @param hasAutoBind : true 已经自动绑定账号到服务器了,不需要再手动调用bindAccount
|
||||
*/
|
||||
public abstract void onConnectionSuccessed(boolean hasAutoBind);
|
||||
|
||||
/**
|
||||
* 当断开服务器连接的时候回调
|
||||
*/
|
||||
public abstract void onConnectionClosed();
|
||||
|
||||
/**
|
||||
* 当服务器连接失败的时候回调
|
||||
*
|
||||
*/
|
||||
public abstract void onConnectionFailed(Exception e);
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
import java.util.ArrayList;
|
||||
import org.apache.log4j.Logger;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
|
||||
|
||||
/**
|
||||
* CIM 消息监听器管理
|
||||
*/
|
||||
public class CIMListenerManager {
|
||||
|
||||
private static ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>();
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(CIMListenerManager.class);
|
||||
|
||||
|
||||
public static void registerMessageListener(CIMEventListener listener) {
|
||||
|
||||
if (!cimListeners.contains(listener)) {
|
||||
cimListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void removeMessageListener(CIMEventListener listener) {
|
||||
for (int i = 0; i < cimListeners.size(); i++) {
|
||||
if (listener.getClass() == cimListeners.get(i).getClass()) {
|
||||
cimListeners.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionSuccessed(boolean antoBind) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionSuccessed(antoBind);
|
||||
}
|
||||
}
|
||||
public static void notifyOnMessageReceived(Message message) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onMessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionClosed() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionClosed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void notifyOnReplyReceived(ReplyBody body) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onReplyReceived(body);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionFailed(Exception e) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void destory() {
|
||||
cimListeners.clear();
|
||||
}
|
||||
|
||||
public static void logListenersName() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
logger.debug("#######" + listener.getClass().getName() + "#######" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* CIM 功能接口
|
||||
*/
|
||||
public class CIMPushManager {
|
||||
protected static final Logger logger = Logger.getLogger(CIMPushManager.class);
|
||||
static String ACTION_ACTIVATE_PUSH_SERVICE ="ACTION_ACTIVATE_PUSH_SERVICE";
|
||||
|
||||
static String ACTION_CREATE_CIM_CONNECTION ="ACTION_CREATE_CIM_CONNECTION";
|
||||
|
||||
static String ACTION_SEND_REQUEST_BODY ="ACTION_SEND_REQUEST_BODY";
|
||||
|
||||
static String ACTION_CLOSE_CIM_CONNECTION ="ACTION_CLOSE_CIM_CONNECTION";
|
||||
|
||||
static String ACTION_DESTORY ="ACTION_DESTORY";
|
||||
|
||||
static String KEY_SEND_BODY ="KEY_SEND_BODY";
|
||||
|
||||
static String KEY_CIM_CONNECTION_STATUS ="KEY_CIM_CONNECTION_STATUS";
|
||||
|
||||
//被销毁的destroy()
|
||||
public static final int STATE_DESTROYED = 0x0000DE;
|
||||
//被销停止的 stop()
|
||||
public static final int STATE_STOPED = 0x0000EE;
|
||||
|
||||
public static final int STATE_NORMAL = 0x000000;
|
||||
/**
|
||||
* 初始化,连接服务端,在程序启动页或者 在Application里调用
|
||||
* @param context
|
||||
* @param ip
|
||||
* @param port
|
||||
*/
|
||||
|
||||
public static void connect(String ip,int port){
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, false);
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
|
||||
|
||||
CIMCacheToolkit.getInstance().putString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
|
||||
CIMCacheToolkit.getInstance().putInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
|
||||
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
|
||||
serviceIntent.setAction(ACTION_CREATE_CIM_CONNECTION);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
private static void startService(Intent intent) {
|
||||
CIMPushService.getInstance().onStartCommand(intent);
|
||||
}
|
||||
|
||||
protected static void connect(){
|
||||
|
||||
boolean isManualStop = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
|
||||
if(isManualStop || isManualDestory)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
String host = CIMCacheToolkit.getInstance().getString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
|
||||
int port =CIMCacheToolkit.getInstance().getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
|
||||
|
||||
connect(host,port);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void sendBindRequest(String account){
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
|
||||
SentBody sent = new SentBody();
|
||||
Properties sysPro=System.getProperties();
|
||||
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
|
||||
sent.put("account", account);
|
||||
sent.put("deviceId", getLocalMac());
|
||||
sent.put("channel", sysPro.getProperty("os.name"));
|
||||
sent.put("device",getDeviceModel());
|
||||
sent.put("version",getClientVersion());
|
||||
sent.put("osVersion",sysPro.getProperty("os.version"));
|
||||
sendRequest(sent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个账号登录到服务端
|
||||
* @param account 用户唯一ID
|
||||
*/
|
||||
public static void bindAccount(String account){
|
||||
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory || account==null || account.trim().length()==0)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
sendBindRequest(account);
|
||||
|
||||
}
|
||||
|
||||
protected static boolean autoBindDeviceId(){
|
||||
|
||||
String account = getAccount();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
boolean isManualStoped = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
if( isManualStoped || account==null || account.trim().length()==0 || isManualDestory )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sendBindRequest(account);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 发送一个CIM请求
|
||||
* @param context
|
||||
* @body
|
||||
*/
|
||||
public static void sendRequest(SentBody body){
|
||||
|
||||
boolean isManualStop = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
|
||||
if(isManualStop || isManualDestory)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra(KEY_SEND_BODY, body);
|
||||
serviceIntent.setAction(ACTION_SEND_REQUEST_BODY);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止接受推送,将会退出当前账号登录,端口与服务端的连接
|
||||
* @param context
|
||||
*/
|
||||
public static void stop(){
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory){
|
||||
return ;
|
||||
}
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, true);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.setAction(ACTION_CLOSE_CIM_CONNECTION);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 完全销毁CIM,一般用于完全退出程序,调用resume将不能恢复
|
||||
* @param context
|
||||
*/
|
||||
public static void destroy(){
|
||||
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, true);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.setAction(ACTION_DESTORY);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重新恢复接收推送,重新连接服务端,并登录当前账号如果aotuBind == true
|
||||
* @param context
|
||||
* @param aotuBind
|
||||
*/
|
||||
public static void resume(){
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory){
|
||||
return ;
|
||||
}
|
||||
|
||||
autoBindDeviceId();
|
||||
}
|
||||
|
||||
public static boolean isConnected(){
|
||||
return CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE);
|
||||
}
|
||||
|
||||
public static int getState(){
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory){
|
||||
return STATE_DESTROYED;
|
||||
}
|
||||
|
||||
boolean isManualStop = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
if(isManualStop){
|
||||
return STATE_STOPED;
|
||||
}
|
||||
|
||||
return STATE_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
public static String getDeviceModel(){
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.DEVICE_MODEL);
|
||||
}
|
||||
|
||||
public static String getClientVersion(){
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_VERSION);
|
||||
}
|
||||
public static String getAccount(){
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_ACCOUNT);
|
||||
}
|
||||
public static void setAccount(String account){
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_ACCOUNT,account);
|
||||
}
|
||||
public static void setClientVersion(String version){
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_VERSION,version);
|
||||
}
|
||||
|
||||
public static void setDeviceModel(String model){
|
||||
System.getProperties().put(CIMConstant.ConfigKey.DEVICE_MODEL,model);
|
||||
}
|
||||
|
||||
private static String getLocalMac() {
|
||||
InetAddress ia;
|
||||
try {
|
||||
ia = InetAddress.getLocalHost();
|
||||
byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
|
||||
StringBuffer sb = new StringBuffer("");
|
||||
for(int i=0; i<mac.length; i++) {
|
||||
if(i!=0) {
|
||||
sb.append("-");
|
||||
}
|
||||
//字节转换为整数
|
||||
int temp = mac[i]&0xff;
|
||||
String str = Integer.toHexString(temp);
|
||||
if(str.length()==1) {
|
||||
sb.append("0"+str);
|
||||
}else {
|
||||
sb.append(str);
|
||||
}
|
||||
}
|
||||
return sb.toString().toUpperCase();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
|
||||
/**
|
||||
* 与服务端连接服务
|
||||
*
|
||||
*/
|
||||
public class CIMPushService {
|
||||
|
||||
protected final static int DEF_CIM_PORT = 28888;
|
||||
private CIMConnectorManager manager;
|
||||
|
||||
private static CIMPushService service;
|
||||
public static CIMPushService getInstance(){
|
||||
if (service==null){
|
||||
service = new CIMPushService();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
public CIMPushService()
|
||||
{
|
||||
manager = CIMConnectorManager.getManager();
|
||||
}
|
||||
|
||||
|
||||
public void onStartCommand(Intent intent) {
|
||||
|
||||
if(intent==null)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
String action = intent.getAction();
|
||||
|
||||
if(CIMPushManager.ACTION_CREATE_CIM_CONNECTION.equals(action))
|
||||
{
|
||||
String host = CIMCacheToolkit.getInstance().getString(CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
|
||||
int port =CIMCacheToolkit.getInstance().getInt(CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
|
||||
manager.connect(host,port);
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_SEND_REQUEST_BODY.equals(action))
|
||||
{
|
||||
manager.send((SentBody) intent.getExtra(CIMPushManager.KEY_SEND_BODY));
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_CLOSE_CIM_CONNECTION.equals(action))
|
||||
{
|
||||
manager.closeSession();
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_DESTORY.equals(action))
|
||||
{
|
||||
manager.destroy();
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action) && !manager.isConnected())
|
||||
{
|
||||
|
||||
String host = CIMCacheToolkit.getInstance().getString(CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
|
||||
int port =CIMCacheToolkit.getInstance().getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
|
||||
manager.connect(host,port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.constant;
|
||||
|
||||
/**
|
||||
* 常量
|
||||
*/
|
||||
public interface CIMConstant {
|
||||
|
||||
|
||||
public static String UTF8="UTF-8";
|
||||
|
||||
public static byte MESSAGE_SEPARATE='\b';
|
||||
|
||||
|
||||
//重连间隔随机数,在 30 -10 ----30+10 之间
|
||||
public static int RECONN_INTERVAL_TIME= 30 * 1000;
|
||||
|
||||
public static int CIM_DEFAULT_MESSAGE_ORDER=1;
|
||||
|
||||
|
||||
static class ConfigKey{
|
||||
|
||||
public static String DEVICE_MODEL ="client.model";
|
||||
public static String CLIENT_VERSION ="client.version";
|
||||
public static String CLIENT_ACCOUNT ="client.account";
|
||||
|
||||
}
|
||||
/**
|
||||
* 服务端心跳请求命令 cmd_server_hb_request
|
||||
*/
|
||||
public static final String CMD_HEARTBEAT_REQUEST="S_H_RQ";
|
||||
/**
|
||||
* 客户端心跳响应命令 cmd_client_hb_response
|
||||
*/
|
||||
public static final String CMD_HEARTBEAT_RESPONSE ="C_H_RS";
|
||||
|
||||
|
||||
public static class RequestKey{
|
||||
|
||||
|
||||
public static String CLIENT_BIND ="client_bind";
|
||||
|
||||
public static String CLIENT_OFFLINE_MESSAGE ="client_get_offline_message";
|
||||
|
||||
public static String CLIENT_CYCLE_LOCATION ="client_cycle_location";
|
||||
|
||||
public static String CLIENT_PUSH_MESSAGE ="client_push_message";
|
||||
|
||||
public static String CLIENT_EXECUTE_SCRIPT ="client_execute_script";
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.exception;
|
||||
|
||||
|
||||
public class CIMSessionDisableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CIMSessionDisableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CIMSessionDisableException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.exception;
|
||||
|
||||
|
||||
public class NetWorkDisableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NetWorkDisableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NetWorkDisableException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.exception;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public class WriteToClosedSessionException extends Exception implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public WriteToClosedSessionException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public WriteToClosedSessionException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.filter;
|
||||
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolCodecFactory;
|
||||
import org.apache.mina.filter.codec.ProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoder;
|
||||
|
||||
/**
|
||||
* android客户端端消息 编码解码器, 可以在
|
||||
* 关于消息加密与加密, 可在 encoder时进行消息加密,在ServerMessageCodecFactory的 decoder时对消息解密
|
||||
*/
|
||||
public class ClientMessageCodecFactory implements ProtocolCodecFactory {
|
||||
|
||||
private final ClientMessageEncoder encoder;
|
||||
|
||||
private final ClientMessageDecoder decoder;
|
||||
|
||||
public ClientMessageCodecFactory() {
|
||||
encoder = new ClientMessageEncoder();
|
||||
decoder = new ClientMessageDecoder();
|
||||
}
|
||||
|
||||
|
||||
public ProtocolEncoder getEncoder(IoSession session) {
|
||||
return encoder;
|
||||
}
|
||||
|
||||
|
||||
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
|
||||
return decoder;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.filter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.apache.mina.core.buffer.IoBuffer;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
|
||||
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
/**
|
||||
* 客户端消息解码
|
||||
*/
|
||||
public class ClientMessageDecoder extends CumulativeProtocolDecoder {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean doDecode(IoSession iosession, IoBuffer iobuffer,
|
||||
ProtocolDecoderOutput out) throws Exception {
|
||||
|
||||
IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true);
|
||||
|
||||
|
||||
boolean complete = false;
|
||||
|
||||
|
||||
iobuffer.mark();
|
||||
|
||||
|
||||
while (iobuffer.hasRemaining()) {
|
||||
byte b = iobuffer.get();
|
||||
/**
|
||||
* CIMConstant.MESSAGE_SEPARATE 为消息界限
|
||||
* 当一次收到多个消息时,以此分隔解析多个消息
|
||||
*/
|
||||
if (b == CIMConstant.MESSAGE_SEPARATE) {
|
||||
|
||||
complete = true;
|
||||
break;
|
||||
} else {
|
||||
buff.put(b);
|
||||
}
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
buff.flip();
|
||||
byte[] bytes = new byte[buff.limit()];
|
||||
buff.get(bytes);
|
||||
String message = new String(bytes, CIMConstant.UTF8);
|
||||
buff.clear();
|
||||
|
||||
try
|
||||
{
|
||||
Object msg = mappingMessageObject(message);
|
||||
out.write(msg);
|
||||
}catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}else{
|
||||
//读取了一部分发现消息没有结束,则重置为没有读取
|
||||
iobuffer.reset();
|
||||
}
|
||||
|
||||
return complete;
|
||||
}
|
||||
|
||||
private Object mappingMessageObject(String message) throws Exception {
|
||||
|
||||
|
||||
|
||||
|
||||
if(CIMConstant.CMD_HEARTBEAT_REQUEST.equalsIgnoreCase(message))
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = (Document) builder.parse(new ByteArrayInputStream(message.getBytes(CIMConstant.UTF8)));
|
||||
|
||||
String name = doc.getDocumentElement().getTagName();
|
||||
if (name.equals("reply")) {
|
||||
ReplyBody reply = new ReplyBody();
|
||||
reply.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
|
||||
reply.setCode(doc.getElementsByTagName("code").item(0).getTextContent());
|
||||
NodeList items = doc.getElementsByTagName("data").item(0).getChildNodes();
|
||||
for (int i = 0; i < items.getLength(); i++) {
|
||||
Node node = items.item(i);
|
||||
reply.getData().put(node.getNodeName(), node.getTextContent());
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
if (name.equals("message")) {
|
||||
|
||||
Message body = new Message();
|
||||
NodeList nodeList = doc.getElementsByTagName("message").item(0).getChildNodes();
|
||||
int count = nodeList.getLength();
|
||||
for(int i = 0;i < count; i++){
|
||||
Node node = nodeList.item(i);
|
||||
|
||||
if(node.getNodeName().equals("mid"))
|
||||
{
|
||||
body.setMid(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("type"))
|
||||
{
|
||||
body.setType(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("file"))
|
||||
{
|
||||
body.setFile(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("fileType"))
|
||||
{
|
||||
body.setFileType(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("content"))
|
||||
{
|
||||
body.setContent(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("sender"))
|
||||
{
|
||||
body.setSender(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("receiver"))
|
||||
{
|
||||
body.setReceiver(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("format"))
|
||||
{
|
||||
body.setFormat(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("timestamp"))
|
||||
{
|
||||
body.setTimestamp(Long.valueOf(node.getTextContent()));
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.filter;
|
||||
|
||||
|
||||
|
||||
import org.apache.mina.core.buffer.IoBuffer;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
|
||||
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
/**
|
||||
* 客户端消息发送前进行编码,可在此加密消息
|
||||
*/
|
||||
public class ClientMessageEncoder extends ProtocolEncoderAdapter {
|
||||
@Override
|
||||
public void encode(IoSession iosession, Object message, ProtocolEncoderOutput out) throws Exception {
|
||||
|
||||
IoBuffer buff = IoBuffer.allocate(320).setAutoExpand(true);
|
||||
buff.put(message.toString().getBytes(CIMConstant.UTF8));
|
||||
buff.put(CIMConstant.MESSAGE_SEPARATE);
|
||||
buff.flip();
|
||||
out.write(buff);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* java |android 客户端请求结构
|
||||
*
|
||||
*/
|
||||
public class Intent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String action;
|
||||
|
||||
private HashMap<String, Object> data = new HashMap<String, Object>();
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public void putExtra(String key , Object value){
|
||||
data.put(key, value);
|
||||
}
|
||||
public Object getExtra(String key){
|
||||
return data.get(key);
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* 消息对象
|
||||
*/
|
||||
public class Message implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/**
|
||||
* 消息类型,用户自定义消息类别
|
||||
*/
|
||||
private String mid;
|
||||
|
||||
|
||||
/**
|
||||
* 消息类型,用户自定义消息类别
|
||||
*/
|
||||
private String type;
|
||||
|
||||
private String content;
|
||||
|
||||
private String file;
|
||||
|
||||
private String fileType;
|
||||
/**
|
||||
* 消息发送者账号
|
||||
*/
|
||||
private String sender;
|
||||
/**
|
||||
* 消息发送者接收者
|
||||
*/
|
||||
private String receiver;
|
||||
|
||||
/**
|
||||
* content 内容格式
|
||||
*/
|
||||
private String format;
|
||||
|
||||
|
||||
private long timestamp;
|
||||
|
||||
|
||||
public Message()
|
||||
{
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public String getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public void setReceiver(String receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
public void setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
}
|
||||
public String toString() {
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<message>");
|
||||
buffer.append("<mid>").append(mid).append("</mid>");
|
||||
|
||||
if (isNotEmpty(type)) {
|
||||
buffer.append("<type>").append(type).append("</type>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(file)) {
|
||||
buffer.append("<file>").append(file).append("</file>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(fileType)) {
|
||||
buffer.append("<fileType>").append(fileType).append("</fileType>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(content)) {
|
||||
buffer.append("<content><![CDATA[").append(content).append("]]></content>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(sender)) {
|
||||
buffer.append("<sender>").append(sender).append("</sender>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(receiver)) {
|
||||
buffer.append("<receiver>").append(receiver).append("</receiver>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(format)) {
|
||||
buffer.append("<format>").append(format).append("</format>");
|
||||
}
|
||||
|
||||
if (timestamp > 0) {
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
}
|
||||
|
||||
buffer.append("</message>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toXmlString() {
|
||||
|
||||
return toString();
|
||||
}
|
||||
|
||||
public String getMid() {
|
||||
return mid;
|
||||
}
|
||||
|
||||
public void setMid(String mid) {
|
||||
this.mid = mid;
|
||||
}
|
||||
|
||||
public boolean isNotEmpty(String txt) {
|
||||
return txt != null && txt.trim().length()>0;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* 请求应答对象
|
||||
*
|
||||
*/
|
||||
public class ReplyBody implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 请求key
|
||||
*/
|
||||
private String key;
|
||||
|
||||
|
||||
/**
|
||||
* 返回码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 返回说明
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 返回数据集合
|
||||
*/
|
||||
private HashMap<String, String> data;
|
||||
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public ReplyBody()
|
||||
{
|
||||
data = new HashMap<String, String>();
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
data.put(k, v);
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public void remove(String k) {
|
||||
data.remove(k);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public HashMap<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<reply>");
|
||||
buffer.append("<key>").append(this.getKey()).append("</key>");
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
buffer.append("<code>").append(code).append("</code>");
|
||||
buffer.append("<data>");
|
||||
for(String key:this.getData().keySet())
|
||||
{
|
||||
buffer.append("<"+key+">").append(this.get(key)).append("</"+key+">");
|
||||
}
|
||||
buffer.append("</data>");
|
||||
buffer.append("</reply>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
public String toXmlString()
|
||||
{
|
||||
|
||||
return toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* java |android 客户端请求结构
|
||||
*
|
||||
*/
|
||||
public class SentBody implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String key;
|
||||
|
||||
private HashMap<String, String> data;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public SentBody() {
|
||||
|
||||
data = new HashMap<String, String>();
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
data.put(k, v);
|
||||
}
|
||||
|
||||
public void remove(String k) {
|
||||
data.remove(k);
|
||||
}
|
||||
|
||||
public HashMap<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<sent>");
|
||||
buffer.append("<key>").append(key).append("</key>");
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
buffer.append("<data>");
|
||||
for (String key : data.keySet()) {
|
||||
buffer.append("<" + key + "><![CDATA[").append(data.get(key)).append("]]></" + key + ">");
|
||||
}
|
||||
buffer.append("</data>");
|
||||
buffer.append("</sent>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toXmlString() {
|
||||
|
||||
return toString();
|
||||
}
|
||||
}
|
@ -62,7 +62,7 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
|
||||
|
||||
String message = new String(bytes, CIMConstant.UTF8);
|
||||
|
||||
logger.debug(message);
|
||||
logger.info(message);
|
||||
|
||||
tBuffer.clear();
|
||||
try{
|
||||
@ -72,7 +72,7 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
|
||||
}catch(Exception e){
|
||||
out.write(message);//解析xml失败 是返回原始的xml数据到上层处理,比如flex sokcet的 安全验证请求xml
|
||||
e.printStackTrace();
|
||||
logger.warn(e.getMessage());
|
||||
logger.error(e);
|
||||
}
|
||||
}else
|
||||
{
|
||||
@ -89,6 +89,11 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
|
||||
return CIMConstant.CMD_HEARTBEAT_RESPONSE;
|
||||
}
|
||||
|
||||
if(CIMConstant.FLEX_POLICY_REQUEST.equalsIgnoreCase(message))
|
||||
{
|
||||
return CIMConstant.FLEX_POLICY_REQUEST;
|
||||
}
|
||||
|
||||
SentBody body = new SentBody();
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
|
@ -98,7 +98,6 @@ public class CIMIoHandler extends IoHandlerAdapter {
|
||||
*/
|
||||
public void exceptionCaught(IoSession session, Throwable cause)
|
||||
throws Exception {
|
||||
logger.error("exceptionCaught()... from "+session.getRemoteAddress());
|
||||
logger.error(cause);
|
||||
cause.printStackTrace();
|
||||
}
|
||||
|
@ -19,7 +19,6 @@
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/antlr-2.7.6.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/asm.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/aspectjweaver.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/cim-server-sdk-2.1.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-fileupload-1.2.1.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-io-2.4.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-lang-2.3.jar"/>
|
||||
@ -38,5 +37,6 @@
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/struts2-core-2.1.8.1.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/xstream-1.3.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/xwork-core-2.1.6.jar"/>
|
||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/cim-server-sdk-2.2.jar"/>
|
||||
<classpathentry kind="output" path="WebRoot/WEB-INF/classes"/>
|
||||
</classpath>
|
||||
|
Binary file not shown.
@ -72,15 +72,21 @@
|
||||
<img src="<%=headerBasePath%>/resource/img/icon.png" style="margin-top: 35px;height: 80px;height: 80px;"/>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
CIM即时通讯后台管理系统
|
||||
<li class="list-group-item" style="border-radius: 0px;">
|
||||
CIM是一个提供于二次开发的即时通信解决方案,可实现基于移动应用,桌面端应用或者系统应用之间的实时消息推送。
|
||||
<p/><p/>项目主页地址<br/><a target="_blank" href="http://git.oschina.net/farsunset/cim">http://git.oschina.net/farsunset/cim</a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
Email:3979434@qq.com
|
||||
|
||||
<li class="list-group-item" style="border-radius: 0px;">
|
||||
作者:远方夕阳
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
QQ:3979434
|
||||
<li class="list-group-item" style="border-radius: 0px;">
|
||||
Q Q:3979434
|
||||
</li>
|
||||
<li class="list-group-item" style="border-radius: 0px;">
|
||||
微信:farbluesky
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,8 +12,7 @@
|
||||
<li style="height: 50px; text-align: center; margin-top: 10px;">
|
||||
<div class="btn-group" style="margin-top: 5px;">
|
||||
<a type="button" class="btn btn-danger" target="_blank"
|
||||
href="javascript:openWebclient();">CIM for
|
||||
Web(测试版)</a>
|
||||
href="javascript:openWebclient();">CIM for Web</a>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/css/table.css" />
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/bootstrap/css/bootstrap.min.css" />
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/css/dialog.css" />
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/jquery-1.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/jquery-2.2.3.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/framework.js"></script>
|
||||
<script>
|
||||
@ -169,7 +169,7 @@ onclick="showMessageDialog('<%=ios.getAccount() %>')">发送消息</button>
|
||||
</div>
|
||||
<div class="form-groupBuy" style="margin-top: 20px;">
|
||||
<label for="exampleInputFile">消息内容:</label>
|
||||
<textarea rows="10" style="width: 100%;height: 120px;" id="message" name="message" class="form-control"></textarea>
|
||||
<textarea rows="10" style="width: 100%;height: 200px;resize: none;" id="message" name="message" class="form-control"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -179,15 +179,6 @@ onclick="showMessageDialog('<%=ios.getAccount() %>')">发送消息</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel panel-primary gdialog" id="scanDownloadDialog" style="display: none;width: 300px;position: absolute;z-index: 1001;">
|
||||
<div class="panel-heading">二维码下载
|
||||
<a class="close" onclick="doHideDialog('scanDownloadDialog'),$('#scanDownloadDialog').css('z-index',1000);">×</a>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<img src = "<%=basePath%>/resource/img/scan_download.png"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#sessionMenu').addClass('current');
|
||||
|
||||
|
Binary file not shown.
@ -4,7 +4,6 @@
|
||||
String basePath = request.getScheme() + "://"
|
||||
+ request.getServerName() + ":" + request.getServerPort()
|
||||
+ path;
|
||||
|
||||
%>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
@ -13,13 +12,13 @@
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>ICHAT for web(beta) </title>
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/bootstrap/css/bootstrap.min.css" />
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/css/dialog.css" />
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/jquery-1.8.3.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/framework.js"></script>
|
||||
<script type="text/javascript" src="cim.js"></script>
|
||||
</head>
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/bootstrap/css/bootstrap.min.css" />
|
||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/css/dialog.css" />
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/jquery-2.2.3.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="<%=basePath%>/resource/js/framework.js"></script>
|
||||
<script type="text/javascript" src="cim.js"></script>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
@ -41,11 +40,11 @@
|
||||
|
||||
|
||||
|
||||
|
||||
/** 当socket连接成功回调 **/
|
||||
function sessionCreated()
|
||||
{
|
||||
document.getElementById("CIMBridge").setAccount(ACCOUNT,ACCOUNT);
|
||||
//使用session id作为唯一标示,区分同一设备的多个用户
|
||||
document.getElementById("CIMBridge").bindAccount(ACCOUNT,"<%=session.getId()%>");
|
||||
}
|
||||
|
||||
/** 当socket断开是回调 **/
|
||||
@ -71,16 +70,16 @@
|
||||
|
||||
/** 当收到消息时候回调 **/
|
||||
|
||||
function onMessageReceived(data,content)
|
||||
function onMessageReceived(data)
|
||||
{
|
||||
|
||||
|
||||
var message = JSON.parse(data);
|
||||
|
||||
if(message.type=='2')
|
||||
{
|
||||
document.getElementById("CIMBridge").playSound();
|
||||
message.content = content;
|
||||
$("#messageList").append("<div class='alert alert-info' >"+content+"</div>");
|
||||
document.getElementById("CIMBridge").playSound("dingdong.mp3");
|
||||
var line = "<div class='alert alert-info' id ="+message.timestamp+" STYLE='white-space: nowrap; overflow: hidden; text-overflow: ellipsis;'></div>";
|
||||
$("#messageList").append(line);
|
||||
$("#"+message.timestamp).text(message.content);
|
||||
}
|
||||
|
||||
|
||||
@ -101,36 +100,27 @@
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<script language="Javascript">
|
||||
document.oncontextmenu = function (){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
window.onload=function()
|
||||
{
|
||||
window.onload=function()
|
||||
{
|
||||
window.onkeydown=function(e)
|
||||
{
|
||||
if(e.which)
|
||||
if(e.which && e.which==116)
|
||||
{
|
||||
if(e.which==116)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if(event.keyCode)
|
||||
if(event.keyCode && event.keyCode==116)
|
||||
{
|
||||
if(event.keyCode==116)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body style="background-color: rgb(190, 209, 216);width: 600px;">
|
||||
<object type="application/x-shockwave-flash" data="CIMBridge.swf" id="CIMBridge" width="0" height="0">
|
||||
<param name="quality" value="low"/>
|
||||
|
File diff suppressed because one or more lines are too long
4
cim_for_mina/cim-server/WebRoot/resource/js/jquery-2.2.3.min.js
vendored
Normal file
4
cim_for_mina/cim-server/WebRoot/resource/js/jquery-2.2.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -26,12 +26,15 @@ public class SessionClosedHandler implements CIMRequestHandler {
|
||||
|
||||
public ReplyBody process(CIMSession ios, SentBody message) {
|
||||
|
||||
Object account =ios.getAttribute(CIMConstant.SESSION_KEY);
|
||||
if(account == null){
|
||||
return null;
|
||||
}
|
||||
DefaultSessionManager sessionManager = ((DefaultSessionManager) ContextHolder.getBean("CIMSessionManager"));
|
||||
|
||||
String account =ios.getAttribute(CIMConstant.SESSION_KEY).toString();
|
||||
ios.removeAttribute(CIMConstant.SESSION_KEY);
|
||||
ios.closeNow();
|
||||
sessionManager.remove(account);
|
||||
sessionManager.remove(account.toString());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
1.1.0
|
@ -180,13 +180,10 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
android.os.Message msg = new android.os.Message();
|
||||
msg.getData().putSerializable("body", body);
|
||||
|
||||
if(channel!=null && channel.isActive())
|
||||
{
|
||||
boolean isDone = channel.writeAndFlush(body).awaitUninterruptibly(5000);
|
||||
boolean isDone = channel.writeAndFlush(body).awaitUninterruptibly(10000);
|
||||
if (!isDone) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
|
@ -7,6 +7,8 @@
|
||||
package com.farsunset.cim.sdk.android.filter;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.serialization.ClassResolver;
|
||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||
@ -38,31 +40,35 @@ public class ClientMessageDecoder extends ObjectDecoder {
|
||||
@Override
|
||||
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
||||
|
||||
int length = buffer.readableBytes();
|
||||
buffer.markReaderIndex();
|
||||
final ByteBuf tBuffer = PooledByteBufAllocator.DEFAULT.buffer(640);
|
||||
|
||||
/**
|
||||
* CIMConstant.MESSAGE_SEPARATE 为消息界限
|
||||
* 当一次收到多个消息时,以此分隔解析多个消息
|
||||
*/
|
||||
if (buffer.isReadable()&& length > 0 && CIMConstant.MESSAGE_SEPARATE == buffer.getByte(length-1)) {
|
||||
|
||||
byte[] data = new byte[length-1];
|
||||
buffer.readBytes(data);
|
||||
String message = new String(new String(data,CIMConstant.UTF8));
|
||||
Log.i(ClientMessageDecoder.class.getSimpleName(), message.toString());
|
||||
//将末尾的消息分隔符读取掉
|
||||
buffer.readByte();
|
||||
|
||||
Object msg = mappingMessageObject(message);
|
||||
|
||||
data = null;
|
||||
message = null;
|
||||
return msg;
|
||||
buffer.markReaderIndex();
|
||||
boolean complete = false;
|
||||
|
||||
while(buffer.isReadable()){
|
||||
byte b = buffer.readByte();
|
||||
if (b == CIMConstant.MESSAGE_SEPARATE) {
|
||||
complete = true;
|
||||
break;
|
||||
} else {
|
||||
tBuffer.writeByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.resetReaderIndex();
|
||||
return null;
|
||||
|
||||
if(complete){
|
||||
|
||||
String message = new String(new String(ByteBufUtil.getBytes(tBuffer),CIMConstant.UTF8));
|
||||
Log.i("ClientMessageDecoder", message);
|
||||
Object msg = mappingMessageObject(message);
|
||||
return msg;
|
||||
|
||||
}else{
|
||||
|
||||
buffer.resetReaderIndex();
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Object mappingMessageObject(String message) throws Exception {
|
||||
|
12
cim_for_netty/cim-java-sdk/.classpath
Normal file
12
cim_for_netty/cim-java-sdk/.classpath
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-buffer-4.1.0.CR7.jar"/>
|
||||
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-codec-4.1.0.CR7.jar"/>
|
||||
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-common-4.1.0.CR7.jar"/>
|
||||
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-handler-4.1.0.CR7.jar"/>
|
||||
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-transport-4.1.0.CR7.jar"/>
|
||||
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-resolver-4.1.0.CR7.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
23
cim_for_netty/cim-java-sdk/.project
Normal file
23
cim_for_netty/cim-java-sdk/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>cim-java-sdk</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>com.genuitec.eclipse.ast.deploy.core.DeploymentBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.genuitec.eclipse.ast.deploy.core.deploymentnature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -0,0 +1,3 @@
|
||||
#Wed Oct 15 09:31:41 CST 2014
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
class CIMCacheToolkit {
|
||||
|
||||
private static HashMap<String,String> CIM_CONFIG_INFO = new HashMap<String,String>();
|
||||
|
||||
public static final String KEY_MANUAL_STOP = "KEY_MANUAL_STOP";
|
||||
|
||||
public static final String KEY_CIM_DESTROYED = "KEY_CIM_DESTROYED";
|
||||
|
||||
public static final String KEY_CIM_SERVIER_HOST = "KEY_CIM_SERVIER_HOST";
|
||||
|
||||
public static final String KEY_CIM_SERVIER_PORT = "KEY_CIM_SERVIER_PORT";
|
||||
|
||||
public static final String KEY_CIM_CONNECTION_STATE = "KEY_CIM_CONNECTION_STATE";
|
||||
|
||||
static CIMCacheToolkit toolkit;
|
||||
public static CIMCacheToolkit getInstance(){
|
||||
if (toolkit==null){
|
||||
toolkit = new CIMCacheToolkit();
|
||||
}
|
||||
return toolkit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void remove(String key)
|
||||
{
|
||||
CIM_CONFIG_INFO.remove(key);
|
||||
}
|
||||
|
||||
|
||||
public void putString(String key,String value)
|
||||
{
|
||||
CIM_CONFIG_INFO.put(key,value);
|
||||
|
||||
}
|
||||
|
||||
public String getString(String key)
|
||||
{
|
||||
return CIM_CONFIG_INFO.get(key);
|
||||
}
|
||||
|
||||
public void putBoolean(String key,boolean value)
|
||||
{
|
||||
putString(key,Boolean.toString(value));
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key)
|
||||
{
|
||||
String value = getString(key);
|
||||
return value == null?false:Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
|
||||
public void putInt(String key,int value)
|
||||
{
|
||||
putString(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
public int getInt(String key)
|
||||
{
|
||||
String value = getString(key);
|
||||
return value == null?0:Integer.parseInt(value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,315 @@
|
||||
/**
|
||||
* probject:cim-server-sdk
|
||||
* @version 2.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.serialization.ClassResolvers;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.exception.CIMSessionDisableException;
|
||||
import com.farsunset.cim.sdk.client.exception.WriteToClosedSessionException;
|
||||
import com.farsunset.cim.sdk.client.filter.ClientMessageDecoder;
|
||||
import com.farsunset.cim.sdk.client.filter.ClientMessageEncoder;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* 连接服务端管理,cim核心处理类,管理连接,以及消息处理
|
||||
*/
|
||||
@io.netty.channel.ChannelHandler.Sharable
|
||||
class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
|
||||
|
||||
private Channel channel;;
|
||||
|
||||
|
||||
Bootstrap bootstrap;
|
||||
EventLoopGroup loopGroup ;
|
||||
static CIMConnectorManager manager;
|
||||
|
||||
// 消息广播action
|
||||
public static final String ACTION_MESSAGE_RECEIVED = "com.farsunset.cim.MESSAGE_RECEIVED";
|
||||
|
||||
// 发送sendbody失败广播
|
||||
public static final String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED";
|
||||
|
||||
// 发送sendbody成功广播
|
||||
public static final String ACTION_SENT_SUCCESSED = "com.farsunset.cim.SENT_SUCCESSED";
|
||||
// 链接意外关闭广播
|
||||
public static final String ACTION_CONNECTION_CLOSED = "com.farsunset.cim.CONNECTION_CLOSED";
|
||||
// 链接失败广播
|
||||
public static final String ACTION_CONNECTION_FAILED = "com.farsunset.cim.CONNECTION_FAILED";
|
||||
// 链接成功广播
|
||||
public static final String ACTION_CONNECTION_SUCCESSED = "com.farsunset.cim.CONNECTION_SUCCESSED";
|
||||
// 发送sendbody成功后获得replaybody回应广播
|
||||
public static final String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED";
|
||||
// 网络变化广播
|
||||
public static final String ACTION_NETWORK_CHANGED = "android.net.conn.CONNECTIVITY_CHANGE";
|
||||
|
||||
// 未知异常
|
||||
public static final String ACTION_UNCAUGHT_EXCEPTION = "com.farsunset.cim.UNCAUGHT_EXCEPTION";
|
||||
|
||||
//重试连接
|
||||
public final static String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
|
||||
|
||||
private ExecutorService executor;
|
||||
public static final String HEARTBEAT_PINGED ="HEARTBEAT_PINGED";
|
||||
//连接空闲时间
|
||||
public static final int READ_IDLE_TIME = 180;//秒
|
||||
|
||||
//心跳超时
|
||||
public static final int HEART_TIME_OUT = 30 * 1000;//秒
|
||||
|
||||
private CIMConnectorManager() {
|
||||
executor = Executors.newCachedThreadPool();
|
||||
bootstrap = new Bootstrap();
|
||||
loopGroup = new NioEventLoopGroup();
|
||||
bootstrap.group(loopGroup);
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
bootstrap.option(ChannelOption.TCP_NODELAY, true);
|
||||
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeline.addLast(new ClientMessageDecoder(ClassResolvers.cacheDisabled(CIMConnectorManager.class.getClassLoader())));
|
||||
pipeline.addLast(new ClientMessageEncoder());
|
||||
pipeline.addLast(new IdleStateHandler(READ_IDLE_TIME,0,0));
|
||||
pipeline.addLast(CIMConnectorManager.this);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public synchronized static CIMConnectorManager getManager() {
|
||||
if (manager == null) {
|
||||
manager = new CIMConnectorManager();
|
||||
}
|
||||
return manager;
|
||||
|
||||
}
|
||||
|
||||
private synchronized void syncConnection(final String cimServerHost,final int cimServerPort) {
|
||||
try {
|
||||
|
||||
if(isConnected()){
|
||||
return ;
|
||||
}
|
||||
ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(cimServerHost, cimServerPort)).sync(); //这里的IP和端口,根据自己情况修改
|
||||
channel = channelFuture.channel();
|
||||
} catch (Exception e) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_CONNECTION_FAILED);
|
||||
intent.putExtra("exception", e);
|
||||
sendBroadcast(intent);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void connect(final String cimServerHost, final int cimServerPort) {
|
||||
|
||||
|
||||
Future<?> future = executor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
syncConnection(cimServerHost, cimServerPort);
|
||||
}
|
||||
});
|
||||
try {
|
||||
if(future.get()!=null)
|
||||
{
|
||||
connect(cimServerHost,cimServerPort);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
connect(cimServerHost,cimServerPort);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void send(final SentBody body) {
|
||||
|
||||
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
|
||||
if(channel!=null && channel.isActive())
|
||||
{
|
||||
boolean isDone = channel.writeAndFlush(body).awaitUninterruptibly(5000);
|
||||
if (!isDone) {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_FAILED);
|
||||
intent.putExtra("exception", new WriteToClosedSessionException());
|
||||
intent.putExtra("sentBody", body);
|
||||
sendBroadcast(intent);
|
||||
}else
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_SUCCESSED);
|
||||
intent.putExtra("sentBody", body);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}else
|
||||
{
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_SENT_FAILED);
|
||||
intent.putExtra("exception", new CIMSessionDisableException());
|
||||
intent.putExtra("sentBody", body);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (manager.channel != null) {
|
||||
manager.channel.close();
|
||||
}
|
||||
loopGroup.shutdownGracefully();
|
||||
manager = null;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
if (channel == null) {
|
||||
return false;
|
||||
}
|
||||
return channel.isActive() ;
|
||||
}
|
||||
|
||||
|
||||
public void closeSession()
|
||||
{
|
||||
if(channel!=null)
|
||||
{
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检测到连接空闲事件,发送心跳请求命令
|
||||
*/
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
if (evt instanceof IdleStateEvent && ((IdleStateEvent) evt).state().equals(IdleState.READER_IDLE))
|
||||
{
|
||||
onReaderIdeled(ctx.channel());
|
||||
}
|
||||
super.userEventTriggered(ctx, evt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void onReaderIdeled(Channel channel){
|
||||
|
||||
//如果心跳请求发出30秒内没收到响应,则关闭连接
|
||||
Long lastTime = (Long) channel.attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).get();
|
||||
if(lastTime != null && System.currentTimeMillis() - lastTime > HEART_TIME_OUT)
|
||||
{
|
||||
channel.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive( ChannelHandlerContext ctx) throws Exception {
|
||||
|
||||
System.out.println("******************CIM连接服务器成功:"+ctx.channel().localAddress());
|
||||
|
||||
ctx.channel().attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).set(System.currentTimeMillis());
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_CONNECTION_SUCCESSED);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
|
||||
System.out.println("******************closeCIM与服务器断开连接:"+ctx.channel().localAddress());
|
||||
if(channel.id().asLongText().equals(ctx.channel().id().asLongText()))
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_CONNECTION_CLOSED);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_UNCAUGHT_EXCEPTION);
|
||||
intent.putExtra("exception", cause.getCause());
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof Message) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_MESSAGE_RECEIVED);
|
||||
intent.putExtra("message", (Message) msg);
|
||||
sendBroadcast(intent);
|
||||
|
||||
}
|
||||
if (msg instanceof ReplyBody) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(ACTION_REPLY_RECEIVED);
|
||||
intent.putExtra("replyBody", (ReplyBody) msg);
|
||||
sendBroadcast(intent);
|
||||
}
|
||||
|
||||
//收到服务端发来的心跳请求命令,则马上回应服务器
|
||||
if (msg.equals(CIMConstant.CMD_HEARTBEAT_REQUEST)) {
|
||||
ctx.writeAndFlush(CIMConstant.CMD_HEARTBEAT_RESPONSE);
|
||||
ctx.channel().attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).set(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sendBroadcast(final Intent intent) {
|
||||
executor.execute(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
CIMEventBroadcastReceiver.getInstance().onReceive(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.exception.CIMSessionDisableException;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* 消息入口,所有消息都会经过这里
|
||||
*/
|
||||
public class CIMEventBroadcastReceiver {
|
||||
Random random = new Random();
|
||||
private static CIMEventBroadcastReceiver recerver;
|
||||
private CIMEventListener listener;
|
||||
private Timer connectionHandler = new Timer();;
|
||||
public static CIMEventBroadcastReceiver getInstance(){
|
||||
if (recerver==null){
|
||||
recerver = new CIMEventBroadcastReceiver();
|
||||
}
|
||||
return recerver;
|
||||
}
|
||||
|
||||
public void setGlobalCIMEventListener(CIMEventListener ls){
|
||||
listener = ls;
|
||||
}
|
||||
|
||||
|
||||
public void onReceive(Intent intent) {
|
||||
|
||||
|
||||
/*
|
||||
* cim断开服务器事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED))
|
||||
{
|
||||
onInnerConnectionClosed();
|
||||
}
|
||||
|
||||
/*
|
||||
* cim连接服务器失败事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED))
|
||||
{
|
||||
onInnerConnectionFailed((Exception) intent.getExtra("exception"));
|
||||
}
|
||||
|
||||
/*
|
||||
* cim连接服务器成功事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESSED))
|
||||
{
|
||||
onInnerConnectionSuccessed();
|
||||
}
|
||||
|
||||
/*
|
||||
* 收到推送消息事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED))
|
||||
{
|
||||
onInnerMessageReceived((Message)intent.getExtra("message"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取收到replybody成功事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_REPLY_RECEIVED))
|
||||
{
|
||||
listener.onReplyReceived((ReplyBody)intent.getExtra("replyBody"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取sendbody发送失败事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_SENT_FAILED))
|
||||
{
|
||||
onSentFailed((Exception) intent.getExtra("exception"),(SentBody)intent.getExtra("sentBody"));
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取sendbody发送成功事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESSED))
|
||||
{
|
||||
onSentSucceed((SentBody)intent.getExtra("sentBody"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 获取cim数据传输异常事件
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_UNCAUGHT_EXCEPTION))
|
||||
{
|
||||
onUncaughtException((Exception)intent.getExtra("exception"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 重新连接,如果断开的话
|
||||
*/
|
||||
if(intent.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_RECOVERY))
|
||||
{
|
||||
CIMPushManager.connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onInnerConnectionClosed(){
|
||||
|
||||
listener.onConnectionClosed();
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, false);
|
||||
CIMPushManager.connect();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void onInnerConnectionFailed(Exception e){
|
||||
|
||||
connectionHandler.schedule(new ConnectionTask(),random.nextInt(CIMConstant.RECONN_INTERVAL_TIME) + 20 );
|
||||
|
||||
listener.onConnectionFailed(e);
|
||||
}
|
||||
|
||||
private void onInnerConnectionSuccessed(){
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, true);
|
||||
|
||||
boolean autoBind = CIMPushManager.autoBindDeviceId();
|
||||
|
||||
listener.onConnectionSuccessed(autoBind);
|
||||
}
|
||||
|
||||
private void onUncaughtException(Throwable arg0) {}
|
||||
|
||||
|
||||
|
||||
|
||||
private void onInnerMessageReceived(com.farsunset.cim.sdk.client.model.Message message)
|
||||
{
|
||||
listener.onMessageReceived(message);
|
||||
}
|
||||
|
||||
private void onSentFailed(Exception e, SentBody body){
|
||||
|
||||
//与服务端端开链接,重新连接
|
||||
if(e instanceof CIMSessionDisableException)
|
||||
{
|
||||
CIMPushManager.connect();
|
||||
}else
|
||||
{
|
||||
//发送失败 重新发送
|
||||
CIMPushManager.sendRequest( body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void onSentSucceed(SentBody body){}
|
||||
|
||||
|
||||
|
||||
class ConnectionTask extends TimerTask{
|
||||
|
||||
public void run(){
|
||||
CIMPushManager.connect();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
|
||||
/**
|
||||
*CIM 主要事件接口
|
||||
*/
|
||||
public interface CIMEventListener
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 当收到服务端推送过来的消息时调用
|
||||
* @param message
|
||||
*/
|
||||
public abstract void onMessageReceived(Message message);
|
||||
|
||||
/**
|
||||
* 当调用CIMPushManager.sendRequest()向服务端发送请求,获得相应时调用
|
||||
* @param replybody
|
||||
*/
|
||||
public abstract void onReplyReceived(ReplyBody replybody);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 当连接服务器成功时回调
|
||||
* @param hasAutoBind : true 已经自动绑定账号到服务器了,不需要再手动调用bindAccount
|
||||
*/
|
||||
public abstract void onConnectionSuccessed(boolean hasAutoBind);
|
||||
|
||||
/**
|
||||
* 当断开服务器连接的时候回调
|
||||
*/
|
||||
public abstract void onConnectionClosed();
|
||||
|
||||
/**
|
||||
* 当服务器连接失败的时候回调
|
||||
*
|
||||
*/
|
||||
public abstract void onConnectionFailed(Exception e);
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
import java.util.ArrayList;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
|
||||
|
||||
/**
|
||||
* CIM 消息监听器管理
|
||||
*/
|
||||
public class CIMListenerManager {
|
||||
|
||||
private static ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>();
|
||||
|
||||
|
||||
|
||||
public static void registerMessageListener(CIMEventListener listener) {
|
||||
|
||||
if (!cimListeners.contains(listener)) {
|
||||
cimListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void removeMessageListener(CIMEventListener listener) {
|
||||
for (int i = 0; i < cimListeners.size(); i++) {
|
||||
if (listener.getClass() == cimListeners.get(i).getClass()) {
|
||||
cimListeners.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionSuccessed(boolean antoBind) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionSuccessed(antoBind);
|
||||
}
|
||||
}
|
||||
public static void notifyOnMessageReceived(Message message) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onMessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionClosed() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionClosed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void notifyOnReplyReceived(ReplyBody body) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onReplyReceived(body);
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyOnConnectionFailed(Exception e) {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
listener.onConnectionFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void destory() {
|
||||
cimListeners.clear();
|
||||
}
|
||||
|
||||
public static void logListenersName() {
|
||||
for (CIMEventListener listener : cimListeners) {
|
||||
System.out.println("#######" + listener.getClass().getName() + "#######" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
/**
|
||||
* CIM 功能接口
|
||||
*/
|
||||
public class CIMPushManager {
|
||||
static String ACTION_ACTIVATE_PUSH_SERVICE ="ACTION_ACTIVATE_PUSH_SERVICE";
|
||||
|
||||
static String ACTION_CREATE_CIM_CONNECTION ="ACTION_CREATE_CIM_CONNECTION";
|
||||
|
||||
static String ACTION_SEND_REQUEST_BODY ="ACTION_SEND_REQUEST_BODY";
|
||||
|
||||
static String ACTION_CLOSE_CIM_CONNECTION ="ACTION_CLOSE_CIM_CONNECTION";
|
||||
|
||||
static String ACTION_DESTORY ="ACTION_DESTORY";
|
||||
|
||||
static String KEY_SEND_BODY ="KEY_SEND_BODY";
|
||||
|
||||
static String KEY_CIM_CONNECTION_STATUS ="KEY_CIM_CONNECTION_STATUS";
|
||||
|
||||
//被销毁的destroy()
|
||||
public static final int STATE_DESTROYED = 0x0000DE;
|
||||
//被销停止的 stop()
|
||||
public static final int STATE_STOPED = 0x0000EE;
|
||||
|
||||
public static final int STATE_NORMAL = 0x000000;
|
||||
/**
|
||||
* 初始化,连接服务端,在程序启动页或者 在Application里调用
|
||||
* @param context
|
||||
* @param ip
|
||||
* @param port
|
||||
*/
|
||||
|
||||
public static void connect(String ip,int port){
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, false);
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
|
||||
|
||||
CIMCacheToolkit.getInstance().putString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
|
||||
CIMCacheToolkit.getInstance().putInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
|
||||
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
|
||||
serviceIntent.setAction(ACTION_CREATE_CIM_CONNECTION);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
private static void startService(Intent intent) {
|
||||
CIMPushService.getInstance().onStartCommand(intent);
|
||||
}
|
||||
|
||||
protected static void connect(){
|
||||
|
||||
boolean isManualStop = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
|
||||
if(isManualStop || isManualDestory)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
String host = CIMCacheToolkit.getInstance().getString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
|
||||
int port =CIMCacheToolkit.getInstance().getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
|
||||
|
||||
connect(host,port);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void sendBindRequest(String account){
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
|
||||
SentBody sent = new SentBody();
|
||||
Properties sysPro=System.getProperties();
|
||||
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
|
||||
sent.put("account", account);
|
||||
sent.put("deviceId", getLocalMac());
|
||||
sent.put("channel", sysPro.getProperty("os.name"));
|
||||
sent.put("device",getDeviceModel());
|
||||
sent.put("version",getClientVersion());
|
||||
sent.put("osVersion",sysPro.getProperty("os.version"));
|
||||
sendRequest(sent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个账号登录到服务端
|
||||
* @param account 用户唯一ID
|
||||
*/
|
||||
public static void bindAccount(String account){
|
||||
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory || account==null || account.trim().length()==0)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
sendBindRequest(account);
|
||||
|
||||
}
|
||||
|
||||
protected static boolean autoBindDeviceId(){
|
||||
|
||||
String account = getAccount();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
boolean isManualStoped = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
if( isManualStoped || account==null || account.trim().length()==0 || isManualDestory )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sendBindRequest(account);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 发送一个CIM请求
|
||||
* @param context
|
||||
* @body
|
||||
*/
|
||||
public static void sendRequest(SentBody body){
|
||||
|
||||
boolean isManualStop = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
|
||||
if(isManualStop || isManualDestory)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.putExtra(KEY_SEND_BODY, body);
|
||||
serviceIntent.setAction(ACTION_SEND_REQUEST_BODY);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止接受推送,将会退出当前账号登录,端口与服务端的连接
|
||||
* @param context
|
||||
*/
|
||||
public static void stop(){
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory){
|
||||
return ;
|
||||
}
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, true);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.setAction(ACTION_CLOSE_CIM_CONNECTION);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 完全销毁CIM,一般用于完全退出程序,调用resume将不能恢复
|
||||
* @param context
|
||||
*/
|
||||
public static void destroy(){
|
||||
|
||||
|
||||
CIMCacheToolkit.getInstance().putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, true);
|
||||
|
||||
Intent serviceIntent = new Intent();
|
||||
serviceIntent.setAction(ACTION_DESTORY);
|
||||
startService(serviceIntent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重新恢复接收推送,重新连接服务端,并登录当前账号如果aotuBind == true
|
||||
* @param context
|
||||
* @param aotuBind
|
||||
*/
|
||||
public static void resume(){
|
||||
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory){
|
||||
return ;
|
||||
}
|
||||
|
||||
autoBindDeviceId();
|
||||
}
|
||||
|
||||
public static boolean isConnected(){
|
||||
return CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE);
|
||||
}
|
||||
|
||||
public static int getState(){
|
||||
boolean isManualDestory = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
|
||||
if(isManualDestory){
|
||||
return STATE_DESTROYED;
|
||||
}
|
||||
|
||||
boolean isManualStop = CIMCacheToolkit.getInstance().getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
|
||||
if(isManualStop){
|
||||
return STATE_STOPED;
|
||||
}
|
||||
|
||||
return STATE_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
public static String getDeviceModel(){
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.DEVICE_MODEL);
|
||||
}
|
||||
|
||||
public static String getClientVersion(){
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_VERSION);
|
||||
}
|
||||
public static String getAccount(){
|
||||
return System.getProperties().getProperty(CIMConstant.ConfigKey.CLIENT_ACCOUNT);
|
||||
}
|
||||
public static void setAccount(String account){
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_ACCOUNT,account);
|
||||
}
|
||||
public static void setClientVersion(String version){
|
||||
System.getProperties().put(CIMConstant.ConfigKey.CLIENT_VERSION,version);
|
||||
}
|
||||
|
||||
public static void setDeviceModel(String model){
|
||||
System.getProperties().put(CIMConstant.ConfigKey.DEVICE_MODEL,model);
|
||||
}
|
||||
|
||||
private static String getLocalMac() {
|
||||
InetAddress ia;
|
||||
try {
|
||||
ia = InetAddress.getLocalHost();
|
||||
byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
|
||||
StringBuffer sb = new StringBuffer("");
|
||||
for(int i=0; i<mac.length; i++) {
|
||||
if(i!=0) {
|
||||
sb.append("-");
|
||||
}
|
||||
//字节转换为整数
|
||||
int temp = mac[i]&0xff;
|
||||
String str = Integer.toHexString(temp);
|
||||
if(str.length()==1) {
|
||||
sb.append("0"+str);
|
||||
}else {
|
||||
sb.append(str);
|
||||
}
|
||||
}
|
||||
return sb.toString().toUpperCase();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client;
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.model.Intent;
|
||||
import com.farsunset.cim.sdk.client.model.SentBody;
|
||||
|
||||
|
||||
/**
|
||||
* 与服务端连接服务
|
||||
*
|
||||
*/
|
||||
public class CIMPushService {
|
||||
|
||||
protected final static int DEF_CIM_PORT = 28888;
|
||||
private CIMConnectorManager manager;
|
||||
|
||||
private static CIMPushService service;
|
||||
public static CIMPushService getInstance(){
|
||||
if (service==null){
|
||||
service = new CIMPushService();
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
public CIMPushService()
|
||||
{
|
||||
manager = CIMConnectorManager.getManager();
|
||||
}
|
||||
|
||||
|
||||
public void onStartCommand(Intent intent) {
|
||||
|
||||
if(intent==null)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
String action = intent.getAction();
|
||||
|
||||
if(CIMPushManager.ACTION_CREATE_CIM_CONNECTION.equals(action))
|
||||
{
|
||||
String host = CIMCacheToolkit.getInstance().getString(CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
|
||||
int port =CIMCacheToolkit.getInstance().getInt(CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
|
||||
manager.connect(host,port);
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_SEND_REQUEST_BODY.equals(action))
|
||||
{
|
||||
manager.send((SentBody) intent.getExtra(CIMPushManager.KEY_SEND_BODY));
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_CLOSE_CIM_CONNECTION.equals(action))
|
||||
{
|
||||
manager.closeSession();
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_DESTORY.equals(action))
|
||||
{
|
||||
manager.destroy();
|
||||
}
|
||||
|
||||
if(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action) && !manager.isConnected())
|
||||
{
|
||||
|
||||
String host = CIMCacheToolkit.getInstance().getString(CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
|
||||
int port =CIMCacheToolkit.getInstance().getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
|
||||
manager.connect(host,port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.constant;
|
||||
|
||||
/**
|
||||
* 常量
|
||||
*/
|
||||
public interface CIMConstant {
|
||||
|
||||
|
||||
public static String UTF8="UTF-8";
|
||||
|
||||
public static byte MESSAGE_SEPARATE='\b';
|
||||
|
||||
|
||||
//重连间隔随机数,在 30 -10 ----30+10 之间
|
||||
public static int RECONN_INTERVAL_TIME= 30 * 1000;
|
||||
|
||||
public static int CIM_DEFAULT_MESSAGE_ORDER=1;
|
||||
|
||||
|
||||
static class ConfigKey{
|
||||
|
||||
public static String DEVICE_MODEL ="client.model";
|
||||
public static String CLIENT_VERSION ="client.version";
|
||||
public static String CLIENT_ACCOUNT ="client.account";
|
||||
|
||||
}
|
||||
/**
|
||||
* 服务端心跳请求命令 cmd_server_hb_request
|
||||
*/
|
||||
public static final String CMD_HEARTBEAT_REQUEST="S_H_RQ";
|
||||
/**
|
||||
* 客户端心跳响应命令 cmd_client_hb_response
|
||||
*/
|
||||
public static final String CMD_HEARTBEAT_RESPONSE ="C_H_RS";
|
||||
|
||||
|
||||
public static class RequestKey{
|
||||
|
||||
|
||||
public static String CLIENT_BIND ="client_bind";
|
||||
|
||||
public static String CLIENT_OFFLINE_MESSAGE ="client_get_offline_message";
|
||||
|
||||
public static String CLIENT_CYCLE_LOCATION ="client_cycle_location";
|
||||
|
||||
public static String CLIENT_PUSH_MESSAGE ="client_push_message";
|
||||
|
||||
public static String CLIENT_EXECUTE_SCRIPT ="client_execute_script";
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.exception;
|
||||
|
||||
|
||||
public class CIMSessionDisableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CIMSessionDisableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CIMSessionDisableException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.exception;
|
||||
|
||||
|
||||
public class NetWorkDisableException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public NetWorkDisableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NetWorkDisableException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.exception;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public class WriteToClosedSessionException extends Exception implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public WriteToClosedSessionException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public WriteToClosedSessionException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/**
|
||||
* probject:cim-server-sdk
|
||||
* @version 2.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.filter;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.serialization.ClassResolver;
|
||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.client.model.Message;
|
||||
import com.farsunset.cim.sdk.client.model.ReplyBody;
|
||||
|
||||
/**
|
||||
* 客户端消息解码
|
||||
*/
|
||||
public class ClientMessageDecoder extends ObjectDecoder {
|
||||
|
||||
|
||||
public ClientMessageDecoder(ClassResolver classResolver) {
|
||||
super(classResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
||||
|
||||
final ByteBuf tBuffer = PooledByteBufAllocator.DEFAULT.buffer(640);
|
||||
|
||||
buffer.markReaderIndex();
|
||||
boolean complete = false;
|
||||
|
||||
while(buffer.isReadable()){
|
||||
byte b = buffer.readByte();
|
||||
if (b == CIMConstant.MESSAGE_SEPARATE) {
|
||||
complete = true;
|
||||
break;
|
||||
} else {
|
||||
tBuffer.writeByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(complete){
|
||||
|
||||
String message = new String(new String(ByteBufUtil.getBytes(tBuffer),CIMConstant.UTF8));
|
||||
Object msg = mappingMessageObject(message);
|
||||
return msg;
|
||||
|
||||
}else{
|
||||
|
||||
buffer.resetReaderIndex();
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private Object mappingMessageObject(String message) throws Exception {
|
||||
|
||||
if(message.equals(CIMConstant.CMD_HEARTBEAT_REQUEST)){//如果是心跳请求命令则直接返回
|
||||
|
||||
return CIMConstant.CMD_HEARTBEAT_REQUEST;
|
||||
}
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = (Document) builder.parse(new ByteArrayInputStream(message.getBytes(CIMConstant.UTF8)));
|
||||
|
||||
String name = doc.getDocumentElement().getTagName();
|
||||
if (name.equals("reply")) {
|
||||
ReplyBody reply = new ReplyBody();
|
||||
reply.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
|
||||
reply.setCode(doc.getElementsByTagName("code").item(0).getTextContent());
|
||||
NodeList items = doc.getElementsByTagName("data").item(0).getChildNodes();
|
||||
for (int i = 0; i < items.getLength(); i++) {
|
||||
Node node = items.item(i);
|
||||
reply.getData().put(node.getNodeName(), node.getTextContent());
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
if (name.equals("message")) {
|
||||
|
||||
Message body = new Message();
|
||||
NodeList nodeList = doc.getElementsByTagName("message").item(0).getChildNodes();
|
||||
int count = nodeList.getLength();
|
||||
for(int i = 0;i < count; i++){
|
||||
Node node = nodeList.item(i);
|
||||
|
||||
if(node.getNodeName().equals("mid")){
|
||||
|
||||
body.setMid(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("type")){
|
||||
|
||||
body.setType(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("content")){
|
||||
|
||||
body.setContent(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("file")){
|
||||
|
||||
body.setFile(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("fileType")){
|
||||
|
||||
body.setFileType(node.getTextContent());
|
||||
}
|
||||
|
||||
|
||||
if(node.getNodeName().equals("sender")){
|
||||
|
||||
body.setSender(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("receiver")){
|
||||
|
||||
body.setReceiver(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("format")){
|
||||
|
||||
body.setFormat(node.getTextContent());
|
||||
}
|
||||
|
||||
if(node.getNodeName().equals("timestamp")){
|
||||
|
||||
body.setTimestamp(Long.valueOf(node.getTextContent()));
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* probject:cim-server-sdk
|
||||
* @version 2.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.filter;
|
||||
|
||||
|
||||
|
||||
import com.farsunset.cim.sdk.client.constant.CIMConstant;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 客户端消息发送前进行编码,可在此加密消息
|
||||
*
|
||||
*/
|
||||
public class ClientMessageEncoder extends MessageToByteEncoder<Object> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Object message, ByteBuf out) throws Exception {
|
||||
out.writeBytes(message.toString().getBytes(CIMConstant.UTF8));
|
||||
out.writeByte(CIMConstant.MESSAGE_SEPARATE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* java |android 客户端请求结构
|
||||
*
|
||||
*/
|
||||
public class Intent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String action;
|
||||
|
||||
private HashMap<String, Object> data = new HashMap<String, Object>();
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public void putExtra(String key , Object value){
|
||||
data.put(key, value);
|
||||
}
|
||||
public Object getExtra(String key){
|
||||
return data.get(key);
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
/**
|
||||
* 消息对象
|
||||
*/
|
||||
public class Message implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
/**
|
||||
* 消息类型,用户自定义消息类别
|
||||
*/
|
||||
private String mid;
|
||||
|
||||
|
||||
/**
|
||||
* 消息类型,用户自定义消息类别
|
||||
*/
|
||||
private String type;
|
||||
|
||||
private String content;
|
||||
|
||||
private String file;
|
||||
|
||||
private String fileType;
|
||||
/**
|
||||
* 消息发送者账号
|
||||
*/
|
||||
private String sender;
|
||||
/**
|
||||
* 消息发送者接收者
|
||||
*/
|
||||
private String receiver;
|
||||
|
||||
/**
|
||||
* content 内容格式
|
||||
*/
|
||||
private String format;
|
||||
|
||||
|
||||
private long timestamp;
|
||||
|
||||
|
||||
public Message()
|
||||
{
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public String getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public void setReceiver(String receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
public void setFile(String file) {
|
||||
this.file = file;
|
||||
}
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
public void setFileType(String fileType) {
|
||||
this.fileType = fileType;
|
||||
}
|
||||
public String toString() {
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<message>");
|
||||
buffer.append("<mid>").append(mid).append("</mid>");
|
||||
|
||||
if (isNotEmpty(type)) {
|
||||
buffer.append("<type>").append(type).append("</type>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(file)) {
|
||||
buffer.append("<file>").append(file).append("</file>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(fileType)) {
|
||||
buffer.append("<fileType>").append(fileType).append("</fileType>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(content)) {
|
||||
buffer.append("<content><![CDATA[").append(content).append("]]></content>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(sender)) {
|
||||
buffer.append("<sender>").append(sender).append("</sender>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(receiver)) {
|
||||
buffer.append("<receiver>").append(receiver).append("</receiver>");
|
||||
}
|
||||
|
||||
if (isNotEmpty(format)) {
|
||||
buffer.append("<format>").append(format).append("</format>");
|
||||
}
|
||||
|
||||
if (timestamp > 0) {
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
}
|
||||
|
||||
buffer.append("</message>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toXmlString() {
|
||||
|
||||
return toString();
|
||||
}
|
||||
|
||||
public String getMid() {
|
||||
return mid;
|
||||
}
|
||||
|
||||
public void setMid(String mid) {
|
||||
this.mid = mid;
|
||||
}
|
||||
|
||||
public boolean isNotEmpty(String txt) {
|
||||
return txt != null && txt.trim().length()>0;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* 请求应答对象
|
||||
*
|
||||
*/
|
||||
public class ReplyBody implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 请求key
|
||||
*/
|
||||
private String key;
|
||||
|
||||
|
||||
/**
|
||||
* 返回码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 返回说明
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 返回数据集合
|
||||
*/
|
||||
private HashMap<String, String> data;
|
||||
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public ReplyBody()
|
||||
{
|
||||
data = new HashMap<String, String>();
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
data.put(k, v);
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public void remove(String k) {
|
||||
data.remove(k);
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public HashMap<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<reply>");
|
||||
buffer.append("<key>").append(this.getKey()).append("</key>");
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
buffer.append("<code>").append(code).append("</code>");
|
||||
buffer.append("<data>");
|
||||
for(String key:this.getData().keySet())
|
||||
{
|
||||
buffer.append("<"+key+">").append(this.get(key)).append("</"+key+">");
|
||||
}
|
||||
buffer.append("</data>");
|
||||
buffer.append("</reply>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
public String toXmlString()
|
||||
{
|
||||
|
||||
return toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* probject:cim-java-sdk
|
||||
* @version 2.0.0
|
||||
*
|
||||
* @author 3979434@qq.com
|
||||
*/
|
||||
package com.farsunset.cim.sdk.client.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
/**
|
||||
* java |android 客户端请求结构
|
||||
*
|
||||
*/
|
||||
public class SentBody implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String key;
|
||||
|
||||
private HashMap<String, String> data;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
public SentBody() {
|
||||
|
||||
data = new HashMap<String, String>();
|
||||
timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String get(String k) {
|
||||
return data.get(k);
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public void put(String k, String v) {
|
||||
data.put(k, v);
|
||||
}
|
||||
|
||||
public void remove(String k) {
|
||||
data.remove(k);
|
||||
}
|
||||
|
||||
public HashMap<String, String> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
buffer.append("<sent>");
|
||||
buffer.append("<key>").append(key).append("</key>");
|
||||
buffer.append("<timestamp>").append(timestamp).append("</timestamp>");
|
||||
buffer.append("<data>");
|
||||
for (String key : data.keySet()) {
|
||||
buffer.append("<" + key + "><![CDATA[").append(data.get(key)).append("]]></" + key + ">");
|
||||
}
|
||||
buffer.append("</data>");
|
||||
buffer.append("</sent>");
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toXmlString() {
|
||||
|
||||
return toString();
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ public interface CIMConstant {
|
||||
public static final String HEARTBEAT_KEY ="heartbeat";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FLEX 客户端socket请求发的安全策略请求,需要特殊处理,返回安全验证报文
|
||||
*/
|
||||
|
@ -7,6 +7,8 @@
|
||||
package com.farsunset.cim.sdk.server.filter;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.serialization.ClassResolver;
|
||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||
@ -33,75 +35,68 @@ public class ServerMessageDecoder extends ObjectDecoder {
|
||||
@Override
|
||||
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
||||
|
||||
|
||||
int length = buffer.readableBytes();
|
||||
final ByteBuf tBuffer = PooledByteBufAllocator.DEFAULT.buffer(320);
|
||||
|
||||
buffer.markReaderIndex();
|
||||
/**
|
||||
* CIMConstant.MESSAGE_SEPARATE 为消息界限
|
||||
* 当一次收到多个消息时,以此分隔解析多个消息
|
||||
*/
|
||||
if (buffer.isReadable()&&length > 0 && CIMConstant.MESSAGE_SEPARATE == buffer.getByte(length-1)) {
|
||||
boolean complete = false;
|
||||
|
||||
while(buffer.isReadable()){
|
||||
byte b = buffer.readByte();
|
||||
if (b == CIMConstant.MESSAGE_SEPARATE || b == CIMConstant.FLEX_DATA_SEPARATE) {
|
||||
complete = true;
|
||||
break;
|
||||
} else {
|
||||
tBuffer.writeByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
if(complete){
|
||||
|
||||
String message = new String(new String(ByteBufUtil.getBytes(tBuffer),CIMConstant.UTF8));
|
||||
|
||||
logger.info(message);
|
||||
|
||||
byte[] data = new byte[length-1];
|
||||
buffer.readBytes(data);
|
||||
String message = new String(new String(data,CIMConstant.UTF8));
|
||||
logger.debug(message);
|
||||
buffer.readByte();
|
||||
|
||||
Object body = parserMessageToSentBody(message);
|
||||
data = null;
|
||||
message = null;
|
||||
return body;
|
||||
return body;
|
||||
|
||||
}else{
|
||||
|
||||
buffer.resetReaderIndex();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* CIMConstant.FLEX_DATA_SEPARATE 为FLEX客户端socket验证消息界限
|
||||
*
|
||||
*/
|
||||
if (buffer.isReadable()&& length > 0 && CIMConstant.FLEX_DATA_SEPARATE == buffer.getByte(length-1)) {
|
||||
|
||||
byte[] data = new byte[length-1];
|
||||
buffer.readBytes(data);
|
||||
String message = new String(new String(data,CIMConstant.UTF8));
|
||||
//将末尾的消息分隔符读取掉
|
||||
buffer.readByte();
|
||||
data = null;
|
||||
|
||||
|
||||
/**
|
||||
* flex 客户端安全策略请求,需要返回特定报文
|
||||
*/
|
||||
if(CIMConstant.FLEX_POLICY_REQUEST.equals(message))
|
||||
{
|
||||
SentBody body = new SentBody();
|
||||
body.setKey(CIMConstant.RequestKey.CLIENT_FLASH_POLICY);
|
||||
return body;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
buffer.resetReaderIndex();
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private Object parserMessageToSentBody(String message) throws Exception
|
||||
{
|
||||
|
||||
SentBody body = new SentBody();
|
||||
if(message.equals(CIMConstant.CMD_HEARTBEAT_RESPONSE))//如果是心跳响应,则让HeartbeatHandler去处理
|
||||
{
|
||||
/*
|
||||
* 如果是心跳响应,则让HeartbeatHandler去处理
|
||||
*/
|
||||
if(message.equalsIgnoreCase(CIMConstant.CMD_HEARTBEAT_RESPONSE)){
|
||||
|
||||
body.setKey(CIMConstant.RequestKey.CLIENT_HEARTBEAT);
|
||||
return body;
|
||||
}
|
||||
|
||||
/*
|
||||
* flex 客户端安全策略请求,需要返回特定报文
|
||||
*/
|
||||
if(CIMConstant.FLEX_POLICY_REQUEST.equalsIgnoreCase(message)){
|
||||
|
||||
body.setKey(CIMConstant.RequestKey.CLIENT_FLASH_POLICY);
|
||||
return body;
|
||||
}
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new ByteArrayInputStream(message.toString().getBytes(CIMConstant.UTF8)));
|
||||
body.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
|
||||
NodeList dataNodeList = doc.getElementsByTagName("data");
|
||||
if(dataNodeList!=null && dataNodeList.getLength()>0)
|
||||
{
|
||||
if(dataNodeList!=null && dataNodeList.getLength()>0){
|
||||
|
||||
NodeList items = dataNodeList.item(0).getChildNodes();
|
||||
for (int i = 0; i < items.getLength(); i++) {
|
||||
Node node = items.item(i);
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
package com.farsunset.cim.sdk.server.handler;
|
||||
|
||||
import com.farsunset.cim.sdk.server.constant.CIMConstant;
|
||||
import com.farsunset.cim.sdk.server.model.ReplyBody;
|
||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||
import com.farsunset.cim.sdk.server.session.CIMSession;
|
||||
@ -22,8 +21,8 @@ public class HeartbeatHandler implements CIMRequestHandler {
|
||||
|
||||
public ReplyBody process(CIMSession session, SentBody message) {
|
||||
|
||||
//收到心跳响应,清除发送心跳请求标记
|
||||
session.removeAttribute(CIMConstant.RequestKey.CLIENT_HEARTBEAT);
|
||||
//收到心跳响应,设置心跳时间
|
||||
session.setHeartbeat(System.currentTimeMillis());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>{
|
||||
|
||||
public static final int PING_TIME_OUT = 30;//心跳响应 超时为30秒
|
||||
|
||||
public static final String HEARTBEAT_PINGED ="HEARTBEAT_PINGED";
|
||||
|
||||
|
||||
public void bind()
|
||||
{
|
||||
@ -94,7 +94,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>{
|
||||
public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause)
|
||||
throws Exception {
|
||||
logger.error(ctx.channel().remoteAddress());
|
||||
|
||||
logger.error(cause);
|
||||
}
|
||||
|
||||
|
||||
@ -118,20 +118,19 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>{
|
||||
|
||||
|
||||
private void onWriterIdeled(Channel channel){
|
||||
channel.attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).set(System.currentTimeMillis());
|
||||
channel.attr(AttributeKey.valueOf(CIMConstant.HEARTBEAT_KEY)).set(System.currentTimeMillis());
|
||||
channel.writeAndFlush(CIMConstant.CMD_HEARTBEAT_REQUEST);
|
||||
}
|
||||
|
||||
private void onReaderIdeled(Channel channel){
|
||||
Long lastTime = (Long) channel.attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).get();
|
||||
if(lastTime == null || System.currentTimeMillis() - lastTime >= PING_TIME_OUT)
|
||||
Long lastTime = (Long) channel.attr(AttributeKey.valueOf(CIMConstant.HEARTBEAT_KEY)).get();
|
||||
if(lastTime != null && System.currentTimeMillis() - lastTime >= PING_TIME_OUT)
|
||||
{
|
||||
channel.close();
|
||||
CIMRequestHandler handler = handlers.get(CIMConstant.RequestKey.KEY_CLIENT_CIMSESSION_CLOSED);
|
||||
handler.process(new CIMSession(channel), null);
|
||||
}
|
||||
|
||||
channel.attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).set(null);
|
||||
channel.attr(AttributeKey.valueOf(CIMConstant.HEARTBEAT_KEY)).set(null);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user