1 新增 Java版本客户端,可用于系统应用,桌面应用之间实时消息推送

2 FlashBridge 基于web版本的插件经过调试优化发布正式版,可以用于网页的消息推送
3 Netty版本修改了当消息断包时处理不当,导致消息丢失的问题
This commit is contained in:
远方夕阳 2016-07-15 18:14:02 +08:00
parent 3585cf4eb2
commit 22e6284dac
114 changed files with 4056 additions and 281 deletions

View File

@ -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>

Binary file not shown.

Binary file not shown.

View File

@ -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);
} }

View File

@ -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();
} }

View File

@ -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
JavaSDK使用文档.doc Normal file

Binary file not shown.

View File

@ -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());

View 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>

View 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>

View File

@ -0,0 +1,3 @@
#Wed Oct 15 09:31:41 CST 2014
eclipse.preferences.version=1
encoding/<project>=UTF-8

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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);
}
}

View File

@ -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 {
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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() + "#######" );
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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";
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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();
} }

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);">&times;</a>
</div>
<div class="panel-body">
<img src = "<%=basePath%>/resource/img/scan_download.png"/>
</div>
</div>
<script> <script>
$('#sessionMenu').addClass('current'); $('#sessionMenu').addClass('current');

View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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;
} }

View File

@ -1 +0,0 @@
1.1.0

View File

@ -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();

View File

@ -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 {

View 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>

View 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>

View File

@ -0,0 +1,3 @@
#Wed Oct 15 09:31:41 CST 2014
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -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);
}
}

View File

@ -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);
}
});
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}

View File

@ -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() + "#######" );
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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";
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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请求发的安全策略请求需要特殊处理返回安全验证报文
*/ */

View File

@ -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);

View File

@ -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;
} }

View File

@ -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