1.修改跨进程下数据存储的问题

2.netty使用最新的4.1版本
3.mina 使用最新的2.0.13版本
4.修改了部分代码包名
5.修改了多处问题
This commit is contained in:
远方夕阳 2016-04-18 12:43:40 +08:00
parent 16afed7b2b
commit 97380a9e9b
197 changed files with 3753 additions and 3337 deletions

Binary file not shown.

View File

@ -18,9 +18,18 @@ package
internal var CIM_HOST:String = "127.0.0.1"; internal var CIM_HOST:String = "127.0.0.1";
internal var CIM_PORT:String = "23456"; internal var CIM_PORT:String = "23456";
internal var socket:Socket; internal var socket:Socket;
internal var heartbeat_timer:Timer=new Timer(180 * 1000);
internal var froceOffline :Boolean = false; internal var froceOffline :Boolean = false;
internal var _sound:Sound = new Sound(new URLRequest("dingdong.mp3")); internal var _sound:Sound = new Sound(new URLRequest("dingdong.mp3"));
/**
* cmd_server_hb_request
*/
internal const CMD_HEARTBEAT_REQUEST:String="S_H_RQ";
/**
* cmd_client_hb_response
*/
internal const CMD_HEARTBEAT_RESPONSE:String ="C_H_RS";
public function CIMBridge() public function CIMBridge()
{ {
@ -29,7 +38,6 @@ package
ExternalInterface.addCallback("getOfflineMessage",getOfflineMessage); ExternalInterface.addCallback("getOfflineMessage",getOfflineMessage);
ExternalInterface.addCallback("logout",logout); ExternalInterface.addCallback("logout",logout);
ExternalInterface.addCallback("playSound",playSound); ExternalInterface.addCallback("playSound",playSound);
heartbeat_timer.addEventListener(TimerEvent.TIMER,doSendHeartbeat);
ExternalInterface.call("bridgeCreationComplete"); ExternalInterface.call("bridgeCreationComplete");
@ -61,7 +69,9 @@ package
xml+="<account>"+account+"</account>"; xml+="<account>"+account+"</account>";
xml+="<deviceId>"+deviceId+"</deviceId>"; xml+="<deviceId>"+deviceId+"</deviceId>";
xml+="<channel>web</channel>"; xml+="<channel>web</channel>";
xml+="<device>browser</device>"; xml+="<device>flash</device>";
xml+="<version>2.0.0</version>";
xml+="<osVersion>"+flash.system.Capabilities.version+"</osVersion>";
xml+="</data>"; xml+="</data>";
xml+="</sent>"; xml+="</sent>";
@ -94,19 +104,10 @@ package
{ {
ExternalInterface.call("sessionCreated"); ExternalInterface.call("sessionCreated");
heartbeat_timer.start();
froceOffline = false; froceOffline = false;
} }
private function doSendHeartbeat(e:TimerEvent):void
{
var xml:String="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
xml+="<sent>";
xml+="<key>client_heartbeat</key>";
xml+="</sent>";
send(xml);
}
private function sessionClosed(event:Event):void private function sessionClosed(event:Event):void
{ {
@ -116,7 +117,6 @@ package
{ {
connect(CIM_HOST); connect(CIM_HOST);
} }
heartbeat_timer.stop();
} }
private function exceptionCaught(event:Event):void{ private function exceptionCaught(event:Event):void{
@ -146,6 +146,14 @@ package
msg = msg.substring(0,index); msg = msg.substring(0,index);
} }
if(msg.toUpperCase() == CMD_HEARTBEAT_REQUEST)
{
send(CMD_HEARTBEAT_RESPONSE);
return;
}
var xml:XML=XML(msg); var xml:XML=XML(msg);
var data:Object = xml as Object; var data:Object = xml as Object;
if(xml.name()=="reply"){ if(xml.name()=="reply"){

Binary file not shown.

Binary file not shown.

View File

@ -49,10 +49,10 @@ com.farsunset.cim.client.android.CIMPushManager
* @param ip * @param ip
* @param port * @param port
*/ */
public static void init(Context context,String ip,int port) public static void connect(Context context,String ip,int port)
示例 示例
CIMPushManager.init(context,"125.12.35.231",28888); CIMPushManager.connect(context,"125.12.35.231",28888);
@ -86,7 +86,7 @@ public static void sendRequest(Context context,SentBody body)
sent.put("account", "xiyang"); sent.put("account", "xiyang");
CIMPushManager.sendRequest(context, sent); CIMPushManager.sendRequest(context, sent);
该功能需要服务端实现,详情参考CIM服务端及辅助文档.doc > 1.2.3 该功能需要服务端实现,详情参考服务端PullOflineMessageHandler.java
@ -120,54 +120,74 @@ public static void sendRequest(Context context,SentBody body)
* 完全销毁CIM一般用于完全退出程序调用resume将不能恢复 * 完全销毁CIM一般用于完全退出程序调用resume将不能恢复
* @param context * @param context
*/ */
public static void destory(Context context) public static void destroy(Context context)
示例: 示例:
CIMPushManager.destory(context); CIMPushManager.destroy(context);
1.7获取是否与服务端连接正常 1.7获取是否与服务端连接正常
/** /**
* 异步获取与服务端连接状态,将会在广播中收到onConnectionStatusboolean f *
* @param context * @param context
*/ */
public void detectIsConnected(Context context) public boolean isConnected(Context context)
示例: 示例:
CIMPushManager.detectIsConnected(context); CIMPushManager.isConnected(context);
1.8获取PushManager状态
//被销毁的destroy()
CIMPushManager.STATE_DESTROYED = 0x0000DE;
//被销停止的 stop()
CIMPushManager.STATE_STOPED = 0x0000EE;
CIMPushManager.STATE_NORMAL = 0x000000;
1.8推送消息以及相关事件的接收 public int getState(Context context)
示例:
CIMPushManager.getState(context);
1.9推送消息以及相关事件的接收
首先注册一个广播并监听以下action 参照 后面androidManifest.xml配置 首先注册一个广播并监听以下action 参照 后面androidManifest.xml配置
参考CustomCIMMessageReceiver的实现 参考CustomCIMMessageReceiver的实现
/** /**
* 当收到消息时调用此方法 * 当收到服务端推送过来的消息时调用
* @param message
*/ */
public void onMessageReceived(message){} public abstract void onMessageReceived(Message message);
/** /**
* 当手机网络变化时调用此方法 * 当调用CIMPushManager.sendRequest()向服务端发送请求,获得相应时调用
* @param info * @param replybody
*/ */
public void onNetworkChanged(NetworkInfo info) public abstract void onReplyReceived(ReplyBody replybody);
/**
* 当手机网络发生变化时调用
* @param networkinfo
*/
public abstract void onNetworkChanged(NetworkInfo networkinfo);
/** /**
* 当调用CIMPushManager.sendRequest()获得相应时 调用此方法 * 当连接服务器成功时回调
* ReplyBody.key 将是对应的 SentBody.key * @param hasAutoBind : true 已经自动绑定账号到服务器了不需要再手动调用bindAccount
* @param info
*/ */
public void onReplyReceived(ReplyBody body) public abstract void onConnectionSuccessed(boolean hasAutoBind);
/** /**
* 获取到是否连接到服务端 * 当断开服务器连接的时候回调
* 通过调用CIMPushManager.detectIsConnected()来异步获取 */
public abstract void onConnectionClosed();
/**
* 当服务器连接失败的时候回调
* *
*/ */
public abstract void onConnectionStatus(boolean isConnected) public abstract void onConnectionFailed(Exception e);
``` ```

View File

@ -4,6 +4,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="C:/dev/Android-SDK-Windows/platforms/android-19/android.jar"/> <classpathentry kind="lib" path="C:/dev/Android-SDK-Windows/platforms/android-19/android.jar"/>
<classpathentry kind="lib" path="D:/cim-system/cim-server/WebRoot/WEB-INF/lib/log4j.jar"/> <classpathentry kind="lib" path="D:/cim-system/cim-server/WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="D:/cim-system/cim-server/WebRoot/WEB-INF/lib/mina-core-2.0.9.jar"/> <classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/mina-core-2.0.13.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -1,57 +0,0 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import android.content.Context;
class CIMCacheTools {
public static String CIM_CONFIG_INFO = "CIM_CONFIG_INFO";
public static String KEY_ACCOUNT = "KEY_ACCOUNT";
public static String KEY_MANUAL_STOP = "KEY_MANUAL_STOP";
public static String KEY_CIM_DESTORYED = "KEY_CIM_DESTORYED";
public static String KEY_CIM_SERVIER_HOST = "KEY_CIM_SERVIER_HOST";
public static String KEY_CIM_SERVIER_PORT = "KEY_CIM_SERVIER_PORT";
public static void putString(Context context,String key,String value)
{
context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).edit().putString(key, value).commit();
}
public static String getString(Context context,String key)
{
return context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).getString(key,null);
}
public static void putBoolean(Context context,String key,boolean value)
{
context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).edit().putBoolean(key, value).commit();
}
public static boolean getBoolean(Context context,String key)
{
return context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).getBoolean(key,false);
}
public static void putInt(Context context,String key,int value)
{
context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).edit().putInt(key, value).commit();
}
public static int getInt(Context context,String key)
{
return context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).getInt(key,0);
}
}

View File

@ -1,57 +0,0 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import android.net.NetworkInfo;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
/**
*CIM 主要事件接口
*/
public interface CIMEventListener
{
/**
* 当收到服务端推送过来的消息时调用
* @param message
*/
public void onMessageReceived(Message message);
/**
* 当调用CIMPushManager.sendRequest()向服务端发送请求获得相应时调用
* @param replybody
*/
public void onReplyReceived(ReplyBody replybody);
/**
* 当手机网络发生变化时调用
* @param networkinfo
*/
public void onNetworkChanged(NetworkInfo networkinfo);
/**
* 获取到是否连接到服务端
* 通过调用CIMPushManager.detectIsConnected()来异步获取
*
*/
public void onConnectionStatus(boolean isConnected);
/**
* 连接服务端成功
*/
public void onCIMConnectionSucceed();
/**
* 连接断开
*/
public void onCIMConnectionClosed();
}

View File

@ -1,215 +0,0 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import java.util.UUID;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.model.SentBody;
/**
* CIM 功能接口
*/
public class CIMPushManager {
static String ACTION_ACTIVATE_PUSH_SERVICE ="ACTION_ACTIVATE_PUSH_SERVICE";
static String ACTION_CONNECTION ="ACTION_CONNECTION";
static String ACTION_CONNECTION_STATUS ="ACTION_CONNECTION_STATUS";
static String ACTION_SENDREQUEST ="ACTION_SENDREQUEST";
static String ACTION_DISCONNECTION ="ACTION_DISSENDREQUEST";
static String ACTION_DESTORY ="ACTION_DESTORY";
static String SERVICE_ACTION ="SERVICE_ACTION";
static String KEY_SEND_BODY ="KEY_SEND_BODY";
static String KEY_CIM_CONNECTION_STATUS ="KEY_CIM_CONNECTION_STATUS";
/**
* 初始化,连接服务端在程序启动页或者 在Application里调用
* @param context
* @param ip
* @param port
*/
public static void init(Context context,String ip,int port){
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED, false);
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, false);
CIMCacheTools.putString(context, CIMCacheTools.KEY_CIM_SERVIER_HOST, ip);
CIMCacheTools.putInt(context, CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST, ip);
serviceIntent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION);
context.startService(serviceIntent);
}
protected static void init(Context context){
boolean isManualStop = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualStop || isManualDestory)
{
return ;
}
String host = CIMCacheTools.getString(context, CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port =CIMCacheTools.getInt(context, CIMCacheTools.KEY_CIM_SERVIER_PORT);
init(context,host,port);
}
/**
* 设置一个账号登录到服务端
* @param account 用户唯一ID
*/
public static void bindAccount(Context context,String account){
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory || account==null || account.trim().length()==0)
{
return ;
}
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, false);
CIMCacheTools.putString(context,CIMCacheTools.KEY_ACCOUNT, account);
String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
imei += context.getPackageName();
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
sent.put("account", account);
sent.put("deviceId",UUID.nameUUIDFromBytes(imei.getBytes()).toString().replaceAll("-", ""));
sent.put("channel", "android");
sent.put("device",android.os.Build.MODEL);
sent.put("appVersion",getVersionName(context));
sent.put("osVersion",android.os.Build.VERSION.RELEASE);
sendRequest(context,sent);
}
protected static void bindAccount(Context context){
String account = CIMCacheTools.getString(context,CIMCacheTools.KEY_ACCOUNT);
bindAccount(context,account);
}
/**
* 发送一个CIM请求
* @param context
* @body
*/
public static void sendRequest(Context context,SentBody body){
boolean isManualStop = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualStop || isManualDestory)
{
return ;
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(KEY_SEND_BODY, body);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_SENDREQUEST);
context.startService(serviceIntent);
}
/**
* 停止接受推送将会退出当前账号登录端口与服务端的连接
* @param context
*/
public static void stop(Context context){
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory){
return ;
}
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, true);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_DISCONNECTION);
context.startService(serviceIntent);
}
/**
* 完全销毁CIM一般用于完全退出程序调用resume将不能恢复
* @param context
*/
public static void destory(Context context){
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED, true);
CIMCacheTools.putString(context,CIMCacheTools.KEY_ACCOUNT, null);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_DESTORY);
context.startService(serviceIntent);
}
/**
* 重新恢复接收推送重新连接服务端并登录当前账号
* @param context
*/
public static void resume(Context context){
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory){
return ;
}
bindAccount(context);
}
public static void detectIsConnected(Context context){
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION_STATUS);
context.startService(serviceIntent);
}
private static String getVersionName(Context context) {
String versionName = null;
try {
PackageInfo mPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
versionName = mPackageInfo.versionName;
} catch (NameNotFoundException e) {
}
return versionName;
}
}

View File

@ -1,97 +0,0 @@
package com.farsunset.cim.client.android;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.farsunset.cim.client.model.SentBody;
/**
* 与服务端连接服务
* @author 3979434
*
*/
public class CIMPushService extends Service {
protected final static int DEF_CIM_PORT = 28888;
CIMConnectorManager manager;
@Override
public void onCreate()
{
manager = CIMConnectorManager.getManager(this.getApplicationContext());
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) {
String action;
if(intent==null)
{
intent = new Intent(CIMPushManager.ACTION_CONNECTION);
String host = CIMCacheTools.getString(this, CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port =CIMCacheTools.getInt(this, CIMCacheTools.KEY_CIM_SERVIER_PORT);
intent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST, host);
intent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
}
action = intent.getStringExtra(CIMPushManager.SERVICE_ACTION);
if(CIMPushManager.ACTION_CONNECTION.equals(action))
{
String host = intent.getStringExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port = intent.getIntExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, DEF_CIM_PORT);
manager.connect(host,port);
}
if(CIMPushManager.ACTION_SENDREQUEST.equals(action))
{
manager.send((SentBody) intent.getSerializableExtra(CIMPushManager.KEY_SEND_BODY));
}
if(CIMPushManager.ACTION_DISCONNECTION.equals(action))
{
manager.closeSession();
}
if(CIMPushManager.ACTION_DESTORY.equals(action))
{
manager.destroy();
this.stopSelf();
android.os.Process.killProcess(android.os.Process.myPid());
}
if(CIMPushManager.ACTION_CONNECTION_STATUS.equals(action))
{
manager.deliverIsConnected();
}
if(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action))
{
if(!manager.isConnected())
{
Log.d(CIMPushService.class.getSimpleName(), "cimpush isConnected() = false ");
String host = intent.getStringExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port = intent.getIntExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, DEF_CIM_PORT);
manager.connect(host,port);
}else
{
Log.d(CIMPushService.class.getSimpleName(), "isConnected() = true ");
}
}
return Service.START_REDELIVER_INTENT;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}

View File

@ -0,0 +1,130 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
class CIMCacheToolkit extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "CIM_CONFIG_INFO.db";
private static final int DATABASE_VERSION = 20160416;
private static final String TABLE_SQL = "CREATE TABLE IF NOT EXISTS T_CIM_CONFIG (KEY VARCHAR(64) PRIMARY KEY,VALUE TEXT)";
private static final String DELETE_SQL = "DELETE FROM T_CIM_CONFIG WHERE KEY = ?";
private static final String SAVE_SQL = "INSERT INTO T_CIM_CONFIG (KEY,VALUE) VALUES(?,?)";
private static final String QUERY_SQL = "SELECT VALUE FROM T_CIM_CONFIG WHERE KEY = ?";
public static final String CIM_CONFIG_INFO = "CIM_CONFIG_INFO";
public static final String KEY_ACCOUNT = "KEY_ACCOUNT";
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(Context context){
if (toolkit==null){
toolkit = new CIMCacheToolkit(context);
}
return toolkit;
}
public CIMCacheToolkit(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
public CIMCacheToolkit(Context context){
this(context, DATABASE_NAME,null, DATABASE_VERSION);
}
public void remove(String key)
{
SQLiteDatabase database = toolkit.getWritableDatabase();
database.execSQL(DELETE_SQL,new String[]{key});
database.close();
toolkit.close();
toolkit = null;
}
public void putString(String key,String value)
{
SQLiteDatabase database = toolkit.getWritableDatabase();
database.execSQL(DELETE_SQL,new String[]{key});
database.execSQL(SAVE_SQL, new String[]{key, value});
database.close();
toolkit.close();
toolkit = null;
}
public String getString(String key)
{
String value = null;
SQLiteDatabase database = toolkit.getWritableDatabase();
Cursor cursor = database.rawQuery(QUERY_SQL, new String[]{key});
if (cursor!=null&&cursor.moveToFirst())
{
value = cursor.getString(0);
}
cursor.close();
database.close();
toolkit.close();
toolkit = null;
return value;
}
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);
}
@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(TABLE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
}
}

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.android; package com.farsunset.cim.sdk.android;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -20,21 +20,20 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter; import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory; import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.apache.mina.transport.socket.nio.NioSocketConnector;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.util.Log; import android.util.Log;
import com.farsunset.cim.client.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.client.exception.CIMSessionDisableException; import com.farsunset.cim.sdk.android.exception.CIMSessionDisableException;
import com.farsunset.cim.client.exception.NetWorkDisableException; import com.farsunset.cim.sdk.android.exception.NetWorkDisableException;
import com.farsunset.cim.client.exception.WriteToClosedSessionException; import com.farsunset.cim.sdk.android.exception.WriteToClosedSessionException;
import com.farsunset.cim.client.filter.ClientMessageCodecFactory; import com.farsunset.cim.sdk.android.filter.ClientMessageCodecFactory;
import com.farsunset.cim.client.model.Message; import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.client.model.ReplyBody; import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.client.model.SentBody; import com.farsunset.cim.sdk.android.model.SentBody;
/** /**
* 连接服务端管理cim核心处理类管理连接以及消息处理 * 连接服务端管理cim核心处理类管理连接以及消息处理
@ -49,6 +48,11 @@ class CIMConnectorManager {
Context context; Context context;
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; static CIMConnectorManager manager;
@ -59,13 +63,13 @@ class CIMConnectorManager {
public static final String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED"; public static final String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED";
// 发送sendbody成功广播 // 发送sendbody成功广播
public static final String ACTION_SENT_SUCCESS = "com.farsunset.cim.SENT_SUCCESS"; 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_CLOSED = "com.farsunset.cim.CONNECTION_CLOSED";
// 链接失败广播 // 链接失败广播
public static final String ACTION_CONNECTION_FAILED = "com.farsunset.cim.CONNECTION_FAILED"; public static final String ACTION_CONNECTION_FAILED = "com.farsunset.cim.CONNECTION_FAILED";
// 链接成功广播 // 链接成功广播
public static final String ACTION_CONNECTION_SUCCESS = "com.farsunset.cim.CONNECTION_SUCCESS"; public static final String ACTION_CONNECTION_SUCCESSED = "com.farsunset.cim.CONNECTION_SUCCESSED";
// 发送sendbody成功后获得replaybody回应广播 // 发送sendbody成功后获得replaybody回应广播
public static final String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED"; public static final String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED";
// 网络变化广播 // 网络变化广播
@ -74,19 +78,18 @@ class CIMConnectorManager {
// 未知异常 // 未知异常
public static final String ACTION_UNCAUGHT_EXCEPTION = "com.farsunset.cim.UNCAUGHT_EXCEPTION"; public static final String ACTION_UNCAUGHT_EXCEPTION = "com.farsunset.cim.UNCAUGHT_EXCEPTION";
// CIM连接状态 //重试连接
public static final String ACTION_CONNECTION_STATUS = "com.farsunset.cim.CONNECTION_STATUS"; public final static String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
private ExecutorService executor; private ExecutorService executor;
private CIMConnectorManager(Context ctx) { private CIMConnectorManager(Context ctx) {
context = ctx; context = ctx;
executor = Executors.newFixedThreadPool(3); executor = Executors.newFixedThreadPool(1);
connector = new NioSocketConnector(); connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(10 * 1000); connector.setConnectTimeoutMillis(10 * 1000);
connector.getSessionConfig().setTcpNoDelay(true); connector.getSessionConfig().setTcpNoDelay(true);
connector.getSessionConfig().setBothIdleTime(BOTH_IDLE_TIME);
connector.getSessionConfig().setReadBufferSize(2048); connector.getSessionConfig().setReadBufferSize(2048);
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ClientMessageCodecFactory())); connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ClientMessageCodecFactory()));
@ -113,6 +116,8 @@ class CIMConnectorManager {
if(isConnected()){ if(isConnected()){
return ; return ;
} }
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, false);
InetSocketAddress remoteSocketAddress = new InetSocketAddress(cimServerHost, cimServerPort); InetSocketAddress remoteSocketAddress = new InetSocketAddress(cimServerHost, cimServerPort);
connectFuture = connector.connect(remoteSocketAddress); connectFuture = connector.connect(remoteSocketAddress);
connectFuture.awaitUninterruptibly(); connectFuture.awaitUninterruptibly();
@ -124,7 +129,7 @@ class CIMConnectorManager {
intent.putExtra("exception", e); intent.putExtra("exception", e);
context.sendBroadcast(intent); context.sendBroadcast(intent);
Log.i(TAG, "******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort); Log.e(TAG, "******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort);
} }
@ -205,7 +210,7 @@ class CIMConnectorManager {
public void destroy() { public void destroy() {
IoSession session = getCurrentSession(); IoSession session = getCurrentSession();
if (session != null) { if (session != null) {
session.close(false); session.closeNow();
session.removeAttribute("account"); session.removeAttribute("account");
} }
@ -223,13 +228,6 @@ class CIMConnectorManager {
return session.isConnected() ; return session.isConnected() ;
} }
public void deliverIsConnected() {
Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_STATUS);
intent.putExtra(CIMPushManager.KEY_CIM_CONNECTION_STATUS, isConnected());
context.sendBroadcast(intent);
}
public void closeSession() public void closeSession()
@ -237,7 +235,7 @@ class CIMConnectorManager {
IoSession session = getCurrentSession(); IoSession session = getCurrentSession();
if(session!=null) if(session!=null)
{ {
session.close(false); session.closeNow();
} }
} }
@ -262,8 +260,10 @@ class CIMConnectorManager {
Log.i(TAG, "******************CIM连接服务器成功:"+session.getLocalAddress()); Log.i(TAG, "******************CIM连接服务器成功:"+session.getLocalAddress());
setLastHeartbeatTime(session);
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_SUCCESS); intent.setAction(ACTION_CONNECTION_SUCCESSED);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
@ -276,7 +276,7 @@ class CIMConnectorManager {
@Override @Override
public void sessionClosed(IoSession session) throws Exception { public void sessionClosed(IoSession session) throws Exception {
Log.i(TAG, "******************CIM与服务器断开连接:"+session.getLocalAddress()); Log.e(TAG, "******************CIM与服务器断开连接:"+session.getLocalAddress());
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_CLOSED); intent.setAction(ACTION_CONNECTION_CLOSED);
@ -285,10 +285,19 @@ class CIMConnectorManager {
} }
@Override @Override
public void sessionIdle(IoSession session, IdleStatus status) public void sessionIdle(IoSession session, IdleStatus status)throws Exception {
throws Exception { Log.d(TAG, "******************CIM与服务器连接空闲:"+session.getLocalAddress() + " isActive:" + session.isActive()+ " isConnected:" + session.isConnected());
Log.i(TAG, "******************CIM与服务器连接空闲:"+session.getLocalAddress()); /**
* 用于解决wifi情况下偶而路由器与服务器断开连接时客户端并没及时收到关闭事件
* 导致这样的情况下当前连接无效也不会重连的问题
*
*/
long lastHeartbeatTime = getLastHeartbeatTime(session);
if(System.currentTimeMillis() - lastHeartbeatTime >= HEARBEAT_TIME_OUT)
{
session.closeNow();
}
} }
@Override @Override
@ -328,13 +337,29 @@ class CIMConnectorManager {
if(message instanceof SentBody) if(message instanceof SentBody)
{ {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_SENT_SUCCESS); intent.setAction(ACTION_SENT_SUCCESSED);
intent.putExtra("sentBody", (SentBody) message); intent.putExtra("sentBody", (SentBody) message);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
} }
}; };
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;
}
public static boolean netWorkAvailable(Context context) { public static boolean netWorkAvailable(Context context) {
try { try {
ConnectivityManager nw = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); ConnectivityManager nw = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
@ -358,8 +383,11 @@ class CIMConnectorManager {
} }
@Override @Override
public boolean isRequest(IoSession arg0, Object arg1) { public boolean isRequest(IoSession session, Object data) {
return CIMConstant.CMD_HEARTBEAT_REQUEST.equals(arg1);
setLastHeartbeatTime(session);
return CIMConstant.CMD_HEARTBEAT_REQUEST.equalsIgnoreCase(data.toString());
} }
@Override @Override

View File

@ -4,36 +4,35 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.android; package com.farsunset.cim.sdk.android;
import java.util.List;
import android.app.ActivityManager; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import android.app.ActivityManager.RunningTaskInfo; import com.farsunset.cim.sdk.android.exception.CIMSessionDisableException;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Handler; import android.os.Handler;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.exception.CIMSessionDisableException;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
import com.farsunset.cim.client.model.SentBody;
/** /**
* 消息入口所有消息都会经过这里 * 消息入口所有消息都会经过这里
*/ */
public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver implements CIMEventListener { public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver implements CIMEventListener {
public Context context; public Context context;
@Override @Override
public void onReceive(Context ctx, Intent it) { public void onReceive(Context ctx, Intent it) {
context = ctx; context = ctx;
/* /*
* 操作事件广播用于提高service存活率 * 操作事件广播用于提高service存活率
*/ */
@ -61,11 +60,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED))
{ {
if(CIMConnectorManager.netWorkAvailable(context)) onInnerConnectionClosed();
{
CIMPushManager.init(context);
}
onCIMConnectionClosed();
} }
/* /*
@ -73,19 +68,15 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED))
{ {
onConnectionFailed((Exception) it.getSerializableExtra("exception")); onInnerConnectionFailed((Exception) it.getSerializableExtra("exception"));
} }
/* /*
* cim连接服务器成功事件 * cim连接服务器成功事件
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESS)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESSED))
{ {
onInnerConnectionSuccessed();
CIMPushManager.bindAccount(context);
onCIMConnectionSucceed();
} }
/* /*
@ -93,7 +84,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED)) if(it.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED))
{ {
filterType999Message((Message)it.getSerializableExtra("message")); onInnerMessageReceived((Message)it.getSerializableExtra("message"));
} }
@ -117,7 +108,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
/* /*
* 获取sendbody发送成功事件 * 获取sendbody发送成功事件
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESS)) if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESSED))
{ {
onSentSucceed((SentBody)it.getSerializableExtra("sentBody")); onSentSucceed((SentBody)it.getSerializableExtra("sentBody"));
} }
@ -131,61 +122,61 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
onUncaughtException((Exception)it.getSerializableExtra("exception")); onUncaughtException((Exception)it.getSerializableExtra("exception"));
} }
/* /*
* 获取cim连接状态事件 * 重新连接如果断开的话
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_STATUS)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_RECOVERY))
{ {
onConnectionStatus(it.getBooleanExtra(CIMPushManager.KEY_CIM_CONNECTION_STATUS, false)); CIMPushManager.connect(context);
} }
} }
protected boolean isInBackground(Context context) {
List<RunningTaskInfo> tasksInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1);
if (tasksInfo.size() > 0) {
if (context.getPackageName().equals(
tasksInfo.get(0).topActivity.getPackageName())) {
return false;
}
}
return true;
}
private void startPushService() private void startPushService()
{ {
Intent intent = new Intent(context, CIMPushService.class); Intent intent = new Intent(context, CIMPushService.class);
intent.putExtra(CIMPushManager.SERVICE_ACTION, CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE); intent.setAction(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE);
context.startService(intent); context.startService(intent);
} }
private void onInnerConnectionClosed(){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, false);
if(CIMConnectorManager.netWorkAvailable(context))
{
CIMPushManager.connect(context);
}
onConnectionClosed();
}
Handler connectionHandler = new Handler(){
@Override
public void handleMessage(android.os.Message message){
CIMPushManager.connect(context);
}
};
private void onInnerConnectionFailed(Exception e){
private void onConnectionFailed(Exception e){
if(CIMConnectorManager.netWorkAvailable(context)) if(CIMConnectorManager.netWorkAvailable(context))
{ {
//间隔30秒后重连 connectionHandler.sendEmptyMessageDelayed(0, CIMConstant.RECONN_INTERVAL_TIME);
connectionHandler.sendMessageDelayed(connectionHandler.obtainMessage(), 30*1000);
} }
onConnectionFailed(e);
} }
Handler connectionHandler = new Handler()
{
@Override
public void handleMessage(android.os.Message message){
CIMPushManager.init(context);
private void onInnerConnectionSuccessed(){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, true);
boolean autoBind = CIMPushManager.autoBindAccount(context);
onConnectionSuccessed(autoBind);
} }
};
private void onUncaughtException(Throwable arg0) {} private void onUncaughtException(Throwable arg0) {}
@ -194,17 +185,17 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
if(info !=null) if(info !=null)
{ {
CIMPushManager.init(context); CIMPushManager.connect(context);
} }
onNetworkChanged(info); onNetworkChanged(info);
} }
private void filterType999Message(com.farsunset.cim.client.model.Message message) private void onInnerMessageReceived(com.farsunset.cim.sdk.android.model.Message message)
{ {
if(CIMConstant.MessageType.TYPE_999.equals(message.getType())) if(CIMConstant.MessageType.TYPE_999.equals(message.getType()))
{ {
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP,true); CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP,true);
} }
onMessageReceived(message); onMessageReceived(message);
@ -215,7 +206,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
//与服务端端开链接重新连接 //与服务端端开链接重新连接
if(e instanceof CIMSessionDisableException) if(e instanceof CIMSessionDisableException)
{ {
CIMPushManager.init(context); CIMPushManager.connect(context);
}else }else
{ {
//发送失败 重新发送 //发送失败 重新发送
@ -225,15 +216,12 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
} }
private void onSentSucceed(SentBody body){} private void onSentSucceed(SentBody body){}
@Override @Override
public abstract void onMessageReceived(com.farsunset.cim.client.model.Message message); public abstract void onMessageReceived(Message message);
@Override @Override
public abstract void onReplyReceived(ReplyBody body); public abstract void onReplyReceived(ReplyBody body);
public abstract void onNetworkChanged(NetworkInfo info); public abstract void onNetworkChanged(NetworkInfo info);
public abstract void onConnectionFailed(Exception e);
public abstract void onCIMConnectionSucceed();
public abstract void onCIMConnectionClosed();
} }

View File

@ -0,0 +1,57 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import android.net.NetworkInfo;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.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 networkinfo
*/
public abstract void onNetworkChanged(NetworkInfo networkinfo);
/**
* 当连接服务器成功时回调
* @param hasAutoBind : true 已经自动绑定账号到服务器了不需要再手动调用bindAccount
*/
public abstract void onConnectionSuccessed(boolean hasAutoBind);
/**
* 当断开服务器连接的时候回调
*/
public abstract void onConnectionClosed();
/**
* 当服务器连接失败的时候回调
*
*/
public abstract void onConnectionFailed(Exception e);
}

View File

@ -4,17 +4,21 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.android; package com.farsunset.cim.sdk.android;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import com.farsunset.cim.client.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.NetworkInfo;
import android.util.Log;
/** /**
@ -44,13 +48,53 @@ public class CIMListenerManager {
} }
} }
public static ArrayList<CIMEventListener> getCIMListeners() {
return cimListeners; public static void notifyOnNetworkChanged(NetworkInfo info) {
for (CIMEventListener listener : cimListeners) {
listener.onNetworkChanged(info);
}
} }
public static void notifyOnConnectionSuccessed(boolean hasAutoBind) {
for (CIMEventListener listener : cimListeners) {
listener.onConnectionSuccessed(hasAutoBind);
}
}
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) {
Log.i(CIMEventListener.class.getSimpleName(),"#######" + listener.getClass().getName() + "#######" );
}
}
/** /**
* 消息接收activity的接收顺序排序CIM_RECEIVE_ORDER倒序 * 消息接收activity的接收顺序排序CIM_RECEIVE_ORDER倒序

View File

@ -0,0 +1,250 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import java.util.UUID;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.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(Context context,String host,int port){
connect(context,host,port,false);
}
private static void connect(Context context,String ip,int port,boolean autoBind){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, false);
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
CIMCacheToolkit.getInstance(context).putString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
CIMCacheToolkit.getInstance(context).putInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
if(!autoBind)
{
CIMCacheToolkit.getInstance(context).remove(CIMCacheToolkit.KEY_ACCOUNT);
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
serviceIntent.setAction(ACTION_CREATE_CIM_CONNECTION);
context.startService(serviceIntent);
}
protected static void connect(Context context){
boolean isManualStop = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualStop || isManualDestory)
{
return ;
}
String host = CIMCacheToolkit.getInstance(context).getString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
int port =CIMCacheToolkit.getInstance(context).getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
connect(context,host,port,true);
}
/**
* 设置一个账号登录到服务端
* @param account 用户唯一ID
*/
public static void bindAccount(Context context,String account){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory || account==null || account.trim().length()==0)
{
return ;
}
sendBindRequest(context,account);
}
private static void sendBindRequest(Context context, String account){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
CIMCacheToolkit.getInstance(context).putString(CIMCacheToolkit.KEY_ACCOUNT, account);
String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
imei += context.getPackageName();
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
sent.put("account", account);
sent.put("deviceId",UUID.nameUUIDFromBytes(imei.getBytes()).toString().replaceAll("-", ""));
sent.put("channel", "android");
sent.put("device",android.os.Build.MODEL);
sent.put("version",getVersionName(context));
sent.put("osVersion",android.os.Build.VERSION.RELEASE);
sent.put("packageName",context.getPackageName());
sendRequest(context,sent);
}
protected static boolean autoBindAccount(Context context){
String account = CIMCacheToolkit.getInstance(context).getString(CIMCacheToolkit.KEY_ACCOUNT);
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
boolean isManualStoped = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
if( isManualStoped || account==null || account.trim().length()==0 || isManualDestory )
{
return false;
}
sendBindRequest(context,account);
return true;
}
/**
* 发送一个CIM请求
* @param context
* @body
*/
public static void sendRequest(Context context, SentBody body){
boolean isManualStop = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualStop || isManualDestory)
{
return ;
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(KEY_SEND_BODY, body);
serviceIntent.setAction(ACTION_SEND_REQUEST_BODY);
context.startService(serviceIntent);
}
/**
* 停止接受推送将会退出当前账号登录端口与服务端的连接
* @param context
*/
public static void stop(Context context){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory){
return ;
}
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, true);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_CLOSE_CIM_CONNECTION);
context.startService(serviceIntent);
}
/**
* 完全销毁CIM一般用于完全退出程序调用resume将不能恢复
* @param context
*/
public static void destroy(Context context){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, true);
CIMCacheToolkit.getInstance(context).remove(CIMCacheToolkit.KEY_ACCOUNT);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_DESTORY);
context.startService(serviceIntent);
}
/**
* 重新恢复接收推送重新连接服务端并登录当前账号如果aotuBind == true
* @param context
* @param aotuBind
*/
public static void resume(Context context){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory){
return ;
}
autoBindAccount(context);
}
public static boolean isConnected(Context context){
return CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE);
}
public static int getState(Context context){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory){
return STATE_DESTROYED;
}
boolean isManualStop = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
if(isManualStop){
return STATE_STOPED;
}
return STATE_NORMAL;
}
private static String getVersionName(Context context) {
String versionName = null;
try {
PackageInfo mPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
versionName = mPackageInfo.versionName;
} catch (NameNotFoundException e) {
}
return versionName;
}
}

View File

@ -0,0 +1,106 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import com.farsunset.cim.sdk.android.model.SentBody;
/**
* 与服务端连接服务
*
*/
public class CIMPushService extends Service {
protected final static int DEF_CIM_PORT = 28888;
CIMConnectorManager manager;
WakeLock wakeLock;
@Override
public void onCreate()
{
manager = CIMConnectorManager.getManager(this.getApplicationContext());
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, CIMPushService.class.getName());
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) {
if(intent==null)
{
return START_STICKY;
}
String action = intent.getAction();
if(CIMPushManager.ACTION_CREATE_CIM_CONNECTION.equals(action))
{
String host = CIMCacheToolkit.getInstance(this).getString(CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
int port =CIMCacheToolkit.getInstance(this).getInt(CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
manager.connect(host,port);
}
if(CIMPushManager.ACTION_SEND_REQUEST_BODY.equals(action))
{
manager.send((SentBody) intent.getSerializableExtra(CIMPushManager.KEY_SEND_BODY));
}
if(CIMPushManager.ACTION_CLOSE_CIM_CONNECTION.equals(action))
{
manager.closeSession();
}
if(CIMPushManager.ACTION_DESTORY.equals(action))
{
manager.destroy();
this.stopSelf();
android.os.Process.killProcess(android.os.Process.myPid());
}
if(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action) && !manager.isConnected())
{
String host = CIMCacheToolkit.getInstance(this).getString(CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
int port =CIMCacheToolkit.getInstance(this).getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
manager.connect(host,port);
}
try{
if(!wakeLock.isHeld())
{
this.wakeLock.acquire();
}
}catch(Exception e){}
return START_STICKY;
}
public void onDestroy()
{
super.onDestroy();
if(wakeLock.isHeld())
{
this.wakeLock.release();
wakeLock = null;
}
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.constant; package com.farsunset.cim.sdk.android.constant;
/** /**
* 常量 * 常量
@ -16,6 +16,7 @@ public interface CIMConstant {
public static byte MESSAGE_SEPARATE='\b'; public static byte MESSAGE_SEPARATE='\b';
public static long RECONN_INTERVAL_TIME= 30 * 1000;
public static int CIM_DEFAULT_MESSAGE_ORDER=1; public static int CIM_DEFAULT_MESSAGE_ORDER=1;
@ -37,13 +38,13 @@ public interface CIMConstant {
} }
/** /**
* 服务端心跳请求命令 * 服务端心跳请求命令 cmd_server_hb_request
*/ */
public static final String CMD_HEARTBEAT_REQUEST="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 ="cmd_client_hb_response"; public static final String CMD_HEARTBEAT_RESPONSE ="C_H_RS";
public static class RequestKey{ public static class RequestKey{

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.exception; package com.farsunset.cim.sdk.android.exception;
public class CIMSessionDisableException extends Exception { public class CIMSessionDisableException extends Exception {

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.exception; package com.farsunset.cim.sdk.android.exception;
public class NetWorkDisableException extends Exception { public class NetWorkDisableException extends Exception {

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.exception; package com.farsunset.cim.sdk.android.exception;
import java.io.Serializable; import java.io.Serializable;

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.filter; package com.farsunset.cim.sdk.android.filter;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFactory;

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.filter; package com.farsunset.cim.sdk.android.filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -21,9 +21,9 @@ import org.w3c.dom.NodeList;
import android.util.Log; import android.util.Log;
import com.farsunset.cim.client.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.client.model.Message; import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.client.model.ReplyBody; import com.farsunset.cim.sdk.android.model.ReplyBody;
/** /**
* 客户端消息解码 * 客户端消息解码
*/ */
@ -60,9 +60,6 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
String message = new String(bytes, CIMConstant.UTF8); String message = new String(bytes, CIMConstant.UTF8);
buff.clear(); buff.clear();
//打印出收到的消息
Log.i(TAG,message);
try try
{ {
Object msg = mappingMessageObject(message); Object msg = mappingMessageObject(message);
@ -71,7 +68,6 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
{ {
e.printStackTrace(); e.printStackTrace();
} }
} }
return complete; return complete;
@ -79,7 +75,10 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
private Object mappingMessageObject(String message) throws Exception { private Object mappingMessageObject(String message) throws Exception {
if(CIMConstant.CMD_HEARTBEAT_REQUEST.equals(message))
Log.i(TAG,message.toString());
if(CIMConstant.CMD_HEARTBEAT_REQUEST.equalsIgnoreCase(message))
{ {
return message; return message;
} }
@ -104,16 +103,61 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
if (name.equals("message")) { if (name.equals("message")) {
Message body = new Message(); Message body = new Message();
body.setType(doc.getElementsByTagName("type").item(0).getTextContent()); NodeList nodeList = doc.getElementsByTagName("message").item(0).getChildNodes();
body.setContent(doc.getElementsByTagName("content").item(0).getTextContent()); int count = nodeList.getLength();
body.setFile(doc.getElementsByTagName("file").item(0).getTextContent()); for(int i = 0;i < count; i++){
body.setFileType(doc.getElementsByTagName("fileType").item(0).getTextContent()); Node node = nodeList.item(i);
body.setTitle(doc.getElementsByTagName("title").item(0).getTextContent());
body.setSender(doc.getElementsByTagName("sender").item(0).getTextContent()); if(node.getNodeName().equals("mid"))
body.setReceiver(doc.getElementsByTagName("receiver").item(0).getTextContent()); {
body.setFormat(doc.getElementsByTagName("format").item(0).getTextContent()); body.setMid(node.getTextContent());
body.setMid(doc.getElementsByTagName("mid").item(0).getTextContent()); }
body.setTimestamp(Long.valueOf(doc.getElementsByTagName("timestamp").item(0).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("title"))
{
body.setTitle(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 body;
} }

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.filter; package com.farsunset.cim.sdk.android.filter;
@ -15,7 +15,7 @@ import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import android.util.Log; import android.util.Log;
import com.farsunset.cim.client.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
/** /**
* 客户端消息发送前进行编码,可在此加密消息 * 客户端消息发送前进行编码,可在此加密消息
*/ */

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.model; package com.farsunset.cim.sdk.android.model;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -137,27 +137,53 @@ public class Message implements Serializable {
this.format = format; this.format = format;
} }
public String toString() public String toString() {
{
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
buffer.append("<message>"); buffer.append("<message>");
buffer.append("<mid>").append(mid).append("</mid>"); buffer.append("<mid>").append(mid).append("</mid>");
if (isNotEmpty(type)) {
buffer.append("<type>").append(type).append("</type>"); buffer.append("<type>").append(type).append("</type>");
buffer.append("<title>").append(this.getTitle()==null?"":this.getTitle()).append("</title>"); }
buffer.append("<content><![CDATA[").append(this.getContent()==null?"":this.getContent()).append("]]></content>");
buffer.append("<file>").append(this.getFile()==null?"":this.getFile()).append("</file>"); if (isNotEmpty(title)) {
buffer.append("<fileType>").append(this.getFileType()==null?"":this.getFileType()).append("</fileType>"); buffer.append("<title>").append(title).append("</title>");
buffer.append("<sender>").append(this.getSender()==null?"":this.getSender()).append("</sender>"); }
buffer.append("<receiver>").append(this.getReceiver()==null?"":this.getReceiver()).append("</receiver>"); if (isNotEmpty(content)) {
buffer.append("<format>").append(this.getFormat()==null?"":this.getFormat()).append("</format>"); buffer.append("<content><![CDATA[").append(content).append("]]></content>");
}
if (isNotEmpty(file)) {
buffer.append("<file>").append(file).append("</file>");
}
if (isNotEmpty(fileType)) {
buffer.append("<fileType>").append(fileType).append("</fileType>");
}
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("<timestamp>").append(timestamp).append("</timestamp>");
}
buffer.append("</message>"); buffer.append("</message>");
return buffer.toString(); return buffer.toString();
} }
public String toXmlString()
{ public String toXmlString() {
return toString(); return toString();
} }
@ -170,5 +196,9 @@ public class Message implements Serializable {
this.mid = mid; this.mid = mid;
} }
public boolean isNotEmpty(String txt) {
return txt != null && !txt.isEmpty();
}
} }

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.model; package com.farsunset.cim.sdk.android.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;

View File

@ -4,7 +4,7 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.model; package com.farsunset.cim.sdk.android.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;

View File

@ -2,7 +2,7 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/log4j.jar"/> <classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/mina-core-2.0.9.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/mina-core-2.0.13.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.constant; package com.farsunset.cim.sdk.server.constant;
/** /**
* 常量 * 常量
@ -31,6 +31,8 @@ public interface CIMConstant {
public static String UTF8="UTF-8"; public static String UTF8="UTF-8";
public static byte MESSAGE_SEPARATE='\b'; public static byte MESSAGE_SEPARATE='\b';
//flex客户端 安全策略验证时会收到<policy-file- request/>\0
public static byte FLEX_DATA_SEPARATE = '\0';
public static int CIM_DEFAULT_MESSAGE_ORDER=1; public static int CIM_DEFAULT_MESSAGE_ORDER=1;
@ -49,21 +51,13 @@ public interface CIMConstant {
public static final String FLEX_POLICY_RESPONSE ="<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0"; public static final String FLEX_POLICY_RESPONSE ="<?xml version=\"1.0\"?><cross-domain-policy><site-control permitted-cross-domain-policies=\"all\"/><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0";
/** /**
* 服务端心跳请求命令 * 服务端心跳请求命令 cmd_server_hb_request
*/ */
public static final String CMD_HEARTBEAT_REQUEST="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 ="cmd_client_hb_response";
/**
* 对应ichat spring-cim.xml > bean:mainIoHandler >handlers
* 服务端处理对应的handlers应该继承与com.farsunset.cim.nio.handle.AbstractHandler
*
*/ */
public static final String CMD_HEARTBEAT_RESPONSE ="C_H_RS";

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.filter; package com.farsunset.cim.sdk.server.filter;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory; import org.apache.mina.filter.codec.ProtocolCodecFactory;

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.filter; package com.farsunset.cim.sdk.server.filter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -20,8 +20,8 @@ import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
/** /**
* 服务端接收消息解码可在此解密消息 * 服务端接收消息解码可在此解密消息
*/ */
@ -42,7 +42,7 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
complete = true; complete = true;
break; break;
}else if(b == '\0')//flex客户端 安全策略验证时会收到<policy-file- request/>\0的消息忽略此消息内容 }else if(b == CIMConstant.FLEX_DATA_SEPARATE)//flex客户端 安全策略验证时会收到<policy-file- request/>\0的消息忽略此消息内容
{ {
complete = true; complete = true;
break; break;
@ -66,7 +66,9 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
Object body = getSentBody(message); Object body = getSentBody(message);
out.write(body); out.write(body);
}catch(Exception e){ }catch(Exception e){
out.write(message);//解析xml失败 是返回原始的xml数据到上层处理,比如心跳响应flex sokcet的 安全验证请求xml out.write(message);//解析xml失败 是返回原始的xml数据到上层处理,比如flex sokcet的 安全验证请求xml
e.printStackTrace();
logger.warn(e.getMessage());
} }
} }
return complete; return complete;
@ -75,6 +77,11 @@ public class ServerMessageDecoder extends CumulativeProtocolDecoder {
public Object getSentBody(String message) throws Exception public Object getSentBody(String message) throws Exception
{ {
if(CIMConstant.CMD_HEARTBEAT_RESPONSE.equalsIgnoreCase(message))
{
return CIMConstant.CMD_HEARTBEAT_RESPONSE;
}
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

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.filter; package com.farsunset.cim.sdk.server.filter;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.IoBuffer;
@ -12,7 +12,7 @@ import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter; import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
/** /**
* 服务端发送消息前编码可在此加密消息 * 服务端发送消息前编码可在此加密消息

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.handler; package com.farsunset.cim.sdk.server.handler;
import java.util.HashMap; import java.util.HashMap;
@ -13,10 +13,10 @@ import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
import com.farsunset.cim.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.ReplyBody;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.CIMSession;
/** /**
* *
@ -84,7 +84,7 @@ public class CIMIoHandler extends IoHandlerAdapter {
CIMSession cimSession =new CIMSession(ios); CIMSession cimSession =new CIMSession(ios);
try{ try{
logger.debug("sessionClosed()... from "+cimSession.getRemoteAddress()); logger.warn("sessionClosed()... from "+cimSession.getRemoteAddress());
CIMRequestHandler handler = handlers.get(CIMSESSION_CLOSED_HANDLER_KEY); CIMRequestHandler handler = handlers.get(CIMSESSION_CLOSED_HANDLER_KEY);
if(handler!=null && cimSession.containsAttribute(CIMConstant.SESSION_KEY)) if(handler!=null && cimSession.containsAttribute(CIMConstant.SESSION_KEY))
{ {

View File

@ -1,18 +1,18 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.handler; package com.farsunset.cim.sdk.server.handler;
/** /**
* 请求处理接口,所有的请求实现必须实现此接口 * 请求处理接口,所有的请求实现必须实现此接口
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
import com.farsunset.cim.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.ReplyBody;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.CIMSession;
public interface CIMRequestHandler { public interface CIMRequestHandler {

View File

@ -1,9 +1,15 @@
package com.farsunset.cim.server.handler; /**
* probject:cim-server-sdk
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.server.handler;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory; import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
public class ServerKeepAliveFactoryImpl implements KeepAliveMessageFactory { public class ServerKeepAliveFactoryImpl implements KeepAliveMessageFactory {
@Override @Override
@ -23,7 +29,7 @@ public class ServerKeepAliveFactoryImpl implements KeepAliveMessageFactory {
@Override @Override
public boolean isResponse(IoSession arg0, Object arg1) { public boolean isResponse(IoSession arg0, Object arg1) {
return CIMConstant.CMD_HEARTBEAT_RESPONSE.equals(arg1); return CIMConstant.CMD_HEARTBEAT_RESPONSE.equalsIgnoreCase(arg1.toString());
} }
} }

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.server.handler; /**
* probject:cim-server-sdk
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.server.launcher;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -17,21 +23,24 @@ import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.DefaultSocketSessionConfig; import org.apache.mina.transport.socket.DefaultSocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import com.farsunset.cim.sdk.server.handler.ServerKeepAliveFactoryImpl;
public class CIMNioSocketAcceptor { public class CIMNioSocketAcceptor {
IoAcceptor acceptor; IoAcceptor acceptor;
IoHandler ioHandler; IoHandler ioHandler;
int port; int port;
private final int IDLE_TIME = 60;// private final int IDLE_TIME = 300;//
private final int TIME_OUT = 30;// private final int TIME_OUT = 10;//
public void bind() throws IOException public void bind() throws IOException
{ {
acceptor = new NioSocketAcceptor(); acceptor = new NioSocketAcceptor();
acceptor.getSessionConfig().setReadBufferSize(1024); acceptor.getSessionConfig().setReadBufferSize(1024);
((DefaultSocketSessionConfig)acceptor.getSessionConfig()).setTcpNoDelay(true); ((DefaultSocketSessionConfig)acceptor.getSessionConfig()).setTcpNoDelay(true);
acceptor.getSessionConfig().setBothIdleTime(IDLE_TIME);
acceptor.getFilterChain().addLast("executor",new ExecutorFilter()); acceptor.getFilterChain().addLast("executor",new ExecutorFilter());
acceptor.getFilterChain().addLast("logger",new LoggingFilter()); acceptor.getFilterChain().addLast("logger",new LoggingFilter());
acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new com.farsunset.cim.server.filter.ServerMessageCodecFactory())); acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new com.farsunset.cim.sdk.server.filter.ServerMessageCodecFactory()));
KeepAliveMessageFactory heartBeatFactory = new ServerKeepAliveFactoryImpl(); KeepAliveMessageFactory heartBeatFactory = new ServerKeepAliveFactoryImpl();
KeepAliveFilter keepAliveFilter = new KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE,KeepAliveRequestTimeoutHandler.CLOSE,IDLE_TIME,TIME_OUT); KeepAliveFilter keepAliveFilter = new KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE,KeepAliveRequestTimeoutHandler.CLOSE,IDLE_TIME,TIME_OUT);
keepAliveFilter.setForwardEvent(true); keepAliveFilter.setForwardEvent(true);

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.model; package com.farsunset.cim.sdk.server.model;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -137,27 +137,53 @@ public class Message implements Serializable {
this.format = format; this.format = format;
} }
public String toString() public String toString() {
{
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
buffer.append("<message>"); buffer.append("<message>");
buffer.append("<mid>").append(mid).append("</mid>"); buffer.append("<mid>").append(mid).append("</mid>");
if (isNotEmpty(type)) {
buffer.append("<type>").append(type).append("</type>"); buffer.append("<type>").append(type).append("</type>");
buffer.append("<title>").append(this.getTitle()==null?"":this.getTitle()).append("</title>"); }
buffer.append("<content><![CDATA[").append(this.getContent()==null?"":this.getContent()).append("]]></content>");
buffer.append("<file>").append(this.getFile()==null?"":this.getFile()).append("</file>"); if (isNotEmpty(title)) {
buffer.append("<fileType>").append(this.getFileType()==null?"":this.getFileType()).append("</fileType>"); buffer.append("<title>").append(title).append("</title>");
buffer.append("<sender>").append(this.getSender()==null?"":this.getSender()).append("</sender>"); }
buffer.append("<receiver>").append(this.getReceiver()==null?"":this.getReceiver()).append("</receiver>"); if (isNotEmpty(content)) {
buffer.append("<format>").append(this.getFormat()==null?"":this.getFormat()).append("</format>"); buffer.append("<content><![CDATA[").append(content).append("]]></content>");
}
if (isNotEmpty(file)) {
buffer.append("<file>").append(file).append("</file>");
}
if (isNotEmpty(fileType)) {
buffer.append("<fileType>").append(fileType).append("</fileType>");
}
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("<timestamp>").append(timestamp).append("</timestamp>");
}
buffer.append("</message>"); buffer.append("</message>");
return buffer.toString(); return buffer.toString();
} }
public String toXmlString()
{ public String toXmlString() {
return toString(); return toString();
} }
@ -170,5 +196,9 @@ public class Message implements Serializable {
this.mid = mid; this.mid = mid;
} }
public boolean isNotEmpty(String txt) {
return txt != null && !txt.isEmpty();
}
} }

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.model; package com.farsunset.cim.sdk.server.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.model; package com.farsunset.cim.sdk.server.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,10 +1,10 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.session; package com.farsunset.cim.sdk.server.session;
import java.io.Serializable; import java.io.Serializable;
import java.net.InetAddress; import java.net.InetAddress;
@ -13,7 +13,7 @@ import java.net.UnknownHostException;
import org.apache.mina.core.session.IoSession; import org.apache.mina.core.session.IoSession;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
/** /**
* IoSession包装类,集群时 将此对象存入表中 * IoSession包装类,集群时 将此对象存入表中
@ -27,8 +27,8 @@ public class CIMSession implements Serializable{
private transient static final long serialVersionUID = 1L; private transient static final long serialVersionUID = 1L;
public transient static String ID = "ID"; public transient static String ID = "ID";
public transient static String HOST = "HOST"; public transient static String HOST = "HOST";
public transient static final int STATUS_ENABLE=0; public transient static final int STATUS_ENABLED = 0;
public transient static final int STATUS_DISENABLE=1; public transient static final int STATUS_DISABLED = 1;
public transient static final int APNS_ON=1; public transient static final int APNS_ON=1;
public transient static final int APNS_OFF=0; public transient static final int APNS_OFF=0;
@ -40,7 +40,7 @@ public class CIMSession implements Serializable{
private transient IoSession session; private transient IoSession session;
private String gid;//session全局ID private String gid;//session全局ID
private Long nid;//session在本台服务器上的ID private long nid;//session在本台服务器上的ID
private String deviceId;//客户端ID (设备号码+应用包名),ios为devicetoken private String deviceId;//客户端ID (设备号码+应用包名),ios为devicetoken
private String host;//session绑定的服务器IP private String host;//session绑定的服务器IP
private String account;//session绑定的账号 private String account;//session绑定的账号
@ -48,6 +48,7 @@ public class CIMSession implements Serializable{
private String deviceModel;//终端设备型号 private String deviceModel;//终端设备型号
private String clientVersion;//终端应用版本 private String clientVersion;//终端应用版本
private String systemVersion;//终端系统版本 private String systemVersion;//终端系统版本
private String packageName;//终端应用包名
private Long bindTime;//登录时间 private Long bindTime;//登录时间
private Long heartbeat;//心跳时间 private Long heartbeat;//心跳时间
private Double longitude;//经度 private Double longitude;//经度
@ -217,6 +218,8 @@ public class CIMSession implements Serializable{
} }
public int getApnsAble() { public int getApnsAble() {
return apnsAble; return apnsAble;
} }
@ -265,16 +268,26 @@ public class CIMSession implements Serializable{
return null; return null;
} }
public void write(Object msg) { public boolean write(Object msg) {
if(session!=null) if(session!=null)
{ {
session.write(msg).isWritten(); return session.write(msg).isWritten();
} }
return false;
} }
public boolean isConnected() { public boolean isConnected() {
if(session!=null) if(session != null && isLocalhost())
{
return session.isConnected(); return session.isConnected();
}
if(!isLocalhost())
{
return status == STATUS_ENABLED;
}
return false; return false;
} }
@ -292,25 +305,56 @@ public class CIMSession implements Serializable{
} }
public void close(boolean immediately) { public void closeNow() {
if(session!=null) if(session!=null)
session.close(immediately); session.closeNow();
}
public void closeOnFlush() {
if(session!=null)
session.closeOnFlush();
} }
public void setPackageName(String packageName) {
this.packageName = packageName;
setAttribute("packageName", apnsAble);
}
public String getPackageName() {
return packageName;
}
public boolean equals(Object o) { public boolean equals(Object o) {
if (o instanceof CIMSession) { if (o instanceof CIMSession) {
CIMSession t = (CIMSession) o; CIMSession t = (CIMSession) o;
if(t.deviceId!=null && deviceId!=null && t.nid!=null && nid!=null) if(t.deviceId!=null && deviceId!=null)
{ {
return t.deviceId.equals(deviceId) && t.nid.longValue()==nid.longValue() && t.host.equals(host); return t.deviceId.equals(deviceId) && t.nid == nid && t.host.equals(host);
} }
} }
return false; return false;
} }
public boolean fromOtherDevice(Object o) {
if (o instanceof CIMSession) {
CIMSession t = (CIMSession) o;
if(t.deviceId!=null && deviceId!=null)
{
return !t.deviceId.equals(deviceId);
}
}
return false;
}
public boolean fromCurrentDevice(Object o) {
return !fromOtherDevice(o);
}
public void setIoSession(IoSession session) { public void setIoSession(IoSession session) {
this.session = session; this.session = session;
} }
@ -343,4 +387,5 @@ public class CIMSession implements Serializable{
} }
} }

View File

@ -1,16 +1,16 @@
/** /**
* probject:cim-core * probject:cim-server-sdk
* @version 1.5.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.server.session; package com.farsunset.cim.sdk.server.session;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
/** /**
* 自带默认 session管理实现 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 * 自带默认 session管理实现 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理
@ -29,7 +29,7 @@ public class DefaultSessionManager implements SessionManager{
/** /**
* *
*/ */
public void addSession(String account,CIMSession session) { public void add(String account,CIMSession session) {
if(session!=null) if(session!=null)
{ {
session.setAttribute(CIMConstant.SESSION_KEY, account); session.setAttribute(CIMConstant.SESSION_KEY, account);
@ -40,7 +40,7 @@ public class DefaultSessionManager implements SessionManager{
} }
public CIMSession getSession(String account) { public CIMSession get(String account) {
return sessions.get(account); return sessions.get(account);
@ -49,18 +49,20 @@ public class DefaultSessionManager implements SessionManager{
public Collection<CIMSession> getSessions() { public List<CIMSession> queryAll() {
return sessions.values(); List<CIMSession> list = new ArrayList<CIMSession>();
list.addAll(sessions.values());
return list;
} }
public void removeSession(CIMSession session) { public void remove(CIMSession session) {
sessions.remove(session.getAttribute(CIMConstant.SESSION_KEY)); sessions.remove(session.getAttribute(CIMConstant.SESSION_KEY));
} }
public void removeSession(String account) { public void remove(String account) {
sessions.remove(account); sessions.remove(account);
@ -94,14 +96,15 @@ public class DefaultSessionManager implements SessionManager{
@Override @Override
public void updateSession(CIMSession session) { public void update(CIMSession session) {
sessions.put(session.getAccount(), session); sessions.put(session.getAccount(), session);
} }
@Override @Override
public void setInvalid(String account) { public void setState(String account,int state) {
sessions.get(account).setStatus(CIMSession.STATUS_DISENABLE); sessions.get(account).setStatus(state);
} }
} }

View File

@ -0,0 +1,55 @@
/**
* probject:cim-server-sdk
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.server.session;
import java.util.List;
/**
* 客户端的 session管理接口
* 可自行实现此接口管理session
*/
public interface SessionManager {
/**
* 添加新的session
*/
public void add(String account,CIMSession session);
/**
* 更新session
*/
public void update(CIMSession session);
/**
*
* @param account 客户端session的 key 一般可用 用户账号来对应session
* @return
*/
CIMSession get(String account);
/**
* 获取所有session
* @return
*/
public List<CIMSession> queryAll();
/**
* 删除session
* @param session
*/
public void remove(String account);
/**
* 设置session失效
* @param session
*/
public void setState(String account,int state);
}

View File

@ -1,63 +0,0 @@
/**
* probject:cim-core
* @version 1.5.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.server.session;
import java.util.Collection;
/**
* 客户端的 session管理接口
* 可自行实现此接口管理session
*/
public interface SessionManager {
/**
* 添加新的session
*/
public void addSession(String account,CIMSession session);
/**
* 添加新的session
*/
public void updateSession(CIMSession session);
/**
*
* @param account 客户端session的 key 一般可用 用户账号来对应session
* @return
*/
CIMSession getSession(String account);
/**
* 获取所有session
* @return
*/
public Collection<CIMSession> getSessions();
/**
* 删除session
* @param session
*/
public void removeSession(String account);
/**
* 删除session
* @param session
*/
public void setInvalid(String account);
/**
* session是否存在
* @param session
*/
public boolean containsCIMSession(String account);
}

View File

@ -30,8 +30,6 @@
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/httpcore-4.3.2.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/httpcore-4.3.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/jstl-1.2.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/jstl-1.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/log4j.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/log4j.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mina-core-2.0.9.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mina-integration-beans-2.0.9.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/ognl-2.7.3.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/ognl-2.7.3.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-api-1.7.5.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-api-1.7.5.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-nop-1.7.5.jar"/> <classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-nop-1.7.5.jar"/>
@ -39,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/mina-core-2.0.13.jar"/>
<classpathentry kind="output" path="WebRoot/WEB-INF/classes"/> <classpathentry kind="output" path="WebRoot/WEB-INF/classes"/>
</classpath> </classpath>

View File

@ -1,4 +1,4 @@
log4j.rootLogger=warn,console, file log4j.rootLogger=debug,console, file
#----------console---------------- #----------console----------------
log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console=org.apache.log4j.ConsoleAppender

View File

@ -13,20 +13,7 @@
" "
> >
<!-- =============================================================== --> <bean id="cimIoHandler" class="com.farsunset.cim.sdk.server.handler.CIMIoHandler" >
<!-- MINA -->
<!-- =============================================================== -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.net.SocketAddress">
<bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
</entry>
</map>
</property>
</bean>
<bean id="cimIoHandler" class="com.farsunset.cim.server.handler.CIMIoHandler" >
<property name="handlers"> <property name="handlers">
<map> <map>
@ -50,13 +37,13 @@
<bean id="CIMNioAcceptor" class="com.farsunset.cim.server.handler.CIMNioSocketAcceptor" <bean id="CIMNioAcceptor" class="com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor"
init-method="bind" destroy-method="unbind"> init-method="bind" destroy-method="unbind">
<property name="port" value="23456" /> <property name="port" value="23456" />
<property name="ioHandler" ref="cimIoHandler" /> <property name="ioHandler" ref="cimIoHandler" />
</bean> </bean>
<bean id="CIMSessionManager" class="com.farsunset.cim.server.session.DefaultSessionManager"/> <bean id="CIMSessionManager" class="com.farsunset.cim.sdk.server.session.DefaultSessionManager"/>
<!-- 集群服务器时 CIMSessionManager 配置 <!-- 集群服务器时 CIMSessionManager 配置
<bean id="CIMSessionManager" class="com.farsunset.lvxin.cim.session.ClusterSessionManager"> <bean id="CIMSessionManager" class="com.farsunset.lvxin.cim.session.ClusterSessionManager">

View File

@ -1,13 +1,13 @@
<%@ page language="java" pageEncoding="utf-8"%> <%@ page language="java" pageEncoding="utf-8"%>
<%@ page import="java.util.Collection"%> <%@ page import="java.util.List"%>
<%@ page import="com.farsunset.cim.server.session.CIMSession"%> <%@ page import="com.farsunset.cim.sdk.server.session.CIMSession"%>
<% <%
String path = request.getContextPath(); String path = request.getContextPath();
String basePath = request.getScheme() + "://" String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort() + request.getServerName() + ":" + request.getServerPort()
+ path; + path;
Collection<CIMSession> sessionList = (Collection<CIMSession>)request.getAttribute("sessionList"); List<CIMSession> sessionList = (List<CIMSession> )request.getAttribute("sessionList");
%> %>
<!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">
@ -92,6 +92,7 @@
<th width="4%">头像</th> <th width="4%">头像</th>
<th width="15%">账号</th> <th width="15%">账号</th>
<th width="10%">终端</th> <th width="10%">终端</th>
<th width="10%">终端版本</th>
<th width="10%">应用版本</th> <th width="10%">应用版本</th>
<th width="10%">设备型号</th> <th width="10%">设备型号</th>
<th width="10%">在线时长</th> <th width="10%">在线时长</th>
@ -118,6 +119,9 @@
<td> <td>
<%=ios.getChannel()%> <%=ios.getChannel()%>
</td> </td>
<td>
<%=ios.getSystemVersion()==null?"":ios.getSystemVersion()%>
</td>
<td> <td>
<%=ios.getClientVersion()==null?"":ios.getClientVersion()%> <%=ios.getClientVersion()==null?"":ios.getClientVersion()%>
</td> </td>

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.admin.action; package com.farsunset.cim.admin.action;
@ -6,8 +12,8 @@ import java.io.IOException;
import org.apache.struts2.ServletActionContext; import org.apache.struts2.ServletActionContext;
import com.farsunset.cim.push.SystemMessagePusher; import com.farsunset.cim.push.SystemMessagePusher;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.server.session.DefaultSessionManager; import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
import com.farsunset.cim.util.ContextHolder; import com.farsunset.cim.util.ContextHolder;
import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ActionSupport;
public class SessionAction extends ActionSupport { public class SessionAction extends ActionSupport {
@ -23,7 +29,7 @@ public class SessionAction extends ActionSupport {
public String list() public String list()
{ {
ServletActionContext.getRequest().setAttribute("sessionList", ((DefaultSessionManager) ContextHolder.getBean("CIMSessionManager")).getSessions()); ServletActionContext.getRequest().setAttribute("sessionList", ((DefaultSessionManager) ContextHolder.getBean("CIMSessionManager")).queryAll());
return "list"; return "list";
} }
@ -37,7 +43,7 @@ public class SessionAction extends ActionSupport {
msg.setReceiver(account); msg.setReceiver(account);
//向客户端 发送消息 //向客户端 发送消息
ContextHolder.getBean(SystemMessagePusher.class).pushMessageToUser(msg); ContextHolder.getBean(SystemMessagePusher.class).push(msg);
} }
} }

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.api.action; package com.farsunset.cim.api.action;
import java.util.HashMap; import java.util.HashMap;
@ -8,9 +14,10 @@ import org.springframework.web.bind.ServletRequestBindingException;
import com.farsunset.cim.push.DefaultMessagePusher; import com.farsunset.cim.push.DefaultMessagePusher;
import com.farsunset.cim.push.SystemMessagePusher; import com.farsunset.cim.push.SystemMessagePusher;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.util.Constants; import com.farsunset.cim.util.Constants;
import com.farsunset.cim.util.ContextHolder; import com.farsunset.cim.util.ContextHolder;
import com.farsunset.cim.util.StringUtil;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven; import com.opensymphony.xwork2.ModelDriven;
@ -43,15 +50,15 @@ public class MessageAction extends ActionSupport implements ModelDriven<Messa
try{ try{
checkParams(); checkParams();
message.setMid(StringUtil.getUUID());
if(Constants.MessageType.TYPE_2.equals(message.getType())) if(Constants.MessageType.TYPE_2.equals(message.getType()))
{ {
//向客户端 发送消息 //向客户端 发送消息
ContextHolder.getBean(SystemMessagePusher.class).pushMessageToUser(message); ContextHolder.getBean(SystemMessagePusher.class).push(message);
}else }else
{ {
//向客户端 发送消息 //向客户端 发送消息
((DefaultMessagePusher)ContextHolder.getBean("messagePusher")).pushMessageToUser(message); ((DefaultMessagePusher)ContextHolder.getBean("messagePusher")).push(message);
} }
data.put("id", message.getMid()); data.put("id", message.getMid());

View File

@ -1,89 +1,109 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.handler; package com.farsunset.cim.handler;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.UUID;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.farsunset.cim.push.SystemMessagePusher;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
import com.farsunset.cim.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.ReplyBody;
import com.farsunset.cim.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.session.CIMSession;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
import com.farsunset.cim.server.session.DefaultSessionManager;
import com.farsunset.cim.util.ContextHolder; import com.farsunset.cim.util.ContextHolder;
import com.farsunset.cim.util.StringUtil;
/** /**
* 账号绑定实现 * 账号绑定实现
* *
* @author
*/ */
public class BindHandler implements CIMRequestHandler { public class BindHandler implements CIMRequestHandler {
protected final Logger logger = Logger.getLogger(BindHandler.class); protected final Logger logger = Logger.getLogger(BindHandler.class);
public ReplyBody process(CIMSession newSession, SentBody message) { public ReplyBody process(CIMSession newSession, SentBody message) {
DefaultSessionManager sessionManager = ((DefaultSessionManager) ContextHolder.getBean("CIMSessionManager"));
ReplyBody reply = new ReplyBody(); ReplyBody reply = new ReplyBody();
DefaultSessionManager sessionManager= ((DefaultSessionManager) ContextHolder.getBean("CIMSessionManager")); reply.setCode(CIMConstant.ReturnCode.CODE_200);
try { try {
String account = message.get("account"); String account = message.get("account");
newSession.setGid(StringUtil.getUUID());
newSession.setAccount(account); newSession.setAccount(account);
newSession.setDeviceId(message.get("deviceId")); newSession.setDeviceId(message.get("deviceId"));
newSession.setGid(UUID.randomUUID().toString());
newSession.setHost(InetAddress.getLocalHost().getHostAddress()); newSession.setHost(InetAddress.getLocalHost().getHostAddress());
newSession.setChannel( message.get("channel")); newSession.setChannel( message.get("channel"));
newSession.setDeviceModel(message.get("device")); newSession.setDeviceModel(message.get("device"));
newSession.setClientVersion(message.get("appVersion")); newSession.setClientVersion(message.get("version"));
//第一次设置心跳时间为登录时间 newSession.setSystemVersion(message.get("osVersion"));
newSession.setBindTime(System.currentTimeMillis()); newSession.setBindTime(System.currentTimeMillis());
newSession.setHeartbeat(System.currentTimeMillis()); newSession.setPackageName(message.get("packageName"));
/** /**
* 由于客户端断线服务端可能会无法获知的情况客户端重连时需要关闭旧的连接 * 由于客户端断线服务端可能会无法获知的情况客户端重连时需要关闭旧的连接
*/ */
CIMSession oldSession = sessionManager.getSession(account); CIMSession oldSession = sessionManager.get(account);
//如果是账号已经在另一台终端登录则让另一个终端下线 //如果是账号已经在另一台终端登录则让另一个终端下线
if(oldSession!=null&&!oldSession.equals(newSession)) if(oldSession!=null)
{ {
if(oldSession.fromOtherDevice(newSession))
{
sendForceOfflineMessage(oldSession,account);
}
if(oldSession.equals(newSession))
{
reply.put("sid", oldSession.getGid());
return reply;
}
oldSession.removeAttribute(CIMConstant.SESSION_KEY); oldSession.removeAttribute(CIMConstant.SESSION_KEY);
Message msg = new Message(); oldSession.closeNow();
msg.setType(CIMConstant.MessageType.TYPE_999);//强行下线消息类型
msg.setReceiver(account);
if(!oldSession.isLocalhost())
{
/*
判断当前session是否连接于本台服务器如不是发往目标服务器处理
MessageDispatcher.execute(msg, oldSession.getHost());
*/
}else
{
oldSession.write(msg);
oldSession.close(true);
oldSession = null;
}
oldSession = null;
}
if(oldSession==null)
{
sessionManager.addSession(account, newSession);
} }
reply.setCode(CIMConstant.ReturnCode.CODE_200);
//第一次设置心跳时间为登录时间
newSession.setBindTime(System.currentTimeMillis());
newSession.setHeartbeat(System.currentTimeMillis());
sessionManager.add(account, newSession);
} catch (Exception e) { } catch (Exception e) {
reply.setCode(CIMConstant.ReturnCode.CODE_500); reply.setCode(CIMConstant.ReturnCode.CODE_500);
e.printStackTrace(); e.printStackTrace();
} }
logger.debug("bind :account:" +message.get("account")+"-----------------------------" +reply.getCode()); logger.debug("bind :account:" +message.get("account")+"-----------------------------" +reply.getCode());
reply.put("sid", newSession.getGid());
return reply; return reply;
} }
private void sendForceOfflineMessage(CIMSession oldSession,String account){
com.farsunset.cim.sdk.server.model.Message msg = new com.farsunset.cim.sdk.server.model.Message();
msg.setType(CIMConstant.MessageType.TYPE_999);//强行下线消息类型
msg.setReceiver(account);
if(oldSession.isLocalhost() && oldSession.isConnected())
{
oldSession.write(msg);
oldSession.closeOnFlush();
}
if(!oldSession.isLocalhost())
{
ContextHolder.getBean(SystemMessagePusher.class).push(msg);
}
oldSession.removeAttribute(CIMConstant.SESSION_KEY);
}
} }

View File

@ -1,19 +1,22 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.handler; package com.farsunset.cim.handler;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
import com.farsunset.cim.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
import com.farsunset.cim.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.ReplyBody;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.CIMSession;
import com.farsunset.cim.server.session.DefaultSessionManager; import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
import com.farsunset.cim.util.ContextHolder; import com.farsunset.cim.util.ContextHolder;
/** /**
* 退出连接实现 * 退出连接实现
*
* @author 3979434@qq.com
*/ */
public class LogoutHandler implements CIMRequestHandler { public class LogoutHandler implements CIMRequestHandler {
@ -24,9 +27,8 @@ public class LogoutHandler implements CIMRequestHandler {
String account =ios.getAttribute(CIMConstant.SESSION_KEY).toString(); String account =ios.getAttribute(CIMConstant.SESSION_KEY).toString();
ios.removeAttribute(CIMConstant.SESSION_KEY); ios.removeAttribute(CIMConstant.SESSION_KEY);
ios.close(true); ios.closeNow();
sessionManager.remove(account);
sessionManager.removeSession(account);
return null; return null;
} }

View File

@ -1,6 +1,6 @@
/** /**
* probject:cim * probject:cim
* @version 1.1.0 * @version 2.0
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
@ -11,12 +11,12 @@ import java.util.List;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
import com.farsunset.cim.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.ReplyBody;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.CIMSession;
/** /**
* 推送离线消息 * 推送离线消息
*/ */

View File

@ -1,20 +1,24 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.handler; package com.farsunset.cim.handler;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.farsunset.cim.server.constant.CIMConstant; import com.farsunset.cim.sdk.server.constant.CIMConstant;
import com.farsunset.cim.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
import com.farsunset.cim.server.model.ReplyBody; import com.farsunset.cim.sdk.server.model.ReplyBody;
import com.farsunset.cim.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.CIMSession;
import com.farsunset.cim.server.session.DefaultSessionManager; import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
import com.farsunset.cim.util.ContextHolder; import com.farsunset.cim.util.ContextHolder;
/** /**
* 断开连接清除session * 断开连接清除session
* *
* @author
*/ */
public class SessionClosedHandler implements CIMRequestHandler { public class SessionClosedHandler implements CIMRequestHandler {
@ -30,7 +34,7 @@ public class SessionClosedHandler implements CIMRequestHandler {
} }
String account = ios.getAttribute(CIMConstant.SESSION_KEY).toString(); String account = ios.getAttribute(CIMConstant.SESSION_KEY).toString();
sessionManager.removeSession(account); sessionManager.remove(account);
return null; return null;
} }

View File

@ -1,12 +1,17 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.push; package com.farsunset.cim.push;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
/** /**
* 消息发送实接口 * 消息发送实接口
* *
* @author farsunset (3979434@qq.com)
*/ */
public interface CIMMessagePusher { public interface CIMMessagePusher {
@ -16,7 +21,7 @@ public interface CIMMessagePusher {
* 向用户发送消息 * 向用户发送消息
* @param msg * @param msg
*/ */
public void pushMessageToUser(Message msg); public void push(Message msg);
} }

View File

@ -1,17 +1,23 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.push; package com.farsunset.cim.push;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
import com.farsunset.cim.server.session.CIMSession; import com.farsunset.cim.sdk.server.session.CIMSession;
import com.farsunset.cim.server.session.DefaultSessionManager; import com.farsunset.cim.sdk.server.session.DefaultSessionManager;
/** /**
* 消息发送实现类 * 消息发送实现类
* *
* @author farsunset (3979434@qq.com)
*/ */
public class DefaultMessagePusher implements CIMMessagePusher { public class DefaultMessagePusher implements CIMMessagePusher {
@ -29,8 +35,8 @@ public class DefaultMessagePusher implements CIMMessagePusher {
* 向用户发送消息 * 向用户发送消息
* @param msg * @param msg
*/ */
public void pushMessageToUser(Message msg) { public void push(Message msg) {
CIMSession session = sessionManager.getSession(msg.getReceiver()); CIMSession session = sessionManager.get(msg.getReceiver());
/*服务器集群时可以在此 判断当前session是否连接于本台服务器如果是继续往下走如果不是将此消息发往当前session连接的服务器并 return /*服务器集群时可以在此 判断当前session是否连接于本台服务器如果是继续往下走如果不是将此消息发往当前session连接的服务器并 return
if(!session.isLocalhost()){//判断当前session是否连接于本台服务器如不是 if(!session.isLocalhost()){//判断当前session是否连接于本台服务器如不是

View File

@ -1,31 +1,21 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.push; package com.farsunset.cim.push;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
/**
*
* @author farsunset (3979434@qq.com)
*/
public class SystemMessagePusher extends DefaultMessagePusher{ public class SystemMessagePusher extends DefaultMessagePusher{
/**
* Constructor.
*/
public SystemMessagePusher() {
super();
}
@Override @Override
public void pushMessageToUser(Message MessageMO){ public void push(Message message){
MessageMO.setSender("system"); message.setSender("system");
super.pushMessageToUser(MessageMO); super.push(message);
} }
} }

View File

@ -1,28 +1,25 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.session; package com.farsunset.cim.session;
import java.util.Collection; import java.util.List;
import com.farsunset.cim.sdk.server.session.CIMSession;
import com.farsunset.cim.sdk.server.session.SessionManager;
import com.farsunset.cim.server.session.CIMSession;
import com.farsunset.cim.server.session.SessionManager;
/** /**
* 集群 session管理实现示例 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理 * 集群 session管理实现示例 各位可以自行实现 AbstractSessionManager接口来实现自己的 session管理
*服务器集群时 须要将CIMSession 信息存入数据库或者nosql 第三方存储空间中便于所有服务器都可以访问 *服务器集群时 须要将CIMSession 信息存入数据库或者nosql 第三方存储空间中便于所有服务器都可以访问
* @author farsunset (3979434@qq.com)
*/ */
public class ClusterSessionManager implements SessionManager{ public class ClusterSessionManager implements SessionManager{
// private static HashMap<String,IoSession> sessions =new HashMap<String,IoSession>();
/**
*
*/
public void addSession(String account,CIMSession session) { public void addSession(String account,CIMSession session) {
@ -33,7 +30,7 @@ public class ClusterSessionManager implements SessionManager{
} }
public CIMSession getSession(String account) { public CIMSession get(String account) {
//这里查询数据库 //这里查询数据库
/*CIMSession session = database.getSession(account); /*CIMSession session = database.getSession(account);
@ -43,57 +40,38 @@ public class ClusterSessionManager implements SessionManager{
} }
@Override
public Collection<CIMSession> getSessions() { public List<CIMSession> queryAll() {
/*//这里查询数据库 /*//这里查询数据库
return database.getSessions();*/ return database.getSessions();*/
return null; return null;
} }
public void removeSession(CIMSession session) {
@Override
//database.removeSession(session.getAttribute(CIMConstant.SESSION_KEY));*/ public void remove(String account) {
}
public void removeSession(String account) {
//database.removeSession(account);*/ //database.removeSession(account);*/
} }
public boolean containsCIMSession(CIMSession ios)
{
//return database.containsCIMSession(session.getAccount());
return false;
}
public String getAccount(CIMSession ios)
{
return ios.getAccount();
}
@Override @Override
public boolean containsCIMSession(String account) { public void setState(String account, int state) {
// TODO Auto-generated method stub
return false;
}
@Override
public void setInvalid(String account) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
} }
@Override @Override
public void updateSession(CIMSession session) { public void update(CIMSession session) {
}
@Override
public void add(String account, CIMSession session) {
// TODO Auto-generated method stub
} }

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.util; package com.farsunset.cim.util;
public interface Constants { public interface Constants {

View File

@ -1,13 +1,14 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.util; package com.farsunset.cim.util;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
/**
* spring 动态获取bean 实现
* @author 3979434
*
*/
public class ContextHolder implements ApplicationContextAware{ public class ContextHolder implements ApplicationContextAware{
private static ApplicationContext context; private static ApplicationContext context;

View File

@ -1,4 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.util; package com.farsunset.cim.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -17,7 +22,8 @@ import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import com.farsunset.cim.server.model.Message; import com.farsunset.cim.sdk.server.model.Message;
public class MessageDispatcher { public class MessageDispatcher {

View File

@ -2,6 +2,7 @@ package com.farsunset.cim.util;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.UUID;
public class StringUtil { public class StringUtil {
@ -46,5 +47,10 @@ public class StringUtil {
return dateFormat.format(new Date()); return dateFormat.format(new Date());
} }
public static String getUUID() {
// TODO Auto-generated method stub
return UUID.randomUUID().toString().replaceAll("-", "");
}
} }

View File

@ -1,4 +1,4 @@
log4j.rootLogger=warn,console, file log4j.rootLogger=debug,console, file
#----------console---------------- #----------console----------------
log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console=org.apache.log4j.ConsoleAppender

View File

@ -13,20 +13,7 @@
" "
> >
<!-- =============================================================== --> <bean id="cimIoHandler" class="com.farsunset.cim.sdk.server.handler.CIMIoHandler" >
<!-- MINA -->
<!-- =============================================================== -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.net.SocketAddress">
<bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
</entry>
</map>
</property>
</bean>
<bean id="cimIoHandler" class="com.farsunset.cim.server.handler.CIMIoHandler" >
<property name="handlers"> <property name="handlers">
<map> <map>
@ -50,13 +37,13 @@
<bean id="CIMNioAcceptor" class="com.farsunset.cim.server.handler.CIMNioSocketAcceptor" <bean id="CIMNioAcceptor" class="com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor"
init-method="bind" destroy-method="unbind"> init-method="bind" destroy-method="unbind">
<property name="port" value="23456" /> <property name="port" value="23456" />
<property name="ioHandler" ref="cimIoHandler" /> <property name="ioHandler" ref="cimIoHandler" />
</bean> </bean>
<bean id="CIMSessionManager" class="com.farsunset.cim.server.session.DefaultSessionManager"/> <bean id="CIMSessionManager" class="com.farsunset.cim.sdk.server.session.DefaultSessionManager"/>
<!-- 集群服务器时 CIMSessionManager 配置 <!-- 集群服务器时 CIMSessionManager 配置
<bean id="CIMSessionManager" class="com.farsunset.lvxin.cim.session.ClusterSessionManager"> <bean id="CIMSessionManager" class="com.farsunset.lvxin.cim.session.ClusterSessionManager">

View File

@ -10,7 +10,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-sdk <uses-sdk
android:minSdkVersion="10" android:minSdkVersion="10"
android:targetSdkVersion="19" /> android:targetSdkVersion="19" />
@ -52,7 +52,7 @@
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<!--推送服务--> <!--推送服务-->
<service android:name="com.farsunset.cim.client.android.CIMPushService" android:process=":cimpush" /> <service android:name="com.farsunset.cim.sdk.android.CIMPushService" android:process=":cimpush" />
<!--消息接受广播注册--> <!--消息接受广播注册-->
<receiver android:name="com.farsunset.ichat.example.receiver.CustomCIMMessageReceiver" android:exported="false"> <receiver android:name="com.farsunset.ichat.example.receiver.CustomCIMMessageReceiver" android:exported="false">
@ -60,12 +60,12 @@
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <!-- 网络变化广播 --> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <!-- 网络变化广播 -->
<action android:name="com.farsunset.cim.MESSAGE_RECEIVED"/><!-- 消息广播action --> <action android:name="com.farsunset.cim.MESSAGE_RECEIVED"/><!-- 消息广播action -->
<action android:name="com.farsunset.cim.SENT_FAILED"/> <!-- 发送sendbody失败广播--> <action android:name="com.farsunset.cim.SENT_FAILED"/> <!-- 发送sendbody失败广播-->
<action android:name="com.farsunset.cim.SENT_SUCCESS"/> <!-- 发送sendbody成功广播 --> <action android:name="com.farsunset.cim.SENT_SUCCESSED"/> <!-- 发送sendbody成功广播 -->
<action android:name="com.farsunset.cim.CONNECTION_RECOVERY"/> <!--重新连接 -->
<action android:name="com.farsunset.cim.CONNECTION_CLOSED"/> <!-- 链接意外关闭广播 --> <action android:name="com.farsunset.cim.CONNECTION_CLOSED"/> <!-- 链接意外关闭广播 -->
<action android:name="com.farsunset.cim.CONNECTION_FAILED"/> <!-- 链接失败广播 --> <action android:name="com.farsunset.cim.CONNECTION_FAILED"/> <!-- 链接失败广播 -->
<action android:name="com.farsunset.cim.CONNECTION_SUCCESS"/> <!-- 链接成功广播--> <action android:name="com.farsunset.cim.CONNECTION_SUCCESSED"/> <!-- 链接成功广播-->
<action android:name="com.farsunset.cim.REPLY_RECEIVED"/> <!-- 发送sendbody成功后获得replaybody回应广播 --> <action android:name="com.farsunset.cim.REPLY_RECEIVED"/> <!-- 发送sendbody成功后获得replaybody回应广播 -->
<action android:name="com.farsunset.cim.CONNECTION_STATUS"/> <!-- 获取到与服务端连接状态广播 -->
<!-- 【可选】 一些常用的系统广播增强pushservice的复活机会--> <!-- 【可选】 一些常用的系统广播增强pushservice的复活机会-->
<action android:name="android.intent.action.USER_PRESENT" /> <action android:name="android.intent.action.USER_PRESENT" />

View File

@ -1,8 +1,14 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.adapter; package com.farsunset.ichat.example.adapter;
import java.util.Comparator; import java.util.Comparator;
import com.farsunset.cim.client.model.Message; import com.farsunset.cim.sdk.android.model.Message;
public class MessageTimeDescComparator implements Comparator<Message>{ public class MessageTimeDescComparator implements Comparator<Message>{

View File

@ -1,17 +1,22 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.adapter; package com.farsunset.ichat.example.adapter;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import android.annotation.SuppressLint;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.client.model.Message;
import com.farsunset.ichat.example.R; import com.farsunset.ichat.example.R;
import com.farsunset.ichat.example.ui.SystemMessageActivity; import com.farsunset.ichat.example.ui.SystemMessageActivity;
@ -48,12 +53,12 @@ public class SystemMsgListViewAdapter extends BaseAdapter {
{ {
//Collections.sort(list, new MessageTimeDescComparator()); //Collections.sort(list, new MessageTimeDescComparator());
} }
@SuppressLint("ViewHolder")
@Override @Override
public View getView(int position, View chatItemView, ViewGroup parent) { public View getView(int position, View chatItemView, ViewGroup parent) {
final Message msg = getItem(position); final Message msg = getItem(position);
chatItemView =LayoutInflater.from(scactivity).inflate(R.layout.item_chat_sysmsg, null); chatItemView =LayoutInflater.from(scactivity).inflate(R.layout.item_chat_sysmsg, null);

View File

@ -1,16 +1,21 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.app; package com.farsunset.ichat.example.app;
import com.farsunset.cim.sdk.android.CIMEventListener;
import com.farsunset.cim.sdk.android.CIMListenerManager;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import android.app.Activity; import android.app.Activity;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Bundle; import android.os.Bundle;
import com.farsunset.cim.client.android.CIMEventListener;
import com.farsunset.cim.client.android.CIMListenerManager;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
public abstract class CIMMonitorActivity extends Activity implements CIMEventListener{ public abstract class CIMMonitorActivity extends Activity implements CIMEventListener{
@ -56,28 +61,30 @@ public abstract class CIMMonitorActivity extends Activity implements CIMEventL
@Override
public void onMessageReceived(Message arg0){};
@Override
public void onNetworkChanged(NetworkInfo info){}
/** /**
* 与服务端断开连接时回调,不要在里面做连接服务端的操作 * 与服务端断开连接时回调,不要在里面做连接服务端的操作
*/ */
@Override @Override
public void onCIMConnectionSucceed() {} public void onConnectionClosed() {}
/** /**
* 连接服务端成功时回调 * 连接服务端成功时回调
*/ */
@Override @Override
public void onCIMConnectionClosed() {} public void onConnectionSuccessed(boolean arg0) {}
@Override
public void onConnectionStatus(boolean isConnected){}
@Override @Override
public void onReplyReceived(ReplyBody reply) {} public void onReplyReceived(ReplyBody arg0) {}
@Override @Override
public void onMessageReceived(Message arg0) {} public void onConnectionFailed(Exception e){};
@Override
public void onNetworkChanged(NetworkInfo info){};
} }

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.app; package com.farsunset.ichat.example.app;

View File

@ -1,18 +1,15 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.app; package com.farsunset.ichat.example.app;
/**
*
* @version 1.0
*/
public interface Constant { public interface Constant {
//服务端IP地址 //服务端IP地址
public static final String CIM_SERVER_HOST = "192.168.2.3"; public static final String CIM_SERVER_HOST = "192.168.2.2";
//服务端web地址 //服务端web地址
public static final String SERVER_URL = "http://"+CIM_SERVER_HOST+":8080/cim-server"; public static final String SERVER_URL = "http://"+CIM_SERVER_HOST+":8080/cim-server";

View File

@ -1,10 +1,13 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.network; package com.farsunset.ichat.example.network;
import java.io.File; import java.io.File;
import java.lang.reflect.Type;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -20,18 +23,13 @@ import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class HttpAPIRequester { public class HttpAPIRequester {
HttpAPIResponser responser; HttpAPIResponser responser;
Type dataType;
Type dataListType;
private static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); private static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 20, TimeUnit.SECONDS,queue);; private static ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 20, TimeUnit.SECONDS,queue);;
@ -72,41 +70,20 @@ public class HttpAPIRequester {
* @exception * @exception
* @since 1.0.0 * @since 1.0.0
*/ */
public void execute( Type dtype , Type dltype, final String url) public void execute( final String url)
{ {
this.dataType = dtype;
this.dataListType = dltype;
responser.onRequest(); responser.onRequest();
executor.execute(new Runnable() { executor.execute(new Runnable() {
@Override @Override
public void run() { public void run() {
Message message = handler.obtainMessage(); Message message = handler.obtainMessage();
HashMap<String,Object> data = new HashMap<String,Object>(); message.getData().putString("url", url);
try { try {
String dataString = httpPost(url,responser.getRequestParams()); String dataString = httpPost(url,responser.getRequestParams());
JSONObject json = JSON.parseObject(dataString);
data.put("code", json.getString("code"));
data.put("url", url);
if(json.containsKey("data") && dataType!=null)
{
dataString = json.getJSONObject("data").toJSONString();
data.put("data", JSON.parseObject(dataString, dataType));
}
if(json.containsKey("dataList") &&dataListType!=null )
{
dataString = json.getJSONArray("dataList").toJSONString();
data.put("list", JSON.parseObject(dataString, dataListType));
}
if(json.containsKey("page") &&json.getJSONObject("page")!=null) message.getData().putString("data", dataString);
{
dataString = json.getJSONObject("page").toJSONString();
data.put("page", JSON.parseObject(dataString, Page.class));
}
message.getData().putSerializable("data", data);
message.what = 0; message.what = 0;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -157,18 +134,16 @@ public class HttpAPIRequester {
Handler handler = new Handler(){ Handler handler = new Handler(){
public void handleMessage(Message message) public void handleMessage(Message message)
{ {
String url = message.getData().getString("url");
switch(message.what) switch(message.what)
{ {
case 0: case 0:
HashMap<String,Object> data =(HashMap<String, Object>) message.getData().getSerializable("data"); String data = message.getData().getString("data");
Page page = (Page) data.get("page"); responser.onSuccess(data,url);
List<Object> list = (List<Object>) data.get("list");
String code = String.valueOf(data.get("code"));
responser.onSuccess(data.get("data"),list,page,String.valueOf(data.get("code")),data.get("url").toString());
break; break;
case 1: case 1:
responser.onFailed((Exception) message.getData().get("exception")); responser.onFailed((Exception) message.getData().get("exception"),url);
break; break;
} }

View File

@ -1,13 +1,17 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.network; package com.farsunset.ichat.example.network;
import java.util.List;
import java.util.Map; import java.util.Map;
public interface HttpAPIResponser { public interface HttpAPIResponser {
public void onSuccess(Object data,List<?> list,Page page,String code,String url); public void onSuccess(String resulet,String url);
public void onFailed(Exception e); public void onFailed(Exception e,String url);
public Map<String,Object> getRequestParams(); public Map<String,Object> getRequestParams();
public void onRequest(); public void onRequest();
} }

View File

@ -1,18 +0,0 @@
package com.farsunset.ichat.example.network;
import java.io.Serializable;
public class Page implements Serializable
{
/**
* serialVersionUID:TODO(用一句话描述这个变量表示什么
*
* @since 1.0.0
*/
private static final long serialVersionUID = 1L;
public int count;
public int size;
public int currentPage;
public int countPage;
}

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.receiver; package com.farsunset.ichat.example.receiver;
@ -7,12 +13,11 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.util.Log;
import com.farsunset.cim.client.android.CIMEventBroadcastReceiver; import com.farsunset.cim.sdk.android.CIMEventBroadcastReceiver;
import com.farsunset.cim.client.android.CIMListenerManager; import com.farsunset.cim.sdk.android.CIMListenerManager;
import com.farsunset.cim.client.model.Message; import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.client.model.ReplyBody; import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.ichat.example.R; import com.farsunset.ichat.example.R;
import com.farsunset.ichat.example.ui.SystemMessageActivity; import com.farsunset.ichat.example.ui.SystemMessageActivity;
@ -29,44 +34,21 @@ public final class CustomCIMMessageReceiver extends CIMEventBroadcastReceiver {
//当收到消息时会执行onMessageReceived这里是消息第一入口 //当收到消息时会执行onMessageReceived这里是消息第一入口
@Override @Override
public void onMessageReceived(com.farsunset.cim.client.model.Message message) { public void onMessageReceived(Message message) {
//调用分发消息监听
for (int index = 0 ;index<CIMListenerManager.getCIMListeners().size();index++) { CIMListenerManager.notifyOnMessageReceived(message);
Log.i(this.getClass().getSimpleName(), "########################"+ (CIMListenerManager.getCIMListeners().get(index).getClass().getName() + ".onMessageReceived################"));
CIMListenerManager.getCIMListeners().get(index).onMessageReceived(message);
}
//以开头的为动作消息无须显示,如被强行下线消息Constant.TYPE_999 //以开头的为动作消息无须显示,如被强行下线消息Constant.TYPE_999
if(message.getType().startsWith("9")) if(message.getType().startsWith("9"))
{ {
return ; return ;
} }
if(isInBackground(context))
{
showNotify(context,message); showNotify(context,message);
} }
}
//当手机网络连接状态变化时会执行onNetworkChanged
@Override
public void onNetworkChanged(NetworkInfo info) {
for (int index = 0 ;index<CIMListenerManager.getCIMListeners().size();index++) {
CIMListenerManager.getCIMListeners().get(index).onNetworkChanged(info);
}
}
//当收到sendbody的响应时会执行onReplyReceived
@Override
public void onReplyReceived(ReplyBody body) {
for (int index = 0 ;index<CIMListenerManager.getCIMListeners().size();index++) {
CIMListenerManager.getCIMListeners().get(index).onReplyReceived(body);
}
}
private void showNotify(Context context , Message msg) private void showNotify(Context context , Message msg)
{ {
@ -87,29 +69,33 @@ public final class CustomCIMMessageReceiver extends CIMEventBroadcastReceiver {
} }
@Override @Override
public void onCIMConnectionSucceed() { public void onNetworkChanged(NetworkInfo info) {
for (int index = 0 ;index<CIMListenerManager.getCIMListeners().size();index++) { CIMListenerManager.notifyOnNetworkChanged(info);
CIMListenerManager.getCIMListeners().get(index).onCIMConnectionSucceed();
}
} }
@Override @Override
public void onConnectionStatus(boolean arg0) { public void onConnectionSuccessed(boolean hasAutoBind) {
for (int index = 0 ;index<CIMListenerManager.getCIMListeners().size();index++) { CIMListenerManager.notifyOnConnectionSuccessed(hasAutoBind);
CIMListenerManager.getCIMListeners().get(index).onConnectionStatus(arg0);
} }
@Override
public void onConnectionClosed() {
CIMListenerManager.notifyOnConnectionClosed();
} }
@Override @Override
public void onCIMConnectionClosed() { public void onReplyReceived(ReplyBody body) {
CIMListenerManager.notifyOnReplyReceived(body);
}
@Override
public void onConnectionFailed(Exception arg0) {
// TODO Auto-generated method stub // TODO Auto-generated method stub
for (int index = 0 ;index<CIMListenerManager.getCIMListeners().size();index++) { CIMListenerManager.notifyOnConnectionFailed(arg0);
CIMListenerManager.getCIMListeners().get(index).onCIMConnectionSucceed();
} }
}
} }

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.ui; package com.farsunset.ichat.example.ui;
import android.content.Intent; import android.content.Intent;
@ -7,12 +13,12 @@ import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import com.farsunset.cim.client.android.CIMPushManager;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.model.ReplyBody;
import com.farsunset.ichat.example.R; import com.farsunset.ichat.example.R;
import com.farsunset.ichat.example.app.CIMMonitorActivity; import com.farsunset.ichat.example.app.CIMMonitorActivity;
import com.farsunset.ichat.example.app.Constant;
import com.farsunset.cim.sdk.android.CIMPushManager;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.ReplyBody;
public class LoginActivity extends CIMMonitorActivity implements public class LoginActivity extends CIMMonitorActivity implements
OnClickListener { OnClickListener {
@ -38,12 +44,26 @@ public class LoginActivity extends CIMMonitorActivity implements
if (!"".equals(accountEdit.getText().toString().trim())) { if (!"".equals(accountEdit.getText().toString().trim())) {
showProgressDialog("提示", "正在登陆,请稍后......"); showProgressDialog("提示", "正在登陆,请稍后......");
if(CIMPushManager.getState(this) == CIMPushManager.STATE_NORMAL )
{
CIMPushManager.bindAccount(this, accountEdit.getText().toString().trim());
return;
}
if(CIMPushManager.getState(this) == CIMPushManager.STATE_STOPED )
{
CIMPushManager.connect(this,Constant.CIM_SERVER_HOST, Constant.CIM_SERVER_PORT);
}
}
}
@Override
public void onConnectionSuccessed(boolean autoBind) {
if(!autoBind)
CIMPushManager.bindAccount(this, accountEdit.getText().toString().trim()); CIMPushManager.bindAccount(this, accountEdit.getText().toString().trim());
} }
}
@Override @Override
public void onReplyReceived(final ReplyBody reply) { public void onReplyReceived(final ReplyBody reply) {
@ -80,7 +100,7 @@ public class LoginActivity extends CIMMonitorActivity implements
@Override @Override
public void onBackPressed() { public void onBackPressed() {
CIMPushManager.destory(this); CIMPushManager.destroy(this);
this.finish(); this.finish();
} }

View File

@ -1,3 +1,9 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.ui; package com.farsunset.ichat.example.ui;
@ -7,7 +13,7 @@ import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.animation.AlphaAnimation; import android.view.animation.AlphaAnimation;
import com.farsunset.cim.client.android.CIMPushManager; import com.farsunset.cim.sdk.android.CIMPushManager;
import com.farsunset.ichat.example.R; import com.farsunset.ichat.example.R;
import com.farsunset.ichat.example.app.CIMMonitorActivity; import com.farsunset.ichat.example.app.CIMMonitorActivity;
import com.farsunset.ichat.example.app.Constant; import com.farsunset.ichat.example.app.Constant;
@ -23,7 +29,7 @@ public class SplanshActivity extends CIMMonitorActivity{
//连接服务端 //连接服务端
CIMPushManager.init(SplanshActivity.this,Constant.CIM_SERVER_HOST, Constant.CIM_SERVER_PORT); CIMPushManager.connect(SplanshActivity.this,Constant.CIM_SERVER_HOST, Constant.CIM_SERVER_PORT);
final View view = View.inflate(this, R.layout.activity_splansh, null); final View view = View.inflate(this, R.layout.activity_splansh, null);
@ -35,7 +41,7 @@ public class SplanshActivity extends CIMMonitorActivity{
} }
@Override @Override
public void onCIMConnectionSucceed() { public void onConnectionSuccessed(boolean autoBind) {
Intent intent = new Intent(SplanshActivity.this,LoginActivity.class); Intent intent = new Intent(SplanshActivity.this,LoginActivity.class);
startActivity(intent); startActivity(intent);
@ -46,6 +52,10 @@ public class SplanshActivity extends CIMMonitorActivity{
@Override @Override
public void onBackPressed() { public void onBackPressed() {
finish(); finish();
CIMPushManager.destory(this); CIMPushManager.destroy(this);
}
public void onConnectionFailed(Exception e){
showToask("连接服务器失败请检查当前设备是否能连接上服务器IP和端口");
} }
} }

View File

@ -1,10 +1,14 @@
/**
* probject:cim
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.ichat.example.ui; package com.farsunset.ichat.example.ui;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import android.content.Intent; import android.content.Intent;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.net.NetworkInfo; import android.net.NetworkInfo;
@ -13,20 +17,16 @@ import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import com.farsunset.cim.sdk.android.CIMPushManager;
import com.alibaba.fastjson.JSONObject; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.alibaba.fastjson.TypeReference; import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.client.android.CIMPushManager; import com.farsunset.cim.sdk.android.model.SentBody;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.SentBody;
import com.farsunset.ichat.example.R; import com.farsunset.ichat.example.R;
import com.farsunset.ichat.example.adapter.SystemMsgListViewAdapter; import com.farsunset.ichat.example.adapter.SystemMsgListViewAdapter;
import com.farsunset.ichat.example.app.CIMMonitorActivity; import com.farsunset.ichat.example.app.CIMMonitorActivity;
import com.farsunset.ichat.example.app.Constant; import com.farsunset.ichat.example.app.Constant;
import com.farsunset.ichat.example.network.HttpAPIRequester; import com.farsunset.ichat.example.network.HttpAPIRequester;
import com.farsunset.ichat.example.network.HttpAPIResponser; import com.farsunset.ichat.example.network.HttpAPIResponser;
import com.farsunset.ichat.example.network.Page;
public class SystemMessageActivity extends CIMMonitorActivity implements OnClickListener, HttpAPIResponser{ public class SystemMessageActivity extends CIMMonitorActivity implements OnClickListener, HttpAPIResponser{
@ -71,7 +71,7 @@ public class SystemMessageActivity extends CIMMonitorActivity implements OnClick
//收到消息 //收到消息
@Override @Override
public void onMessageReceived(com.farsunset.cim.client.model.Message message) { public void onMessageReceived(Message message) {
if(message.getType().equals(Constant.MessageType.TYPE_999)) if(message.getType().equals(Constant.MessageType.TYPE_999))
{ {
@ -121,20 +121,16 @@ public class SystemMessageActivity extends CIMMonitorActivity implements OnClick
private void sendMessage() throws Exception private void sendMessage() throws Exception
{ {
requester.execute(new TypeReference<JSONObject>(){}.getType(), null, SEND_MESSAGE_API_URL); requester.execute(SEND_MESSAGE_API_URL);
} }
@Override @Override
public void onSuccess(Object data, List<?> list, Page page, String code,String url) { public void onSuccess(String data,String url) {
hideProgressDialog(); hideProgressDialog();
if(CIMConstant.ReturnCode.CODE_200.equals(code))
{
showToask("发送成功"); showToask("发送成功");
} }
}
@Override @Override
public Map<String, Object> getRequestParams() { public Map<String, Object> getRequestParams() {
@ -163,7 +159,7 @@ public class SystemMessageActivity extends CIMMonitorActivity implements OnClick
} }
@Override @Override
public void onFailed(Exception e) {} public void onFailed(Exception e,String url) {}
@Override @Override
public void onBackPressed() { public void onBackPressed() {

View File

@ -1,231 +0,0 @@
package com.farsunset.ichat.example.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
/**
* 文件下载器 每秒2次跟新进度
*
* @author Administrator
*
*/
public class FileDownloader {
private DownloadHandler handler;
private static FileDownloader fileDownloader;
private static FileDownloadCallBack downloadCallBack;
private ThreadPoolExecutor downloadExecutor;// 下载线程执行器
public static final int STATUS_STOP = 1;
public static final int STATUS_AWAIT = 3;
public static final int STATUS_FAILED = 4;
public static final int STATUS_DONE = 200;
public static final int STATUS_RUNING = 0;
// 每个下载线程的状态记录
private static HashMap<String, Integer> STATUS_MAP = new HashMap<String, Integer>();
// 每个文件的大小 byte
private static HashMap<String, Long> FILE_SIZE_MAP = new HashMap<String, Long>();
// 每个下载线程的进度大小(byte)
private static HashMap<String,Long> PROGRESS_MAP = new HashMap<String,Long>();
private FileDownloader() {
handler = new DownloadHandler();
//支持3个线程同时下载
downloadExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
}
public synchronized static FileDownloader getInstance() {
if (fileDownloader == null) {
fileDownloader = new FileDownloader();
}
return fileDownloader;
}
public String download(final String fileUrl, final File file) {
// 创建线程key
final String threadKey = fileUrl;
// 创建下载任务当运行的任务线程已经满了则会等待直到有下载线程完成
downloadExecutor.execute(new Runnable() {
@Override
public void run() {
STATUS_MAP.put(threadKey, STATUS_RUNING);
HttpURLConnection conn = null;
InputStream is = null;
FileOutputStream fos = null;
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("threadKey", threadKey);
msg.setData(bundle);
try {
URL fielURL = new URL(fileUrl);
conn = (HttpURLConnection) fielURL.openConnection();
FILE_SIZE_MAP.put(threadKey, (long)conn.getContentLength());
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
msg.what = STATUS_FAILED;
handler.sendMessage(msg);
return;
}
is = conn.getInputStream();
fos = new FileOutputStream(file);
PROGRESS_MAP.put(threadKey, 0l);
handler.sendMessageDelayed(msg, 200);
byte buf[] = new byte[1024];
int numread;
long downloadSize = 0;
while ((numread = is.read(buf)) != -1) {
if (STATUS_MAP.get(threadKey) == STATUS_STOP) {
msg = new Message();
msg.what = STATUS_STOP;
handler.sendMessage(msg);
break;
}
fos.write(buf, 0, numread);
downloadSize += numread;
PROGRESS_MAP.put(threadKey, downloadSize);
}
} catch (Exception e) {
msg = new Message();
msg.what = STATUS_FAILED;
handler.sendMessage(msg);
e.printStackTrace();
} finally {
try {
is.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
conn.disconnect();
}
STATUS_MAP.put(threadKey, STATUS_DONE);
}
});
return threadKey;
}
/**
* 通过任务名称停止下载 threadKey download()返回的任务名
*/
public void setOnDownloadCallBack(FileDownloadCallBack callBack) {
downloadCallBack = callBack;
}
/**
* 通过任务名称停止下载 threadKey download()返回的任务名
*/
public void stop(String threadKey) {
STATUS_MAP.put(threadKey, STATUS_STOP);
}
/**
* 停止所有下载任务
*/
public void stopAll() {
for (String threadKey : STATUS_MAP.keySet()) {
stop(threadKey);
}
}
/**
* 停止所有下载任务
*/
public void shutdown() {
downloadExecutor.shutdown();
}
/**
* 销毁下载器
*/
public void destroy() {
stopAll();
downloadExecutor.shutdown();
downloadExecutor = null;
fileDownloader = null;
}
static class DownloadHandler extends Handler {
private DownloadHandler() {
super(Looper.getMainLooper());
}
@Override
public void dispatchMessage(Message message) {
String threadKey = message.getData().getString("threadKey");
switch (message.what) {
case STATUS_RUNING:
downloadCallBack.progress(threadKey, FILE_SIZE_MAP.get(threadKey), PROGRESS_MAP.get(threadKey));
message = this.obtainMessage();
message.getData().putString("threadKey", threadKey);
if(FILE_SIZE_MAP.get(threadKey).equals(PROGRESS_MAP.get(threadKey)) || STATUS_MAP.get(threadKey).equals(STATUS_DONE))
{
message.what = STATUS_DONE;
}
this.sendMessageDelayed(message, 200);
break;
case STATUS_STOP:
downloadCallBack.statusChange(threadKey, STATUS_STOP);
break;
case STATUS_FAILED:
downloadCallBack.statusChange(threadKey, STATUS_FAILED);
break;
case STATUS_DONE:
downloadCallBack.progress(threadKey, FILE_SIZE_MAP.get(threadKey), FILE_SIZE_MAP.get(threadKey));
PROGRESS_MAP.remove(threadKey);
STATUS_MAP.remove(threadKey);
FILE_SIZE_MAP.remove(threadKey);
break;
}
}
}
public static interface FileDownloadCallBack {
public abstract void progress(String threadKey, long fileSize,long downloadSize);
public abstract void statusChange(String threadKey, int status);
}
}

View File

@ -1,52 +0,0 @@
package com.farsunset.ichat.example.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.Context;
import android.telephony.TelephonyManager;
public class StringUtil {
public static boolean isEmpty(Object obj)
{
return null == obj || "".equals(obj.toString().trim());
}
public static boolean isNotEmpty(Object obj)
{
return !isEmpty(obj);
}
public static String getSequenceId()
{
String mark = String.valueOf(System.currentTimeMillis());
return mark;
}
public static String getCurrentlyDateTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyyMMddHHmmss");
return dateFormat.format(new Date());
}
public static String transformDateTime(long t) {
Date date = new Date(t);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(date);
}
public static String getCurrentlyDate() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
return dateFormat.format(new Date());
}
public static String getIMEI(Context context)
{
return ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
}
}

View File

@ -3,6 +3,10 @@
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="C:/dev/Android-SDK-Windows/platforms/android-19/android.jar"/> <classpathentry kind="lib" path="C:/dev/Android-SDK-Windows/platforms/android-19/android.jar"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-all-5.0.0.Alpha2.jar" sourcepath="C:/Users/Administrator/Desktop/netty-all-5.0.0.Alpha2-sources.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-handler-4.1.0.CR7.jar"/>
<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-transport-4.1.0.CR7.jar"/>
<classpathentry kind="lib" path="/cim-server/WebRoot/WEB-INF/lib/netty-common-4.1.0.CR7.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -1,57 +0,0 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import android.content.Context;
class CIMCacheTools {
public static String CIM_CONFIG_INFO = "CIM_CONFIG_INFO";
public static String KEY_ACCOUNT = "KEY_ACCOUNT";
public static String KEY_MANUAL_STOP = "KEY_MANUAL_STOP";
public static String KEY_CIM_DESTORYED = "KEY_CIM_DESTORYED";
public static String KEY_CIM_SERVIER_HOST = "KEY_CIM_SERVIER_HOST";
public static String KEY_CIM_SERVIER_PORT = "KEY_CIM_SERVIER_PORT";
public static void putString(Context context,String key,String value)
{
context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).edit().putString(key, value).commit();
}
public static String getString(Context context,String key)
{
return context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).getString(key,null);
}
public static void putBoolean(Context context,String key,boolean value)
{
context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).edit().putBoolean(key, value).commit();
}
public static boolean getBoolean(Context context,String key)
{
return context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).getBoolean(key,false);
}
public static void putInt(Context context,String key,int value)
{
context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).edit().putInt(key, value).commit();
}
public static int getInt(Context context,String key)
{
return context.getSharedPreferences(CIM_CONFIG_INFO, Context.MODE_PRIVATE).getInt(key,0);
}
}

View File

@ -1,57 +0,0 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import android.net.NetworkInfo;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
/**
*CIM 主要事件接口
*/
public interface CIMEventListener
{
/**
* 当收到服务端推送过来的消息时调用
* @param message
*/
public void onMessageReceived(Message message);
/**
* 当调用CIMPushManager.sendRequest()向服务端发送请求获得相应时调用
* @param replybody
*/
public void onReplyReceived(ReplyBody replybody);
/**
* 当手机网络发生变化时调用
* @param networkinfo
*/
public void onNetworkChanged(NetworkInfo networkinfo);
/**
* 获取到是否连接到服务端
* 通过调用CIMPushManager.detectIsConnected()来异步获取
*
*/
public void onConnectionStatus(boolean isConnected);
/**
* 连接服务端成功
*/
public void onCIMConnectionSucceed();
/**
* 连接断开
*/
public void onCIMConnectionClosed();
}

View File

@ -1,215 +0,0 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.client.android;
import java.util.UUID;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.model.SentBody;
/**
* CIM 功能接口
*/
public class CIMPushManager {
static String ACTION_ACTIVATE_PUSH_SERVICE ="ACTION_ACTIVATE_PUSH_SERVICE";
static String ACTION_CONNECTION ="ACTION_CONNECTION";
static String ACTION_CONNECTION_STATUS ="ACTION_CONNECTION_STATUS";
static String ACTION_SENDREQUEST ="ACTION_SENDREQUEST";
static String ACTION_DISCONNECTION ="ACTION_DISSENDREQUEST";
static String ACTION_DESTORY ="ACTION_DESTORY";
static String SERVICE_ACTION ="SERVICE_ACTION";
static String KEY_SEND_BODY ="KEY_SEND_BODY";
static String KEY_CIM_CONNECTION_STATUS ="KEY_CIM_CONNECTION_STATUS";
/**
* 初始化,连接服务端在程序启动页或者 在Application里调用
* @param context
* @param ip
* @param port
*/
public static void init(Context context,String ip,int port){
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED, false);
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, false);
CIMCacheTools.putString(context, CIMCacheTools.KEY_CIM_SERVIER_HOST, ip);
CIMCacheTools.putInt(context, CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST, ip);
serviceIntent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION);
context.startService(serviceIntent);
}
protected static void init(Context context){
boolean isManualStop = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualStop || isManualDestory)
{
return ;
}
String host = CIMCacheTools.getString(context, CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port =CIMCacheTools.getInt(context, CIMCacheTools.KEY_CIM_SERVIER_PORT);
init(context,host,port);
}
/**
* 设置一个账号登录到服务端
* @param account 用户唯一ID
*/
public static void bindAccount(Context context,String account){
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory || account==null || account.trim().length()==0)
{
return ;
}
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, false);
CIMCacheTools.putString(context,CIMCacheTools.KEY_ACCOUNT, account);
String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
imei += context.getPackageName();
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
sent.put("account", account);
sent.put("deviceId",UUID.nameUUIDFromBytes(imei.getBytes()).toString().replaceAll("-", ""));
sent.put("channel", "android");
sent.put("device",android.os.Build.MODEL);
sent.put("appVersion",getVersionName(context));
sent.put("osVersion",android.os.Build.VERSION.RELEASE);
sendRequest(context,sent);
}
protected static void bindAccount(Context context){
String account = CIMCacheTools.getString(context,CIMCacheTools.KEY_ACCOUNT);
bindAccount(context,account);
}
/**
* 发送一个CIM请求
* @param context
* @body
*/
public static void sendRequest(Context context,SentBody body){
boolean isManualStop = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualStop || isManualDestory)
{
return ;
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(KEY_SEND_BODY, body);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_SENDREQUEST);
context.startService(serviceIntent);
}
/**
* 停止接受推送将会退出当前账号登录端口与服务端的连接
* @param context
*/
public static void stop(Context context){
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory){
return ;
}
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP, true);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_DISCONNECTION);
context.startService(serviceIntent);
}
/**
* 完全销毁CIM一般用于完全退出程序调用resume将不能恢复
* @param context
*/
public static void destory(Context context){
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED, true);
CIMCacheTools.putString(context,CIMCacheTools.KEY_ACCOUNT, null);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_DESTORY);
context.startService(serviceIntent);
}
/**
* 重新恢复接收推送重新连接服务端并登录当前账号
* @param context
*/
public static void resume(Context context){
boolean isManualDestory = CIMCacheTools.getBoolean(context,CIMCacheTools.KEY_CIM_DESTORYED);
if(isManualDestory){
return ;
}
bindAccount(context);
}
public static void detectIsConnected(Context context){
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(SERVICE_ACTION, ACTION_CONNECTION_STATUS);
context.startService(serviceIntent);
}
private static String getVersionName(Context context) {
String versionName = null;
try {
PackageInfo mPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
versionName = mPackageInfo.versionName;
} catch (NameNotFoundException e) {
}
return versionName;
}
}

View File

@ -1,97 +0,0 @@
package com.farsunset.cim.client.android;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import com.farsunset.cim.client.model.SentBody;
/**
* 与服务端连接服务
* @author 3979434
*
*/
public class CIMPushService extends Service {
protected final static int DEF_CIM_PORT = 28888;
CIMConnectorManager manager;
@Override
public void onCreate()
{
manager = CIMConnectorManager.getManager(this.getApplicationContext());
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) {
String action;
if(intent==null)
{
intent = new Intent(CIMPushManager.ACTION_CONNECTION);
String host = CIMCacheTools.getString(this, CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port =CIMCacheTools.getInt(this, CIMCacheTools.KEY_CIM_SERVIER_PORT);
intent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST, host);
intent.putExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, port);
}
action = intent.getStringExtra(CIMPushManager.SERVICE_ACTION);
if(CIMPushManager.ACTION_CONNECTION.equals(action))
{
String host = intent.getStringExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port = intent.getIntExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, DEF_CIM_PORT);
manager.connect(host,port);
}
if(CIMPushManager.ACTION_SENDREQUEST.equals(action))
{
manager.send((SentBody) intent.getSerializableExtra(CIMPushManager.KEY_SEND_BODY));
}
if(CIMPushManager.ACTION_DISCONNECTION.equals(action))
{
manager.closeSession();
}
if(CIMPushManager.ACTION_DESTORY.equals(action))
{
manager.destroy();
this.stopSelf();
android.os.Process.killProcess(android.os.Process.myPid());
}
if(CIMPushManager.ACTION_CONNECTION_STATUS.equals(action))
{
manager.deliverIsConnected();
}
if(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE.equals(action))
{
if(!manager.isConnected())
{
Log.d(CIMPushService.class.getSimpleName(), "cimpush isConnected() = false ");
String host = intent.getStringExtra(CIMCacheTools.KEY_CIM_SERVIER_HOST);
int port = intent.getIntExtra(CIMCacheTools.KEY_CIM_SERVIER_PORT, DEF_CIM_PORT);
manager.connect(host,port);
}else
{
Log.d(CIMPushService.class.getSimpleName(), "isConnected() = true ");
}
}
return Service.START_REDELIVER_INTENT;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}

View File

@ -0,0 +1,130 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
class CIMCacheToolkit extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "CIM_CONFIG_INFO.db";
private static final int DATABASE_VERSION = 20160406;
private static final String TABLE_SQL = "CREATE TABLE IF NOT EXISTS T_CIM_CONFIG (KEY VARCHAR(64) PRIMARY KEY,VALUE TEXT)";
private static final String DELETE_SQL = "DELETE FROM T_CIM_CONFIG WHERE KEY = ?";
private static final String SAVE_SQL = "INSERT INTO T_CIM_CONFIG (KEY,VALUE) VALUES(?,?)";
private static final String QUERY_SQL = "SELECT VALUE FROM T_CIM_CONFIG WHERE KEY = ?";
public static final String CIM_CONFIG_INFO = "CIM_CONFIG_INFO";
public static final String KEY_ACCOUNT = "KEY_ACCOUNT";
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(Context context){
if (toolkit==null){
toolkit = new CIMCacheToolkit(context);
}
return toolkit;
}
public CIMCacheToolkit(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
public CIMCacheToolkit(Context context){
this(context, DATABASE_NAME,null, DATABASE_VERSION);
}
public void remove(String key)
{
SQLiteDatabase database = toolkit.getWritableDatabase();
database.execSQL(DELETE_SQL,new String[]{key});
database.close();
toolkit.close();
toolkit = null;
}
public void putString(String key,String value)
{
SQLiteDatabase database = toolkit.getWritableDatabase();
database.execSQL(DELETE_SQL,new String[]{key});
database.execSQL(SAVE_SQL, new String[]{key, value});
database.close();
toolkit.close();
toolkit = null;
}
public String getString(String key)
{
String value = null;
SQLiteDatabase database = toolkit.getWritableDatabase();
Cursor cursor = database.rawQuery(QUERY_SQL, new String[]{key});
if (cursor!=null&&cursor.moveToFirst())
{
value = cursor.getString(0);
}
cursor.close();
database.close();
toolkit.close();
toolkit = null;
return value;
}
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);
}
@Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(TABLE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
}
}

View File

@ -1,4 +1,10 @@
package com.farsunset.cim.client.android; /**
* probject:cim-server-sdk
* @version 2.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
@ -12,6 +18,10 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers; 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.net.InetSocketAddress;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -22,25 +32,25 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.util.Log;
import com.farsunset.cim.client.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.client.exception.CIMSessionDisableException; import com.farsunset.cim.sdk.android.exception.CIMSessionDisableException;
import com.farsunset.cim.client.exception.NetWorkDisableException; import com.farsunset.cim.sdk.android.exception.NetWorkDisableException;
import com.farsunset.cim.client.exception.WriteToClosedSessionException; import com.farsunset.cim.sdk.android.exception.WriteToClosedSessionException;
import com.farsunset.cim.client.filter.ClientMessageDecoder; import com.farsunset.cim.sdk.android.filter.ClientMessageDecoder;
import com.farsunset.cim.client.filter.ClientMessageEncoder; import com.farsunset.cim.sdk.android.filter.ClientMessageEncoder;
import com.farsunset.cim.client.model.Message; import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.client.model.ReplyBody; import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.client.model.SentBody; import com.farsunset.cim.sdk.android.model.SentBody;
/** /**
* 连接服务端管理cim核心处理类管理连接以及消息处理 * 连接服务端管理cim核心处理类管理连接以及消息处理
*
* @author 3979434@qq.com
*/ */
@io.netty.channel.ChannelHandler.Sharable @io.netty.channel.ChannelHandler.Sharable
class CIMConnectorManager extends SimpleChannelInboundHandler<Object> { class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
private final static String TAG = CIMConnectorManager.class.getSimpleName();
private Channel channel;; private Channel channel;;
Context context; Context context;
@ -56,13 +66,13 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
public static final String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED"; public static final String ACTION_SENT_FAILED = "com.farsunset.cim.SENT_FAILED";
// 发送sendbody成功广播 // 发送sendbody成功广播
public static final String ACTION_SENT_SUCCESS = "com.farsunset.cim.SENT_SUCCESS"; 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_CLOSED = "com.farsunset.cim.CONNECTION_CLOSED";
// 链接失败广播 // 链接失败广播
public static final String ACTION_CONNECTION_FAILED = "com.farsunset.cim.CONNECTION_FAILED"; public static final String ACTION_CONNECTION_FAILED = "com.farsunset.cim.CONNECTION_FAILED";
// 链接成功广播 // 链接成功广播
public static final String ACTION_CONNECTION_SUCCESS = "com.farsunset.cim.CONNECTION_SUCCESS"; public static final String ACTION_CONNECTION_SUCCESSED = "com.farsunset.cim.CONNECTION_SUCCESSED";
// 发送sendbody成功后获得replaybody回应广播 // 发送sendbody成功后获得replaybody回应广播
public static final String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED"; public static final String ACTION_REPLY_RECEIVED = "com.farsunset.cim.REPLY_RECEIVED";
// 网络变化广播 // 网络变化广播
@ -71,12 +81,16 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
// 未知异常 // 未知异常
public static final String ACTION_UNCAUGHT_EXCEPTION = "com.farsunset.cim.UNCAUGHT_EXCEPTION"; public static final String ACTION_UNCAUGHT_EXCEPTION = "com.farsunset.cim.UNCAUGHT_EXCEPTION";
// CIM连接状态 //重试连接
public static final String ACTION_CONNECTION_STATUS = "com.farsunset.cim.CONNECTION_STATUS"; public final static String ACTION_CONNECTION_RECOVERY = "com.farsunset.cim.CONNECTION_RECOVERY";
private ExecutorService executor; 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(Context ctx) { private CIMConnectorManager(Context ctx) {
context = ctx; context = ctx;
@ -85,17 +99,18 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
loopGroup = new NioEventLoopGroup(); loopGroup = new NioEventLoopGroup();
bootstrap.group(loopGroup); bootstrap.group(loopGroup);
bootstrap.channel(NioSocketChannel.class); bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.handler(new ChannelInitializer<SocketChannel>() { bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline(); ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ClientMessageDecoder(ClassResolvers.cacheDisabled(null))); pipeline.addLast(new ClientMessageDecoder(ClassResolvers.cacheDisabled(null)));
pipeline.addLast(new ClientMessageEncoder()); pipeline.addLast(new ClientMessageEncoder());
pipeline.addLast(new IdleStateHandler(READ_IDLE_TIME,0,0));
pipeline.addLast(CIMConnectorManager.this); pipeline.addLast(CIMConnectorManager.this);
} }
}); });
bootstrap.option(ChannelOption.TCP_NODELAY, true);
} }
@ -122,7 +137,7 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
intent.putExtra("exception", e); intent.putExtra("exception", e);
context.sendBroadcast(intent); context.sendBroadcast(intent);
System.out.println("******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort); Log.e(TAG,"******************CIM连接服务器失败 "+cimServerHost+":"+cimServerPort);
} }
@ -182,7 +197,7 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
}else }else
{ {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_SENT_SUCCESS); intent.setAction(ACTION_SENT_SUCCESSED);
intent.putExtra("sentBody", body); intent.putExtra("sentBody", body);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
@ -214,14 +229,6 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
return channel.isActive() ; return channel.isActive() ;
} }
public void deliverIsConnected() {
Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_STATUS);
intent.putExtra(CIMPushManager.KEY_CIM_CONNECTION_STATUS, isConnected());
context.sendBroadcast(intent);
}
public void closeSession() public void closeSession()
{ {
@ -232,15 +239,40 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
} }
/**
* 检测到连接空闲事件发送心跳请求命令
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
Log.e(TAG,"userEventTriggered:"+evt.toString());
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 @Override
public void channelActive( ChannelHandlerContext ctx) throws Exception { public void channelActive( ChannelHandlerContext ctx) throws Exception {
System.out.println("******************CIM连接服务器成功:"+ctx.channel().localAddress()); Log.i(TAG,"******************CIM连接服务器成功:"+ctx.channel().localAddress());
ctx.channel().attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).set(System.currentTimeMillis());
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_CONNECTION_SUCCESS); intent.setAction(ACTION_CONNECTION_SUCCESSED);
context.sendBroadcast(intent); context.sendBroadcast(intent);
} }
@ -248,7 +280,7 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("******************closeCIM与服务器断开连接:"+ctx.channel().localAddress()); Log.e(TAG,"******************closeCIM与服务器断开连接:"+ctx.channel().localAddress());
if(channel.id().asLongText().equals(ctx.channel().id().asLongText())) if(channel.id().asLongText().equals(ctx.channel().id().asLongText()))
{ {
Intent intent = new Intent(); Intent intent = new Intent();
@ -269,8 +301,7 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
} }
@Override @Override
protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Message) { if (msg instanceof Message) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_MESSAGE_RECEIVED); intent.setAction(ACTION_MESSAGE_RECEIVED);
@ -288,6 +319,7 @@ class CIMConnectorManager extends SimpleChannelInboundHandler<Object> {
//收到服务端发来的心跳请求命令则马上回应服务器 //收到服务端发来的心跳请求命令则马上回应服务器
if (msg.equals(CIMConstant.CMD_HEARTBEAT_REQUEST)) { if (msg.equals(CIMConstant.CMD_HEARTBEAT_REQUEST)) {
ctx.writeAndFlush(CIMConstant.CMD_HEARTBEAT_RESPONSE); ctx.writeAndFlush(CIMConstant.CMD_HEARTBEAT_RESPONSE);
ctx.channel().attr(AttributeKey.valueOf(HEARTBEAT_PINGED)).set(System.currentTimeMillis());
} }
} }

View File

@ -4,36 +4,35 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.android; package com.farsunset.cim.sdk.android;
import java.util.List;
import android.app.ActivityManager; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import android.app.ActivityManager.RunningTaskInfo; import com.farsunset.cim.sdk.android.exception.CIMSessionDisableException;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Handler; import android.os.Handler;
import com.farsunset.cim.client.constant.CIMConstant;
import com.farsunset.cim.client.exception.CIMSessionDisableException;
import com.farsunset.cim.client.model.Message;
import com.farsunset.cim.client.model.ReplyBody;
import com.farsunset.cim.client.model.SentBody;
/** /**
* 消息入口所有消息都会经过这里 * 消息入口所有消息都会经过这里
*/ */
public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver implements CIMEventListener { public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver implements CIMEventListener {
public Context context; public Context context;
@Override @Override
public void onReceive(Context ctx, Intent it) { public void onReceive(Context ctx, Intent it) {
context = ctx; context = ctx;
/* /*
* 操作事件广播用于提高service存活率 * 操作事件广播用于提高service存活率
*/ */
@ -61,11 +60,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_CLOSED))
{ {
if(CIMConnectorManager.netWorkAvailable(context)) onInnerConnectionClosed();
{
CIMPushManager.init(context);
}
onCIMConnectionClosed();
} }
/* /*
@ -73,19 +68,15 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_FAILED))
{ {
onConnectionFailed((Exception) it.getSerializableExtra("exception")); onInnerConnectionFailed((Exception) it.getSerializableExtra("exception"));
} }
/* /*
* cim连接服务器成功事件 * cim连接服务器成功事件
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESS)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_SUCCESSED))
{ {
onInnerConnectionSuccessed();
CIMPushManager.bindAccount(context);
onCIMConnectionSucceed();
} }
/* /*
@ -93,7 +84,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED)) if(it.getAction().equals(CIMConnectorManager.ACTION_MESSAGE_RECEIVED))
{ {
filterType999Message((Message)it.getSerializableExtra("message")); onInnerMessageReceived((Message)it.getSerializableExtra("message"));
} }
@ -117,7 +108,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
/* /*
* 获取sendbody发送成功事件 * 获取sendbody发送成功事件
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESS)) if(it.getAction().equals(CIMConnectorManager.ACTION_SENT_SUCCESSED))
{ {
onSentSucceed((SentBody)it.getSerializableExtra("sentBody")); onSentSucceed((SentBody)it.getSerializableExtra("sentBody"));
} }
@ -131,61 +122,61 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
onUncaughtException((Exception)it.getSerializableExtra("exception")); onUncaughtException((Exception)it.getSerializableExtra("exception"));
} }
/* /*
* 获取cim连接状态事件 * 重新连接如果断开的话
*/ */
if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_STATUS)) if(it.getAction().equals(CIMConnectorManager.ACTION_CONNECTION_RECOVERY))
{ {
onConnectionStatus(it.getBooleanExtra(CIMPushManager.KEY_CIM_CONNECTION_STATUS, false)); CIMPushManager.connect(context);
} }
} }
protected boolean isInBackground(Context context) {
List<RunningTaskInfo> tasksInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(1);
if (tasksInfo.size() > 0) {
if (context.getPackageName().equals(
tasksInfo.get(0).topActivity.getPackageName())) {
return false;
}
}
return true;
}
private void startPushService() private void startPushService()
{ {
Intent intent = new Intent(context, CIMPushService.class); Intent intent = new Intent(context, CIMPushService.class);
intent.putExtra(CIMPushManager.SERVICE_ACTION, CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE); intent.setAction(CIMPushManager.ACTION_ACTIVATE_PUSH_SERVICE);
context.startService(intent); context.startService(intent);
} }
private void onInnerConnectionClosed(){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, false);
if(CIMConnectorManager.netWorkAvailable(context))
{
CIMPushManager.connect(context);
}
onConnectionClosed();
}
Handler connectionHandler = new Handler(){
@Override
public void handleMessage(android.os.Message message){
CIMPushManager.connect(context);
}
};
private void onInnerConnectionFailed(Exception e){
private void onConnectionFailed(Exception e){
if(CIMConnectorManager.netWorkAvailable(context)) if(CIMConnectorManager.netWorkAvailable(context))
{ {
//间隔30秒后重连 connectionHandler.sendEmptyMessageDelayed(0, CIMConstant.RECONN_INTERVAL_TIME);
connectionHandler.sendMessageDelayed(connectionHandler.obtainMessage(), 30*1000);
} }
onConnectionFailed(e);
} }
Handler connectionHandler = new Handler()
{
@Override
public void handleMessage(android.os.Message message){
CIMPushManager.init(context);
private void onInnerConnectionSuccessed(){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE, true);
boolean autoBind = CIMPushManager.autoBindAccount(context);
onConnectionSuccessed(autoBind);
} }
};
private void onUncaughtException(Throwable arg0) {} private void onUncaughtException(Throwable arg0) {}
@ -194,17 +185,17 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
if(info !=null) if(info !=null)
{ {
CIMPushManager.init(context); CIMPushManager.connect(context);
} }
onNetworkChanged(info); onNetworkChanged(info);
} }
private void filterType999Message(com.farsunset.cim.client.model.Message message) private void onInnerMessageReceived(com.farsunset.cim.sdk.android.model.Message message)
{ {
if(CIMConstant.MessageType.TYPE_999.equals(message.getType())) if(CIMConstant.MessageType.TYPE_999.equals(message.getType()))
{ {
CIMCacheTools.putBoolean(context,CIMCacheTools.KEY_MANUAL_STOP,true); CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP,true);
} }
onMessageReceived(message); onMessageReceived(message);
@ -215,7 +206,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
//与服务端端开链接重新连接 //与服务端端开链接重新连接
if(e instanceof CIMSessionDisableException) if(e instanceof CIMSessionDisableException)
{ {
CIMPushManager.init(context); CIMPushManager.connect(context);
}else }else
{ {
//发送失败 重新发送 //发送失败 重新发送
@ -225,15 +216,12 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver impl
} }
private void onSentSucceed(SentBody body){} private void onSentSucceed(SentBody body){}
@Override @Override
public abstract void onMessageReceived(com.farsunset.cim.client.model.Message message); public abstract void onMessageReceived(Message message);
@Override @Override
public abstract void onReplyReceived(ReplyBody body); public abstract void onReplyReceived(ReplyBody body);
public abstract void onNetworkChanged(NetworkInfo info); public abstract void onNetworkChanged(NetworkInfo info);
public abstract void onConnectionFailed(Exception e);
public abstract void onCIMConnectionSucceed();
public abstract void onCIMConnectionClosed();
} }

View File

@ -0,0 +1,57 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import android.net.NetworkInfo;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.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 networkinfo
*/
public abstract void onNetworkChanged(NetworkInfo networkinfo);
/**
* 当连接服务器成功时回调
* @param hasAutoBind : true 已经自动绑定账号到服务器了不需要再手动调用bindAccount
*/
public abstract void onConnectionSuccessed(boolean hasAutoBind);
/**
* 当断开服务器连接的时候回调
*/
public abstract void onConnectionClosed();
/**
* 当服务器连接失败的时候回调
*
*/
public abstract void onConnectionFailed(Exception e);
}

View File

@ -4,17 +4,21 @@
* *
* @author 3979434@qq.com * @author 3979434@qq.com
*/ */
package com.farsunset.cim.client.android; package com.farsunset.cim.sdk.android;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import com.farsunset.cim.client.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.NetworkInfo;
import android.util.Log;
/** /**
@ -44,13 +48,53 @@ public class CIMListenerManager {
} }
} }
public static ArrayList<CIMEventListener> getCIMListeners() {
return cimListeners; public static void notifyOnNetworkChanged(NetworkInfo info) {
for (CIMEventListener listener : cimListeners) {
listener.onNetworkChanged(info);
}
} }
public static void notifyOnConnectionSuccessed(boolean hasAutoBind) {
for (CIMEventListener listener : cimListeners) {
listener.onConnectionSuccessed(hasAutoBind);
}
}
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) {
Log.i(CIMEventListener.class.getSimpleName(),"#######" + listener.getClass().getName() + "#######" );
}
}
/** /**
* 消息接收activity的接收顺序排序CIM_RECEIVE_ORDER倒序 * 消息接收activity的接收顺序排序CIM_RECEIVE_ORDER倒序

View File

@ -0,0 +1,250 @@
/**
* probject:cim-android-sdk
* @version 2.0.0
*
* @author 3979434@qq.com
*/
package com.farsunset.cim.sdk.android;
import java.util.UUID;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.telephony.TelephonyManager;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.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(Context context,String host,int port){
connect(context,host,port,false);
}
private static void connect(Context context,String ip,int port,boolean autoBind){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, false);
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
CIMCacheToolkit.getInstance(context).putString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
CIMCacheToolkit.getInstance(context).putInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
if(!autoBind)
{
CIMCacheToolkit.getInstance(context).remove(CIMCacheToolkit.KEY_ACCOUNT);
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_HOST, ip);
serviceIntent.putExtra(CIMCacheToolkit.KEY_CIM_SERVIER_PORT, port);
serviceIntent.setAction(ACTION_CREATE_CIM_CONNECTION);
context.startService(serviceIntent);
}
protected static void connect(Context context){
boolean isManualStop = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualStop || isManualDestory)
{
return ;
}
String host = CIMCacheToolkit.getInstance(context).getString( CIMCacheToolkit.KEY_CIM_SERVIER_HOST);
int port =CIMCacheToolkit.getInstance(context).getInt( CIMCacheToolkit.KEY_CIM_SERVIER_PORT);
connect(context,host,port,true);
}
/**
* 设置一个账号登录到服务端
* @param account 用户唯一ID
*/
public static void bindAccount(Context context,String account){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory || account==null || account.trim().length()==0)
{
return ;
}
sendBindRequest(context,account);
}
private static void sendBindRequest(Context context, String account){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, false);
CIMCacheToolkit.getInstance(context).putString(CIMCacheToolkit.KEY_ACCOUNT, account);
String imei = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
imei += context.getPackageName();
SentBody sent = new SentBody();
sent.setKey(CIMConstant.RequestKey.CLIENT_BIND);
sent.put("account", account);
sent.put("deviceId",UUID.nameUUIDFromBytes(imei.getBytes()).toString().replaceAll("-", ""));
sent.put("channel", "android");
sent.put("device",android.os.Build.MODEL);
sent.put("version",getVersionName(context));
sent.put("osVersion",android.os.Build.VERSION.RELEASE);
sent.put("packageName",context.getPackageName());
sendRequest(context,sent);
}
protected static boolean autoBindAccount(Context context){
String account = CIMCacheToolkit.getInstance(context).getString(CIMCacheToolkit.KEY_ACCOUNT);
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
boolean isManualStoped = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
if( isManualStoped || account==null || account.trim().length()==0 || isManualDestory )
{
return false;
}
sendBindRequest(context,account);
return true;
}
/**
* 发送一个CIM请求
* @param context
* @body
*/
public static void sendRequest(Context context, SentBody body){
boolean isManualStop = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualStop || isManualDestory)
{
return ;
}
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.putExtra(KEY_SEND_BODY, body);
serviceIntent.setAction(ACTION_SEND_REQUEST_BODY);
context.startService(serviceIntent);
}
/**
* 停止接受推送将会退出当前账号登录端口与服务端的连接
* @param context
*/
public static void stop(Context context){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory){
return ;
}
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_MANUAL_STOP, true);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_CLOSE_CIM_CONNECTION);
context.startService(serviceIntent);
}
/**
* 完全销毁CIM一般用于完全退出程序调用resume将不能恢复
* @param context
*/
public static void destroy(Context context){
CIMCacheToolkit.getInstance(context).putBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED, true);
CIMCacheToolkit.getInstance(context).remove(CIMCacheToolkit.KEY_ACCOUNT);
Intent serviceIntent = new Intent(context, CIMPushService.class);
serviceIntent.setAction(ACTION_DESTORY);
context.startService(serviceIntent);
}
/**
* 重新恢复接收推送重新连接服务端并登录当前账号如果aotuBind == true
* @param context
* @param aotuBind
*/
public static void resume(Context context){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory){
return ;
}
autoBindAccount(context);
}
public static boolean isConnected(Context context){
return CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_CONNECTION_STATE);
}
public static int getState(Context context){
boolean isManualDestory = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_CIM_DESTROYED);
if(isManualDestory){
return STATE_DESTROYED;
}
boolean isManualStop = CIMCacheToolkit.getInstance(context).getBoolean(CIMCacheToolkit.KEY_MANUAL_STOP);
if(isManualStop){
return STATE_STOPED;
}
return STATE_NORMAL;
}
private static String getVersionName(Context context) {
String versionName = null;
try {
PackageInfo mPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
versionName = mPackageInfo.versionName;
} catch (NameNotFoundException e) {
}
return versionName;
}
}

Some files were not shown because too many files have changed in this diff Show More