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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<projectDescription>
|
<projectDescription>
|
||||||
<name>CIMBridge</name>
|
<name>CIMFlashBridge</name>
|
||||||
<comment></comment>
|
<comment></comment>
|
||||||
<projects>
|
<projects>
|
||||||
</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.display.Sprite;
|
||||||
import flash.events.Event;
|
import flash.events.Event;
|
||||||
import flash.events.IOErrorEvent;
|
|
||||||
import flash.events.ProgressEvent;
|
import flash.events.ProgressEvent;
|
||||||
import flash.events.SecurityErrorEvent;
|
|
||||||
import flash.events.TimerEvent;
|
|
||||||
import flash.external.ExternalInterface;
|
import flash.external.ExternalInterface;
|
||||||
import flash.net.Socket;
|
|
||||||
import flash.system.Security;
|
|
||||||
import flash.utils.Timer;
|
|
||||||
import flash.media.Sound;
|
import flash.media.Sound;
|
||||||
|
import flash.net.Socket;
|
||||||
import flash.net.URLRequest;
|
import flash.net.URLRequest;
|
||||||
|
import flash.system.Security;
|
||||||
|
|
||||||
public class CIMBridge extends Sprite
|
public class CIMBridge extends Sprite
|
||||||
{
|
{
|
||||||
@ -19,22 +15,23 @@ package
|
|||||||
internal var CIM_PORT:String = "23456";
|
internal var CIM_PORT:String = "23456";
|
||||||
internal var socket:Socket;
|
internal var socket:Socket;
|
||||||
internal var froceOffline :Boolean = false;
|
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";
|
internal const CMD_HEARTBEAT_REQUEST:String="S_H_RQ";
|
||||||
/**
|
/**
|
||||||
* 客户端心跳响应命令 cmd_client_hb_response
|
* 客户端心跳响应命令
|
||||||
*/
|
*/
|
||||||
internal const CMD_HEARTBEAT_RESPONSE:String ="C_H_RS";
|
internal const CMD_HEARTBEAT_RESPONSE:String ="C_H_RS";
|
||||||
|
|
||||||
|
internal var mBuffer :String = '\b';
|
||||||
|
|
||||||
public function CIMBridge()
|
public function CIMBridge()
|
||||||
{
|
{
|
||||||
|
|
||||||
ExternalInterface.addCallback("connect",connect);
|
ExternalInterface.addCallback("connect",connect);
|
||||||
ExternalInterface.addCallback("setAccount",setAccount);
|
ExternalInterface.addCallback("bindAccount",bindAccount);
|
||||||
ExternalInterface.addCallback("getOfflineMessage",getOfflineMessage);
|
ExternalInterface.addCallback("getOfflineMessage",getOfflineMessage);
|
||||||
ExternalInterface.addCallback("logout",logout);
|
ExternalInterface.addCallback("logout",logout);
|
||||||
ExternalInterface.addCallback("playSound",playSound);
|
ExternalInterface.addCallback("playSound",playSound);
|
||||||
@ -47,20 +44,17 @@ package
|
|||||||
|
|
||||||
CIM_HOST = host;
|
CIM_HOST = host;
|
||||||
var policyfile:String="xmlsocket://"+CIM_HOST+":"+CIM_PORT;
|
var policyfile:String="xmlsocket://"+CIM_HOST+":"+CIM_PORT;
|
||||||
Security.loadPolicyFile(policyfile);
|
Security.loadPolicyFile(policyfile);//加载安全策略文件,得到相应的返回才会创建连接
|
||||||
socket=new Socket();
|
socket=new Socket();
|
||||||
socket.addEventListener(Event.CONNECT,sessionCreated);//监听是否连接上服务器
|
socket.addEventListener(Event.CONNECT,sessionCreated);//监听是否连接上服务器
|
||||||
socket.addEventListener(Event.CLOSE,sessionClosed);//监听套接字连接是否关闭
|
socket.addEventListener(Event.CLOSE,sessionClosed);//监听套接字连接是否关闭
|
||||||
socket.addEventListener(IOErrorEvent.IO_ERROR,exceptionCaught);
|
socket.addEventListener(ProgressEvent.SOCKET_DATA,messageReceived); //监听服务器消息
|
||||||
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityErrorFun);
|
|
||||||
//监听服务器新信息
|
|
||||||
socket.addEventListener(ProgressEvent.SOCKET_DATA,messageReceived);
|
|
||||||
|
|
||||||
socket.connect(CIM_HOST,parseInt(CIM_PORT));//连接服务器
|
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\"?>";
|
var xml:String="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||||
xml+="<sent>";
|
xml+="<sent>";
|
||||||
@ -68,10 +62,10 @@ package
|
|||||||
xml+="<data>";
|
xml+="<data>";
|
||||||
xml+="<account>"+account+"</account>";
|
xml+="<account>"+account+"</account>";
|
||||||
xml+="<deviceId>"+deviceId+"</deviceId>";
|
xml+="<deviceId>"+deviceId+"</deviceId>";
|
||||||
xml+="<channel>web</channel>";
|
xml+="<channel>browse</channel>";
|
||||||
xml+="<device>flash</device>";
|
xml+="<device>Flash</device>";
|
||||||
xml+="<version>2.0.0</version>";
|
xml+="<version>2.0.0</version>";
|
||||||
xml+="<osVersion>"+flash.system.Capabilities.version+"</osVersion>";
|
xml+="<osVersion>"+flash.system.Capabilities.os+"</osVersion>";
|
||||||
xml+="</data>";
|
xml+="</data>";
|
||||||
xml+="</sent>";
|
xml+="</sent>";
|
||||||
|
|
||||||
@ -118,44 +112,18 @@ package
|
|||||||
connect(CIM_HOST);
|
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{
|
||||||
|
|
||||||
/**接受服务器信息*/
|
if(message.toUpperCase() == CMD_HEARTBEAT_REQUEST)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
send(CMD_HEARTBEAT_RESPONSE);
|
send(CMD_HEARTBEAT_RESPONSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var xml:XML=XML(msg);
|
var xml:XML=XML(message);
|
||||||
var data:Object = xml as Object;
|
|
||||||
if(xml.name()=="reply"){
|
if(xml.name()=="reply"){
|
||||||
ExternalInterface.call("onReplyReceived",ReplyBody.mappingToJSON(xml));
|
ExternalInterface.call("onReplyReceived",ReplyBody.mappingToJSON(xml));
|
||||||
}
|
}
|
||||||
@ -167,7 +135,28 @@ package
|
|||||||
froceOffline = true;
|
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
|
internal function send(msg:String):void
|
||||||
{
|
{
|
||||||
//新建一个ByteArray来存放数据
|
//新建一个ByteArray来存放数据
|
||||||
socket.writeUTFBytes(msg+"\b");
|
socket.writeUTFBytes(msg+MESSAGE_SEPARATE);
|
||||||
//调用flush方法发送信息
|
//调用flush方法发送信息
|
||||||
socket.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);
|
_sound.play(1);
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +64,7 @@ package
|
|||||||
message.file = xml["file"];
|
message.file = xml["file"];
|
||||||
message.fileType = xml["fileType"];
|
message.fileType = xml["fileType"];
|
||||||
message.timestamp = xml["timestamp"];
|
message.timestamp = xml["timestamp"];
|
||||||
message.content = "";
|
message.content =xml["content"];
|
||||||
return com.adobe.serialization.json.JSON.encode(message).toString();
|
return com.adobe.serialization.json.JSON.encode(message).toString();
|
||||||
}
|
}
|
||||||
|
|
@ -3,26 +3,29 @@ package
|
|||||||
{
|
{
|
||||||
import com.adobe.serialization.json.JSON;
|
import com.adobe.serialization.json.JSON;
|
||||||
|
|
||||||
|
|
||||||
public class ReplyBody
|
public class ReplyBody
|
||||||
{
|
{
|
||||||
public var key:String;
|
public var key:String;
|
||||||
public var code:String;
|
public var code:String;
|
||||||
public var message:String;
|
public var message:String;
|
||||||
public var data:Object;
|
public var data:Object = new Object();
|
||||||
public var timestamp:Number;
|
public var timestamp:Number;
|
||||||
|
|
||||||
|
public static function mappingToJSON(xml:XML):String
|
||||||
|
|
||||||
public static function mappingToJSON(xml:XML):Object
|
|
||||||
{
|
{
|
||||||
var body:ReplyBody = new ReplyBody();
|
var body:ReplyBody = new ReplyBody();
|
||||||
body.key = xml["key"];
|
body.key = xml["key"];
|
||||||
body.code = xml["code"];
|
body.code = xml["code"];
|
||||||
body.timestamp = xml["timestamp"];
|
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);
|
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
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
android.os.Message msg = new android.os.Message();
|
|
||||||
msg.getData().putSerializable("body", body);
|
|
||||||
|
|
||||||
IoSession session = getCurrentSession();
|
IoSession session = getCurrentSession();
|
||||||
if(session!=null && session.isConnected())
|
if(session!=null && session.isConnected())
|
||||||
{
|
{
|
||||||
WriteFuture wf = session.write(body);
|
WriteFuture wf = session.write(body);
|
||||||
// 消息发送超时 10秒
|
// 消息发送超时 10秒
|
||||||
wf.awaitUninterruptibly(5, TimeUnit.SECONDS);
|
wf.awaitUninterruptibly(10, TimeUnit.SECONDS);
|
||||||
|
|
||||||
if (!wf.isWritten()) {
|
if (!wf.isWritten()) {
|
||||||
|
|
||||||
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setAction(ACTION_SENT_FAILED);
|
intent.setAction(ACTION_SENT_FAILED);
|
||||||
intent.putExtra("exception", new WriteToClosedSessionException());
|
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);
|
String message = new String(bytes, CIMConstant.UTF8);
|
||||||
|
|
||||||
logger.debug(message);
|
logger.info(message);
|
||||||
|
|
||||||
tBuffer.clear();
|
tBuffer.clear();
|
||||||
try{
|
try{
|
||||||
@ -72,7 +72,7 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
|
|||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
out.write(message);//解析xml失败 是返回原始的xml数据到上层处理,比如flex sokcet的 安全验证请求xml
|
out.write(message);//解析xml失败 是返回原始的xml数据到上层处理,比如flex sokcet的 安全验证请求xml
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
logger.warn(e.getMessage());
|
logger.error(e);
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
@ -89,6 +89,11 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
|
|||||||
return CIMConstant.CMD_HEARTBEAT_RESPONSE;
|
return CIMConstant.CMD_HEARTBEAT_RESPONSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(CIMConstant.FLEX_POLICY_REQUEST.equalsIgnoreCase(message))
|
||||||
|
{
|
||||||
|
return CIMConstant.FLEX_POLICY_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
SentBody body = new SentBody();
|
SentBody body = new SentBody();
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
@ -98,7 +98,6 @@ public class CIMIoHandler extends IoHandlerAdapter {
|
|||||||
*/
|
*/
|
||||||
public void exceptionCaught(IoSession session, Throwable cause)
|
public void exceptionCaught(IoSession session, Throwable cause)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
logger.error("exceptionCaught()... from "+session.getRemoteAddress());
|
|
||||||
logger.error(cause);
|
logger.error(cause);
|
||||||
cause.printStackTrace();
|
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/antlr-2.7.6.jar"/>
|
||||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/asm.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/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-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-io-2.4.jar"/>
|
||||||
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-lang-2.3.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/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/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/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"/>
|
<classpathentry kind="output" path="WebRoot/WEB-INF/classes"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
Binary file not shown.
@ -72,15 +72,21 @@
|
|||||||
<img src="<%=headerBasePath%>/resource/img/icon.png" style="margin-top: 35px;height: 80px;height: 80px;"/>
|
<img src="<%=headerBasePath%>/resource/img/icon.png" style="margin-top: 35px;height: 80px;height: 80px;"/>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item" style="border-radius: 0px;">
|
||||||
CIM即时通讯后台管理系统
|
CIM是一个提供于二次开发的即时通信解决方案,可实现基于移动应用,桌面端应用或者系统应用之间的实时消息推送。
|
||||||
|
<p/><p/>项目主页地址<br/><a target="_blank" href="http://git.oschina.net/farsunset/cim">http://git.oschina.net/farsunset/cim</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
|
||||||
Email:3979434@qq.com
|
<li class="list-group-item" style="border-radius: 0px;">
|
||||||
|
作者:远方夕阳
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item" style="border-radius: 0px;">
|
||||||
Q Q:3979434
|
Q Q:3979434
|
||||||
</li>
|
</li>
|
||||||
|
<li class="list-group-item" style="border-radius: 0px;">
|
||||||
|
微信:farbluesky
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
<li style="height: 50px; text-align: center; margin-top: 10px;">
|
<li style="height: 50px; text-align: center; margin-top: 10px;">
|
||||||
<div class="btn-group" style="margin-top: 5px;">
|
<div class="btn-group" style="margin-top: 5px;">
|
||||||
<a type="button" class="btn btn-danger" target="_blank"
|
<a type="button" class="btn btn-danger" target="_blank"
|
||||||
href="javascript:openWebclient();">CIM for
|
href="javascript:openWebclient();">CIM for Web</a>
|
||||||
Web(测试版)</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</li>
|
</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/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/bootstrap/css/bootstrap.min.css" />
|
||||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/css/dialog.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/bootstrap/js/bootstrap.min.js"></script>
|
||||||
<script type="text/javascript" src="<%=basePath%>/resource/js/framework.js"></script>
|
<script type="text/javascript" src="<%=basePath%>/resource/js/framework.js"></script>
|
||||||
<script>
|
<script>
|
||||||
@ -169,7 +169,7 @@ onclick="showMessageDialog('<%=ios.getAccount() %>')">发送消息</button>
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-groupBuy" style="margin-top: 20px;">
|
<div class="form-groupBuy" style="margin-top: 20px;">
|
||||||
<label for="exampleInputFile">消息内容:</label>
|
<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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -179,15 +179,6 @@ onclick="showMessageDialog('<%=ios.getAccount() %>')">发送消息</button>
|
|||||||
</div>
|
</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>
|
<script>
|
||||||
$('#sessionMenu').addClass('current');
|
$('#sessionMenu').addClass('current');
|
||||||
|
|
||||||
|
Binary file not shown.
@ -4,7 +4,6 @@
|
|||||||
String basePath = request.getScheme() + "://"
|
String basePath = request.getScheme() + "://"
|
||||||
+ request.getServerName() + ":" + request.getServerPort()
|
+ request.getServerName() + ":" + request.getServerPort()
|
||||||
+ path;
|
+ path;
|
||||||
|
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
@ -15,11 +14,11 @@
|
|||||||
<title>ICHAT for web(beta) </title>
|
<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/bootstrap/css/bootstrap.min.css" />
|
||||||
<link charset="utf-8" rel="stylesheet" href="<%=basePath%>/resource/css/dialog.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/bootstrap/js/bootstrap.min.js"></script>
|
||||||
<script type="text/javascript" src="<%=basePath%>/resource/js/framework.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" src="cim.js"></script>
|
||||||
</head>
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -41,11 +40,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 当socket连接成功回调 **/
|
/** 当socket连接成功回调 **/
|
||||||
function sessionCreated()
|
function sessionCreated()
|
||||||
{
|
{
|
||||||
document.getElementById("CIMBridge").setAccount(ACCOUNT,ACCOUNT);
|
//使用session id作为唯一标示,区分同一设备的多个用户
|
||||||
|
document.getElementById("CIMBridge").bindAccount(ACCOUNT,"<%=session.getId()%>");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 当socket断开是回调 **/
|
/** 当socket断开是回调 **/
|
||||||
@ -71,16 +70,16 @@
|
|||||||
|
|
||||||
/** 当收到消息时候回调 **/
|
/** 当收到消息时候回调 **/
|
||||||
|
|
||||||
function onMessageReceived(data,content)
|
function onMessageReceived(data)
|
||||||
{
|
{
|
||||||
|
|
||||||
var message = JSON.parse(data);
|
var message = JSON.parse(data);
|
||||||
|
|
||||||
if(message.type=='2')
|
if(message.type=='2')
|
||||||
{
|
{
|
||||||
document.getElementById("CIMBridge").playSound();
|
document.getElementById("CIMBridge").playSound("dingdong.mp3");
|
||||||
message.content = content;
|
var line = "<div class='alert alert-info' id ="+message.timestamp+" STYLE='white-space: nowrap; overflow: hidden; text-overflow: ellipsis;'></div>";
|
||||||
$("#messageList").append("<div class='alert alert-info' >"+content+"</div>");
|
$("#messageList").append(line);
|
||||||
|
$("#"+message.timestamp).text(message.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,36 +100,27 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<script language="Javascript">
|
|
||||||
document.oncontextmenu = function (){
|
document.oncontextmenu = function (){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.onload=function()
|
window.onload=function()
|
||||||
{
|
{
|
||||||
window.onkeydown=function(e)
|
window.onkeydown=function(e)
|
||||||
{
|
{
|
||||||
if(e.which)
|
if(e.which && e.which==116)
|
||||||
{
|
|
||||||
if(e.which==116)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
if(event.keyCode && event.keyCode==116)
|
||||||
else if(event.keyCode)
|
|
||||||
{
|
|
||||||
if(event.keyCode==116)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
<body style="background-color: rgb(190, 209, 216);width: 600px;">
|
<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">
|
<object type="application/x-shockwave-flash" data="CIMBridge.swf" id="CIMBridge" width="0" height="0">
|
||||||
<param name="quality" value="low"/>
|
<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) {
|
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"));
|
DefaultSessionManager sessionManager = ((DefaultSessionManager) ContextHolder.getBean("CIMSessionManager"));
|
||||||
|
|
||||||
String account =ios.getAttribute(CIMConstant.SESSION_KEY).toString();
|
|
||||||
ios.removeAttribute(CIMConstant.SESSION_KEY);
|
ios.removeAttribute(CIMConstant.SESSION_KEY);
|
||||||
ios.closeNow();
|
ios.closeNow();
|
||||||
sessionManager.remove(account);
|
sessionManager.remove(account.toString());
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
1.1.0
|
|
@ -181,12 +181,9 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
android.os.Message msg = new android.os.Message();
|
|
||||||
msg.getData().putSerializable("body", body);
|
|
||||||
|
|
||||||
if(channel!=null && channel.isActive())
|
if(channel!=null && channel.isActive())
|
||||||
{
|
{
|
||||||
boolean isDone = channel.writeAndFlush(body).awaitUninterruptibly(5000);
|
boolean isDone = channel.writeAndFlush(body).awaitUninterruptibly(10000);
|
||||||
if (!isDone) {
|
if (!isDone) {
|
||||||
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
package com.farsunset.cim.sdk.android.filter;
|
package com.farsunset.cim.sdk.android.filter;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.serialization.ClassResolver;
|
import io.netty.handler.codec.serialization.ClassResolver;
|
||||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||||
@ -38,31 +40,35 @@ public class ClientMessageDecoder extends ObjectDecoder {
|
|||||||
@Override
|
@Override
|
||||||
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
||||||
|
|
||||||
int length = buffer.readableBytes();
|
final ByteBuf tBuffer = PooledByteBufAllocator.DEFAULT.buffer(640);
|
||||||
|
|
||||||
buffer.markReaderIndex();
|
buffer.markReaderIndex();
|
||||||
|
boolean complete = false;
|
||||||
|
|
||||||
/**
|
while(buffer.isReadable()){
|
||||||
* CIMConstant.MESSAGE_SEPARATE 为消息界限
|
byte b = buffer.readByte();
|
||||||
* 当一次收到多个消息时,以此分隔解析多个消息
|
if (b == CIMConstant.MESSAGE_SEPARATE) {
|
||||||
*/
|
complete = true;
|
||||||
if (buffer.isReadable()&& length > 0 && CIMConstant.MESSAGE_SEPARATE == buffer.getByte(length-1)) {
|
break;
|
||||||
|
} else {
|
||||||
byte[] data = new byte[length-1];
|
tBuffer.writeByte(b);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
buffer.resetReaderIndex();
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object mappingMessageObject(String message) throws Exception {
|
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";
|
public static final String HEARTBEAT_KEY ="heartbeat";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FLEX 客户端socket请求发的安全策略请求,需要特殊处理,返回安全验证报文
|
* FLEX 客户端socket请求发的安全策略请求,需要特殊处理,返回安全验证报文
|
||||||
*/
|
*/
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
package com.farsunset.cim.sdk.server.filter;
|
package com.farsunset.cim.sdk.server.filter;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.serialization.ClassResolver;
|
import io.netty.handler.codec.serialization.ClassResolver;
|
||||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||||
@ -33,75 +35,68 @@ public class ServerMessageDecoder extends ObjectDecoder {
|
|||||||
@Override
|
@Override
|
||||||
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
public Object decode(ChannelHandlerContext arg0, ByteBuf buffer) throws Exception {
|
||||||
|
|
||||||
|
final ByteBuf tBuffer = PooledByteBufAllocator.DEFAULT.buffer(320);
|
||||||
|
|
||||||
int length = buffer.readableBytes();
|
|
||||||
buffer.markReaderIndex();
|
buffer.markReaderIndex();
|
||||||
/**
|
boolean complete = false;
|
||||||
* CIMConstant.MESSAGE_SEPARATE 为消息界限
|
|
||||||
* 当一次收到多个消息时,以此分隔解析多个消息
|
while(buffer.isReadable()){
|
||||||
*/
|
byte b = buffer.readByte();
|
||||||
if (buffer.isReadable()&&length > 0 && CIMConstant.MESSAGE_SEPARATE == buffer.getByte(length-1)) {
|
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);
|
Object body = parserMessageToSentBody(message);
|
||||||
data = null;
|
|
||||||
message = null;
|
|
||||||
return body;
|
return body;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
buffer.resetReaderIndex();
|
buffer.resetReaderIndex();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private Object parserMessageToSentBody(String message) throws Exception
|
private Object parserMessageToSentBody(String message) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
SentBody body = new SentBody();
|
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);
|
body.setKey(CIMConstant.RequestKey.CLIENT_HEARTBEAT);
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flex 客户端安全策略请求,需要返回特定报文
|
||||||
|
*/
|
||||||
|
if(CIMConstant.FLEX_POLICY_REQUEST.equalsIgnoreCase(message)){
|
||||||
|
|
||||||
|
body.setKey(CIMConstant.RequestKey.CLIENT_FLASH_POLICY);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
Document doc = builder.parse(new ByteArrayInputStream(message.toString().getBytes(CIMConstant.UTF8)));
|
Document doc = builder.parse(new ByteArrayInputStream(message.toString().getBytes(CIMConstant.UTF8)));
|
||||||
body.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
|
body.setKey(doc.getElementsByTagName("key").item(0).getTextContent());
|
||||||
NodeList dataNodeList = doc.getElementsByTagName("data");
|
NodeList dataNodeList = doc.getElementsByTagName("data");
|
||||||
if(dataNodeList!=null && dataNodeList.getLength()>0)
|
if(dataNodeList!=null && dataNodeList.getLength()>0){
|
||||||
{
|
|
||||||
NodeList items = dataNodeList.item(0).getChildNodes();
|
NodeList items = dataNodeList.item(0).getChildNodes();
|
||||||
for (int i = 0; i < items.getLength(); i++) {
|
for (int i = 0; i < items.getLength(); i++) {
|
||||||
Node node = items.item(i);
|
Node node = items.item(i);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.farsunset.cim.sdk.server.handler;
|
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.ReplyBody;
|
||||||
import com.farsunset.cim.sdk.server.model.SentBody;
|
import com.farsunset.cim.sdk.server.model.SentBody;
|
||||||
import com.farsunset.cim.sdk.server.session.CIMSession;
|
import com.farsunset.cim.sdk.server.session.CIMSession;
|
||||||
@ -22,8 +21,8 @@ public class HeartbeatHandler implements CIMRequestHandler {
|
|||||||
|
|
||||||
public ReplyBody process(CIMSession session, SentBody message) {
|
public ReplyBody process(CIMSession session, SentBody message) {
|
||||||
|
|
||||||
//收到心跳响应,清除发送心跳请求标记
|
//收到心跳响应,设置心跳时间
|
||||||
session.removeAttribute(CIMConstant.RequestKey.CLIENT_HEARTBEAT);
|
session.setHeartbeat(System.currentTimeMillis());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>{
|
|||||||
|
|
||||||
public static final int PING_TIME_OUT = 30;//心跳响应 超时为30秒
|
public static final int PING_TIME_OUT = 30;//心跳响应 超时为30秒
|
||||||
|
|
||||||
public static final String HEARTBEAT_PINGED ="HEARTBEAT_PINGED";
|
|
||||||
|
|
||||||
public void bind()
|
public void bind()
|
||||||
{
|
{
|
||||||
@ -94,7 +94,7 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>{
|
|||||||
public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause)
|
public void exceptionCaught( ChannelHandlerContext ctx, Throwable cause)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
logger.error(ctx.channel().remoteAddress());
|
logger.error(ctx.channel().remoteAddress());
|
||||||
|
logger.error(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -118,20 +118,19 @@ public class CIMNioSocketAcceptor extends SimpleChannelInboundHandler<SentBody>{
|
|||||||
|
|
||||||
|
|
||||||
private void onWriterIdeled(Channel channel){
|
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);
|
channel.writeAndFlush(CIMConstant.CMD_HEARTBEAT_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onReaderIdeled(Channel channel){
|
private void onReaderIdeled(Channel channel){
|
||||||
Long lastTime = (Long) channel.attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).get();
|
Long lastTime = (Long) channel.attr(AttributeKey.valueOf(CIMConstant.HEARTBEAT_KEY)).get();
|
||||||
if(lastTime == null || System.currentTimeMillis() - lastTime >= PING_TIME_OUT)
|
if(lastTime != null && System.currentTimeMillis() - lastTime >= PING_TIME_OUT)
|
||||||
{
|
{
|
||||||
channel.close();
|
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