UNPKG

nyx_server

Version:

Node内容发布

327 lines (286 loc) 11.9 kB
(function (win) { "use strict"; /** * 消息管理对象 * @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);