nyx_server
Version:
Node内容发布
327 lines (286 loc) • 11.9 kB
JavaScript
(function (win) {
;
/**
* 消息管理对象
* @param options
* {
* serverUrl: 服务器地址
* dataType: 数据类型 string | json
* socketType: WebSocket | XHR | JSONP
* interval : 抓取时间
* }
*
* 向服务器提供的消息格式
* {
msgType:”onRegEvent|onUnregEvent|onceEvent”,
params:{
entity: “topic|page|fragment|…”
op: “publish|edit|online|lock…”
id: “123”,
attach:{},
}
}
*/
var MsgManager = function(options){
//这里需要能够通过scheme得到传输对象
var socket = getSocket(this , options);
EventEmitter.call(this); //合并EventEmitter方法
var _options = options || {};
var interval = _options.interval || 3000;
var eventDatas = {};
var iID;
var _self = this;
var closeRetry = 10; //用户关闭重连次数
var connState = 'closed'; //连接状态
//获得scoket
function getSocket(magManager , options){
var socketType = 'undefined' != typeof options.socketType ? options.socketType : 'XHR';
if(socketType == 'WebSocket'){
return new WS(magManager , options);
}else if(socketType == 'XHR'){
return new XHR(magManager , options);
}else if(socketType == 'JSONP'){
return new JSONP(magManager , options);
}
}
/**
* 注册一个监听事件,注册只在WebSocket中使用
* @param msgTYpe 消息类型
* @param entityType 监控的实体类型
* @param entityId 监控的实体ID
* @param receiver 消息的回调方法
* @param options 配置注册的配置信息
{int} timeout 注册的超时时间(毫秒)
* {int} retry 注册超时的重试次数
* {object} attach 额外的数据,客户端解释该数据,简单的对象类型
*/
this.register = function (msgType , entityType , entityId , receiver , options ){
var entityId = ((typeof entityId == 'undefined') || (entityId ==null)) ? '' : entityId;
var options = options || {};
var key = msgType+'_'+entityType+"_"+entityId; //消息的唯一标示
var attach = options.attach || {};
var sendData = {msgType:'onRegEvent' , params:{entity:entityType , id:entityId , op :msgType , attach:attach }};
eventDatas[key] = {};
eventDatas[key].type = 'onRegEvent'; //注册事件
eventDatas[key].eventData = sendData; //事件的具体内容
eventDatas[key].status = 'sended'; //已经发送
eventDatas[key].sendTime = new Date(); //发送到服务器的时间,用来进行重发的。
eventDatas[key].sendCount = 0;
eventDatas[key].timeout = options.timeout || 30000; //默认30秒
eventDatas[key].retry = options.retry || 5; //默认重发5次
eventDatas[key].receiveCount = 0; //接收数据的次数
eventDatas[key].attach = options.attach || {}; //默认附着数据
this.on(key , receiver);
socket.send(sendData);
};
var removeListener = function(key){
var _data = {};
for(var p in eventDatas){
if(p != key){
_data[p] = eventDatas[p];
}else{
_self.removeAllListeners(p); //删除所有事件监听
}
}
eventDatas = _data;
}
/**
* 反注册监听消息
* @param msgTYpe 消息类型
* @param entityType 监控的实体类型
* @param entityId 监控的实体ID
*/
this.unregister = function(msgType , entityType , entityId){
var entityId = ((typeof entityId == 'undefined') || (entityId ==null)) ? '' : entityId;
var key = msgType+'_'+entityType+"_"+entityId;
removeListener(key);
var sendData = {'msgType':'onUnregEvent' , params:{entity:entityType , id:entityId , op : msgType}};
socket.send(sendData);
};
/**
* 轮询向服务器发送消息,轮询的事件由MsgManager创建时指定,如果没有指定使用默认值
* @param msgTYpe 消息类型
* @param entityType 监控的实体类型
* @param entityId 监控的实体ID
* @param receiver 消息的回调方法
* @param options 配置属性
{int} interval 轮询的间隔时间(毫秒)
{Object} attach 附着的本地数据
*/
this.poll = function(msgType , entityType , entityId , receiver , options){
var entityId = ((typeof entityId == 'undefined') || (entityId ==null)) ? '' : entityId;
var options = options || {};
var attach = options.attach || {};
var key = msgType+'_'+entityType+"_"+entityId; //消息的唯一标示
var sendData = {msgType :'onceEvent' , params:{entity:entityType,id:entityId , op :msgType , attach:attach }};
eventDatas[key] = {};
eventDatas[key].type = 'onceEvent'; //注册事件
eventDatas[key].eventData = sendData; //事件的具体内容
eventDatas[key].sendCount = 0; //已发送次数
eventDatas[key].sendTime = new Date(); //发送数据的时间
eventDatas[key].interval = options.interval || 10000; //默认轮询间隔10秒
eventDatas[key].status = 'completed'; //默认就是完成状态
this.on(key , receiver);
socket.send(sendData);
};
/**
* 当连接打开时,开始定时向服务端发送方消息
*/
this.onOpen = function(){
connState = 'connected';
iID = setInterval(function(){
for(var p in eventDatas){
var data = eventDatas[p];
var curDate = new Date();
if( (data.type == 'onRegEvent') //注册事件
&& (data.status != 'completed') //未注册成功状态
&& (data.timeout < curDate.getTime() - data.sendTime.getTime()) //已经注册超时
&& (data.sendCount < data.retry) //重试次数不超过配置
){
data.sendTime = new Date(); //重置发送时间
data.sendCount ++; //增加重试次数
socket.send(data.eventData);
}else if(data.type == 'onceEvent' && (data.interval < (curDate.getTime() - data.sendTime.getTime()))){ //轮询时间
//如果是轮询事件
data.sendTime = new Date(); //重置发送时间
data.sendCount ++;
socket.send(data.eventData);
}
}
} , interval);
};
/**
* 服务器返回消息格式
* {
* msgType:”onRegEvent|onUnregEvent|onceEvent”,
* code:'OK|ERROR',
* params:{
* entity:'',
* id:'',
* op:'publish|edit|online|notify|error',
* data:{...}
* attach:{}
* }
* }
*/
this.onData = function(result){
var jdata = result;
if(Object.prototype.toString.call(result) === '[object Array]'){
jdata = result[0];
}
var msgData = jdata.params;
var msgType = jdata.params.op; //消息类型,例如发布、编辑
if(msgType == 'notify'){ //通知类型直接给注册的方法
this.emit("notify" , jdata);
return;
}
var code = jdata.code; // code:'OK|ERROR'
var entityType = typeof jdata.params.entity == 'undefined' ? '' : jdata.params.entity ; //实体类型
var entityId = typeof jdata.params.id == 'undefined' ? '' : jdata.params.id; //实体id
var key = msgType+"_"+entityType+"_"+entityId;
var data = eventDatas[key];
if(code == 'OK' && ('undefined'!= typeof data) && data.type == 'onRegEvent'){ //这里是事件返回 注册|轮询|取消 ,对于onUnregEvent和onceEvent,不做处理
data.status = 'completed';
}else if(code == 'ERROR'){ //
//对于加锁则需要告诉前端调用
msgData.success = false;
msgData.msg = jdata.msg; //系统异常错误消息
if(data.params && (data.params.op == 'lock' || data.params.op == 'unlock')){
this.emit(key , msgData);
}
}else if(code == ''){ //如果是空字符串,则后端推送了具体业务数据
//这里是真正的业务消息
msgData.success = true; //为方便处理,这里为前端加一个是否成功的状态
this.emit(key , msgData);
}
};
/**
* 通用的消息接收,这个消息现在接收通用消息格式
*/
this.receiveMsg = function(receiver){
this.on("notify" , receiver);
};
/**
* 请求一个对象锁
* @param entityType 类型
* @param entityId ID
* @param receive 请求加锁结果接收者
*/
this.lock = function(entityType , entityId , receiver){
if(connState == 'closed'){ //还未连接成功,需要立即返回给用户
var params = {};
params.entity = entityType;
params.id = entityId;
params.success = false;
params.msg = '还未建立连接!';
params.op = 'lock';
if(typeof receiver != 'undefined' && typeof receicer == 'function'){
receiver(msg);
}
return;
}
//这里直接使用poll,只是将轮训周期设置为一天,
var proxy = function(data){
var key = 'lock_'+entityType+"_"+entityId; //消息的唯一标示
removeListener(key);
receiver(data);
}
this.poll('lock' , entityType , entityId , proxy , {interval:24*60*60*1000});
};
/**
* 释放一个对象上的锁
* @param entityType 类型
* @param entityId ID
*/
this.unlock = function(entityType , entityId , receiver){
var proxy = function(data){
var key = 'unlock_'+entityType+"_"+entityId; //消息的唯一标示
removeListener(key);
receiver(data);
}
this.poll('unlock' , entityType , entityId , proxy , {interval:24*60*60*1000});
};
//服务器连接关闭,
var waitconnect = '';
this.onClose = function(){
if(waitconnect == ''){
reconnect();
}
};
this.onError = function(e){
if(waitconnect == ''){
reconnect();
}
};
var reconnect = function(){
waitconnect = 'wait';
setInterval(function(){
if(connState == 'connected'){
waitconnect = '';
return;
}
if(closeRetry > 0){
if(iID){
clearInterval(iID);
}
//重新初始化数据,重新建立连接,重新注册事件
for(var p in eventDatas){
var data = eventDatas[p];
data.sendCount = 0;
data.sendTime = new Date();
if(data.type == 'onRegEvent'){
data.status = 'sended';
}
}
closeRetry--;
socket.open();
}
},10000); //断开后10秒后重连
};
this.getConnState = function(){
return connState;
};
socket.open();
};
win.MsgManager = MsgManager;
})(window);