Skip to content

Instantly share code, notes, and snippets.

@yangfch3
Created March 21, 2018 06:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yangfch3/c60babb36179b556bed011b8db7e72ce to your computer and use it in GitHub Desktop.
Save yangfch3/c60babb36179b556bed011b8db7e72ce to your computer and use it in GitHub Desktop.
pomelo 小程序客户端
(function() {
var JS_WS_CLIENT_TYPE = 'js-websocket';
var JS_WS_CLIENT_VERSION = '0.0.1';
//微信web开发工具v0.10.102800之前不支持arraybuffer,websocket发送data数据之前转换为utf8字符串
function toUTF8Array(str) {
var utf8 = [];
for (var i=0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff));
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
var isArray = Array.isArray;
var root = this;
function EventEmitter() {
}
// if (typeof module !== 'undefined' && module.exports) {
// module.exports.EventEmitter = EventEmitter;
// }
// else {
// root = window;
// root.EventEmitter = EventEmitter;
// }
// By default EventEmitters will print a warning if more than
// 10 listeners are added to it. This is a useful default which
// helps finding memory leaks.
//
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
var defaultMaxListeners = 10;
EventEmitter.prototype.setMaxListeners = function(n) {
if (!this._events) this._events = {};
this._maxListeners = n;
};
EventEmitter.prototype.emit = function() {
var type = arguments[0];
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events || !this._events.error ||
(isArray(this._events.error) && !this._events.error.length))
{
if (this.domain) {
var er = arguments[1];
er.domain_emitter = this;
er.domain = this.domain;
er.domain_thrown = false;
this.domain.emit('error', er);
return false;
}
if (arguments[1] instanceof Error) {
throw arguments[1]; // Unhandled 'error' event
} else {
throw new Error("Uncaught, unspecified 'error' event.");
}
return false;
}
}
if (!this._events) return false;
var handler = this._events[type];
if (!handler) return false;
if (typeof handler == 'function') {
if (this.domain) {
this.domain.enter();
}
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
var l = arguments.length;
var args = new Array(l - 1);
for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
handler.apply(this, args);
}
if (this.domain) {
this.domain.exit();
}
return true;
} else if (isArray(handler)) {
if (this.domain) {
this.domain.enter();
}
var l = arguments.length;
var args = new Array(l - 1);
for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
var listeners = handler.slice();
for (var i = 0, l = listeners.length; i < l; i++) {
listeners[i].apply(this, args);
}
if (this.domain) {
this.domain.exit();
}
return true;
} else {
return false;
}
};
EventEmitter.prototype.addListener = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('addListener only takes instances of Function');
}
if (!this._events) this._events = {};
// To avoid recursion in the case that type == "newListeners"! Before
// adding it to the listeners, first emit "newListeners".
this.emit('newListener', type, typeof listener.listener === 'function' ?
listener.listener : listener);
if (!this._events[type]) {
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
} else if (isArray(this._events[type])) {
// If we've already got an array, just append.
this._events[type].push(listener);
} else {
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
}
// Check for listener leak
if (isArray(this._events[type]) && !this._events[type].warned) {
var m;
if (this._maxListeners !== undefined) {
m = this._maxListeners;
} else {
m = defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
console.trace();
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('.once only takes instances of Function');
}
var self = this;
function g() {
self.removeListener(type, g);
listener.apply(this, arguments);
};
g.listener = listener;
self.on(type, g);
return this;
};
EventEmitter.prototype.removeListener = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('removeListener only takes instances of Function');
}
// does not use listeners(), so no side effect of creating _events[type]
if (!this._events || !this._events[type]) return this;
var list = this._events[type];
if (isArray(list)) {
var position = -1;
for (var i = 0, length = list.length; i < length; i++) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener))
{
position = i;
break;
}
}
if (position < 0) return this;
list.splice(position, 1);
} else if (list === listener ||
(list.listener && list.listener === listener))
{
delete this._events[type];
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
if (arguments.length === 0) {
this._events = {};
return this;
}
var events = this._events && this._events[type];
if (!events) return this;
if (isArray(events)) {
events.splice(0);
} else {
this._events[type] = null;
}
return this;
};
EventEmitter.prototype.listeners = function(type) {
if (!this._events) this._events = {};
if (!this._events[type]) this._events[type] = [];
if (!isArray(this._events[type])) {
this._events[type] = [this._events[type]];
}
return this._events[type];
}
var Protocol = exports;
var PKG_HEAD_BYTES = 4;
var MSG_FLAG_BYTES = 1;
var MSG_ROUTE_CODE_BYTES = 2;
var MSG_ID_MAX_BYTES = 5;
var MSG_ROUTE_LEN_BYTES = 1;
var MSG_ROUTE_CODE_MAX = 0xffff;
var MSG_COMPRESS_ROUTE_MASK = 0x1;
var MSG_TYPE_MASK = 0x7;
var Package = Protocol.Package = {};
var Message = Protocol.Message = {};
Package.TYPE_HANDSHAKE = 1;
Package.TYPE_HANDSHAKE_ACK = 2;
Package.TYPE_HEARTBEAT = 3;
Package.TYPE_DATA = 4;
Package.TYPE_KICK = 5;
Message.TYPE_REQUEST = 0;
Message.TYPE_NOTIFY = 1;
Message.TYPE_RESPONSE = 2;
Message.TYPE_PUSH = 3;
/**
* pomele client encode
* id message id;
* route message route
* msg message body
* socketio current support string
*/
Protocol.strencode = function(str) {
var buffer = new Uint8Array(str.length * 3);
var offset = 0;
for(var i = 0; i < str.length; i++){
var charCode = str.charCodeAt(i);
var codes = null;
if(charCode <= 0x7f){
codes = [charCode];
}else if(charCode <= 0x7ff){
codes = [0xc0|(charCode>>6), 0x80|(charCode & 0x3f)];
}else{
codes = [0xe0|(charCode>>12), 0x80|((charCode & 0xfc0)>>6), 0x80|(charCode & 0x3f)];
}
for(var j = 0; j < codes.length; j++){
buffer[offset] = codes[j];
++offset;
}
}
var _buffer = new Uint8Array(offset);
copyArray(_buffer, 0, buffer, 0, offset);
return _buffer;
};
/**
* client decode
* msg String data
* return Message Object
*/
Protocol.strdecode = function(buffer) {
var bytes = new Uint8Array(buffer);
var array = [];
var offset = 0;
var charCode = 0;
var end = bytes.length;
while(offset < end){
if(bytes[offset] < 128){
charCode = bytes[offset];
offset += 1;
}else if(bytes[offset] < 224){
charCode = ((bytes[offset] & 0x3f)<<6) + (bytes[offset+1] & 0x3f);
offset += 2;
}else{
charCode = ((bytes[offset] & 0x0f)<<12) + ((bytes[offset+1] & 0x3f)<<6) + (bytes[offset+2] & 0x3f);
offset += 3;
}
array.push(charCode);
}
return String.fromCharCode.apply(null, array);
};
/**
* Package protocol encode.
*
* Pomelo package format:
* +------+-------------+------------------+
* | type | body length | body |
* +------+-------------+------------------+
*
* Head: 4bytes
* 0: package type,
* 1 - handshake,
* 2 - handshake ack,
* 3 - heartbeat,
* 4 - data
* 5 - kick
* 1 - 3: big-endian body length
* Body: body length bytes
*
* @param {Number} type package type
* @param {Uint8Array} body body content in bytes
* @return {Uint8Array} new byte array that contains encode result
*/
Package.encode = function(type, body){
var length = body ? body.length : 0;
var buffer = new Uint8Array(PKG_HEAD_BYTES + length);
var index = 0;
buffer[index++] = type & 0xff;
buffer[index++] = (length >> 16) & 0xff;
buffer[index++] = (length >> 8) & 0xff;
buffer[index++] = length & 0xff;
if(body) {
copyArray(buffer, index, body, 0, length);
}
// return String.fromCharCode.apply(null,buffer);
return buffer;
};
/**
* Package protocol decode.
* See encode for package format.
*
* @param {Uint8Array} buffer byte array containing package content
* @return {Object} {type: package type, buffer: body byte array}
*/
Package.decode = function(buffer){
// buffer = toUTF8Array(str)
var offset = 0;
var bytes = new Uint8Array(buffer);
var length = 0;
var rs = [];
while(offset < bytes.length) {
var type = bytes[offset++];
length = ((bytes[offset++]) << 16 | (bytes[offset++]) << 8 | bytes[offset++]) >>> 0;
var body = length ? new Uint8Array(length) : null;
copyArray(body, 0, bytes, offset, length);
offset += length;
rs.push({'type': type, 'body': body});
}
return rs.length === 1 ? rs[0]: rs;
};
/**
* Message protocol encode.
*
* @param {Number} id message id
* @param {Number} type message type
* @param {Number} compressRoute whether compress route
* @param {Number|String} route route code or route string
* @param {Buffer} msg message body bytes
* @return {Buffer} encode result
*/
Message.encode = function(id, type, compressRoute, route, msg){
// caculate message max length
var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0;
var msgLen = MSG_FLAG_BYTES + idBytes;
if(msgHasRoute(type)) {
if(compressRoute) {
if(typeof route !== 'number'){
throw new Error('error flag for number route!');
}
msgLen += MSG_ROUTE_CODE_BYTES;
} else {
msgLen += MSG_ROUTE_LEN_BYTES;
if(route) {
route = Protocol.strencode(route);
if(route.length>255) {
throw new Error('route maxlength is overflow');
}
msgLen += route.length;
}
}
}
console.log('msg.len:'+msg.length)
if(msg) {
msgLen += msg.length;
}
var buffer = new Uint8Array(msgLen);
var offset = 0;
// add flag
offset = encodeMsgFlag(type, compressRoute, buffer, offset);
// add message id
if(msgHasId(type)) {
offset = encodeMsgId(id, buffer, offset);
}
// add route
if(msgHasRoute(type)) {
offset = encodeMsgRoute(compressRoute, route, buffer, offset);
}
// add body
if(msg) {
offset = encodeMsgBody(msg, buffer, offset);
}
return buffer;
};
/**
* Message protocol decode.
*
* @param {Buffer|Uint8Array} buffer message bytes
* @return {Object} message object
*/
Message.decode = function(buffer) {
var bytes = new Uint8Array(buffer);
var bytesLen = bytes.length || bytes.byteLength;
var offset = 0;
var id = 0;
var route = null;
// parse flag
var flag = bytes[offset++];
var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK;
var type = (flag >> 1) & MSG_TYPE_MASK;
// parse id
if(msgHasId(type)) {
var m = parseInt(bytes[offset]);
var i = 0;
do{
var m = parseInt(bytes[offset]);
id = id + ((m & 0x7f) * Math.pow(2,(7*i)));
offset++;
i++;
}while(m >= 128);
}
// parse route
if(msgHasRoute(type)) {
if(compressRoute) {
route = (bytes[offset++]) << 8 | bytes[offset++];
} else {
var routeLen = bytes[offset++];
if(routeLen) {
route = new Uint8Array(routeLen);
copyArray(route, 0, bytes, offset, routeLen);
route = Protocol.strdecode(route);
} else {
route = '';
}
offset += routeLen;
}
}
// parse body
var bodyLen = bytesLen - offset;
var body = new Uint8Array(bodyLen);
copyArray(body, 0, bytes, offset, bodyLen);
return {'id': id, 'type': type, 'compressRoute': compressRoute,
'route': route, 'body': body};
};
var copyArray = function(dest, doffset, src, soffset, length) {
if('function' === typeof src.copy) {
// Buffer
src.copy(dest, doffset, soffset, soffset + length);
} else {
// Uint8Array
for(var index=0; index<length; index++){
dest[doffset++] = src[soffset++];
}
}
};
var msgHasId = function(type) {
return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE;
};
var msgHasRoute = function(type) {
return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY ||
type === Message.TYPE_PUSH;
};
var caculateMsgIdBytes = function(id) {
var len = 0;
do {
len += 1;
id >>= 7;
} while(id > 0);
return len;
};
var encodeMsgFlag = function(type, compressRoute, buffer, offset) {
if(type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY &&
type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) {
throw new Error('unkonw message type: ' + type);
}
buffer[offset] = (type << 1) | (compressRoute ? 1 : 0);
return offset + MSG_FLAG_BYTES;
};
var encodeMsgId = function(id, buffer, offset) {
do{
var tmp = id % 128;
var next = Math.floor(id/128);
if(next !== 0){
tmp = tmp + 128;
}
buffer[offset++] = tmp;
id = next;
} while(id !== 0);
return offset;
};
var encodeMsgRoute = function(compressRoute, route, buffer, offset) {
if (compressRoute) {
if(route > MSG_ROUTE_CODE_MAX){
throw new Error('route number is overflow');
}
buffer[offset++] = (route >> 8) & 0xff;
buffer[offset++] = route & 0xff;
} else {
if(route) {
buffer[offset++] = route.length & 0xff;
copyArray(buffer, offset, route, 0, route.length);
offset += route.length;
} else {
buffer[offset++] = 0;
}
}
return offset;
};
var encodeMsgBody = function(msg, buffer, offset) {
copyArray(buffer, offset, msg, 0, msg.length);
return offset + msg.length;
};
// var Protocol = getApp().Protocol;
// var protobuf = window.protobuf;
// var decodeIO_protobuf = window.decodeIO_protobuf;
// var decodeIO_encoder = null;
// var decodeIO_decoder = null;
// var Package = Protocol.Package;
// var Message = Protocol.Message;
// var EventEmitter = getApp().EventEmitter;
// var rsa = window.rsa;
// if(typeof(window) != "undefined" && typeof(sys) != 'undefined' && sys.localStorage) {
// window.localStorage = sys.localStorage;
// }
var RES_OK = 200;
var RES_FAIL = 500;
var RES_OLD_CLIENT = 501;
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
var root = getApp();
var pomelo = Object.create(EventEmitter.prototype); // object extend from object
root.pomelo = pomelo;
var socket = false;
var reqId = 0;
var callbacks = {};
var handlers = {};
//Map from request id to route
// var routeMap = {};
// var dict = {}; // route string to code
// var abbrs = {}; // code to route string
// var serverProtos = {};
// var clientProtos = {};
// var protoVersion = 0;
var heartbeatInterval = 0;
var heartbeatTimeout = 0;
var nextHeartbeatTimeout = 0;
var gapThreshold = 100; // heartbeat gap threashold
var heartbeatId = null;
var heartbeatTimeoutId = null;
var handshakeCallback = null;
var decode = null;
var encode = null;
var reconnect = false;
var reconncetTimer = null;
var reconnectUrl = null;
var reconnectAttempts = 0;
var reconnectionDelay = 5000;
var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
var useCrypto;
var handshakeBuffer = {
'sys': {
type: JS_WS_CLIENT_TYPE,
version: JS_WS_CLIENT_VERSION,
rsa: {}
},
'user': {
}
};
var initCallback = null;
pomelo.init = function(params, cb) {
initCallback = cb;
var host = params.host;
var port = params.port;
encode = params.encode || defaultEncode;
decode = params.decode || defaultDecode;
var url = 'ws://' + host;
if(port) {
url += ':' + port;
}
handshakeBuffer.user = params.user;
// if(params.encrypt) {
// useCrypto = true;
// rsa.generate(1024, "10001");
// var data = {
// rsa_n: rsa.n.toString(16),
// rsa_e: rsa.e
// }
// handshakeBuffer.sys.rsa = data;
// }
handshakeCallback = params.handshakeCallback;
connect(params, url, cb);
};
var defaultDecode = pomelo.decode = function(data) {
//probuff decode
var msg = Message.decode(data);
// if(msg.id > 0){
// msg.route = routeMap[msg.id];
// delete routeMap[msg.id];
// if(!msg.route){
// return;
// }
// }
msg.body = deCompose(msg);
return msg;
};
var defaultEncode = pomelo.encode = function(reqId, route, msg) {
var type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY;
//compress message by protobuf
// if(protobuf && clientProtos[route]) {
// msg = protobuf.encode(route, msg);
// } else if(decodeIO_encoder && decodeIO_encoder.lookup(route)) {
// var Builder = decodeIO_encoder.build(route);
// msg = new Builder(msg).encodeNB();
// } else {
msg = Protocol.strencode(JSON.stringify(msg));
// }
var compressRoute = 0;
// if(dict && dict[route]) {
// route = dict[route];
// compressRoute = 1;
// }
return Message.encode(reqId, type, compressRoute, route, msg);
};
var connect = function(params, url, cb) {
console.log('connect to ' + url);
var params = params || {};
var maxReconnectAttempts = params.maxReconnectAttempts || DEFAULT_MAX_RECONNECT_ATTEMPTS;
reconnectUrl = url;
//Add protobuf version
// if(window.localStorage && window.localStorage.getItem('protos') && protoVersion === 0) {
// var protos = JSON.parse(window.localStorage.getItem('protos'));
//
// protoVersion = protos.version || 0;
// serverProtos = protos.server || {};
// clientProtos = protos.client || {};
//
// if(!!protobuf) {
// protobuf.init({encoderProtos: clientProtos, decoderProtos: serverProtos});
// }
// if(!!decodeIO_protobuf) {
// decodeIO_encoder = decodeIO_protobuf.loadJson(clientProtos);
// decodeIO_decoder = decodeIO_protobuf.loadJson(serverProtos);
// }
// }
//Set protoversion
// handshakeBuffer.sys.protoVersion = protoVersion;
var onopen = function(event) {
if(!!reconnect) {
pomelo.emit('reconnect');
}
reset();
socket =true;
var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(handshakeBuffer)));
send(obj);
};
var onmessage = function(event) {
processPackage(Package.decode(event.data), cb);
// new package arrived, update the heartbeat timeout
if(heartbeatTimeout) {
nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
}
};
var onerror = function(event) {
pomelo.emit('io-error', event);
console.error('socket error: ', event);
};
var onclose = function(event) {
pomelo.emit('close',event);
pomelo.emit('disconnect', event);
if(!!params.reconnect && reconnectAttempts < maxReconnectAttempts) {
reconnect = true;
reconnectAttempts++;
reconncetTimer = setTimeout(function() {
connect(params, reconnectUrl, cb);
}, reconnectionDelay);
reconnectionDelay *= 2;
}
};
// socket = new WebSocket(url);
// socket.binaryType = 'arraybuffer';
// socket.onopen = onopen;
// socket.onmessage = onmessage;
// socket.onerror = onerror;
// socket.onclose = onclose;
wx.connectSocket({
// url: `${url}?EIO=3&transport=websocket`
url:url
});
wx.onSocketError(onerror);
wx.onSocketOpen(onopen);
wx.onSocketMessage(onmessage);
wx.onSocketClose(onclose);
};
pomelo.disconnect = function() {
if(socket) {
wx.closeSocket()
console.log('disconnect');
socket = false;
}
if(heartbeatId) {
clearTimeout(heartbeatId);
heartbeatId = null;
}
if(heartbeatTimeoutId) {
clearTimeout(heartbeatTimeoutId);
heartbeatTimeoutId = null;
}
};
var reset = function() {
reconnect = false;
reconnectionDelay = 1000 * 5;
reconnectAttempts = 0;
clearTimeout(reconncetTimer);
};
pomelo.request = function(route, msg, cb) {
if(arguments.length === 2 && typeof msg === 'function') {
cb = msg;
msg = {};
} else {
msg = msg || {};
}
route = route || msg.route;
if(!route) {
return;
}
reqId++;
sendMessage(reqId, route, msg);
callbacks[reqId] = cb;
// routeMap[reqId] = route;
};
pomelo.notify = function(route, msg) {
msg = msg || {};
sendMessage(0, route, msg);
};
var sendMessage = function(reqId, route, msg) {
// if(useCrypto) {
// msg = JSON.stringify(msg);
// var sig = rsa.signString(msg, "sha256");
// msg = JSON.parse(msg);
// msg['__crypto__'] = sig;
// }
if(encode) {
msg = encode(reqId, route, msg);
}
var packet = Package.encode(Package.TYPE_DATA, msg);
send(packet);
};
var send = function(packet) {
if(socket)
wx.sendSocketMessage({data:packet.buffer});
};
var handler = {};
var heartbeat = function(data) {
if(!heartbeatInterval) {
// no heartbeat
return;
}
var obj = Package.encode(Package.TYPE_HEARTBEAT);
if(heartbeatTimeoutId) {
clearTimeout(heartbeatTimeoutId);
heartbeatTimeoutId = null;
}
if(heartbeatId) {
// already in a heartbeat interval
return;
}
heartbeatId = setTimeout(function() {
heartbeatId = null;
send(obj);
nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, heartbeatTimeout);
}, heartbeatInterval);
};
var heartbeatTimeoutCb = function() {
var gap = nextHeartbeatTimeout - Date.now();
if(gap > gapThreshold) {
heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, gap);
} else {
console.error('server heartbeat timeout');
pomelo.emit('heartbeat timeout');
pomelo.disconnect();
}
};
var handshake = function(data) {
data = JSON.parse(Protocol.strdecode(data));
if(data.code === RES_OLD_CLIENT) {
pomelo.emit('error', 'client version not fullfill');
return;
}
if(data.code !== RES_OK) {
pomelo.emit('error', 'handshake fail');
return;
}
handshakeInit(data);
var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK);
send(obj);
if(initCallback) {
initCallback(socket);
}
};
var onData = function(data) {
var msg = data;
if(decode) {
msg = decode(msg);
}
processMessage(pomelo, msg);
};
var onKick = function(data) {
data = JSON.parse(Protocol.strdecode(data));
pomelo.emit('onKick', data);
};
handlers[Package.TYPE_HANDSHAKE] = handshake;
handlers[Package.TYPE_HEARTBEAT] = heartbeat;
handlers[Package.TYPE_DATA] = onData;
handlers[Package.TYPE_KICK] = onKick;
var processPackage = function(msgs) {
if(Array.isArray(msgs)) {
for(var i=0; i<msgs.length; i++) {
var msg = msgs[i];
handlers[msg.type](msg.body);
}
} else {
handlers[msgs.type](msgs.body);
}
};
var processMessage = function(pomelo, msg) {
if(!msg.id) {
// server push message
console.log(msg.route +':');
console.log(msg.body);
pomelo.emit(msg.route, msg.body);
return;
}
//if have a id then find the callback function with the request
var cb = callbacks[msg.id];
delete callbacks[msg.id];
if(typeof cb !== 'function') {
return;
}
cb(msg.body);
return;
};
var processMessageBatch = function(pomelo, msgs) {
for(var i=0, l=msgs.length; i<l; i++) {
processMessage(pomelo, msgs[i]);
}
};
var deCompose = function(msg) {
var route = msg.route;
//
// //Decompose route from dict
// if(msg.compressRoute) {
// if(!abbrs[route]){
// return {};
// }
//
// route = msg.route = abbrs[route];
// }
// if(protobuf && serverProtos[route]) {
// return protobuf.decodeStr(route, msg.body);
// } else if(decodeIO_decoder && decodeIO_decoder.lookup(route)) {
// return decodeIO_decoder.build(route).decode(msg.body);
// } else {
return JSON.parse(Protocol.strdecode(msg.body));
// }
// return msg;
};
var handshakeInit = function(data) {
if(data.sys && data.sys.heartbeat) {
heartbeatInterval = data.sys.heartbeat * 1000; // heartbeat interval
heartbeatTimeout = heartbeatInterval * 2; // max heartbeat timeout
} else {
heartbeatInterval = 0;
heartbeatTimeout = 0;
}
initData(data);
if(typeof handshakeCallback === 'function') {
handshakeCallback(data.user);
}
};
//Initilize data used in pomelo client
var initData = function(data) {
if(!data || !data.sys) {
return;
}
// dict = data.sys.dict;
// var protos = data.sys.protos;
//
// //Init compress dict
// if(dict) {
// dict = dict;
// abbrs = {};
//
// for(var route in dict) {
// abbrs[dict[route]] = route;
// }
// }
//
// //Init protobuf protos
// if(protos) {
// protoVersion = protos.version || 0;
// serverProtos = protos.server || {};
// clientProtos = protos.client || {};
//
// //Save protobuf protos to localStorage
// window.localStorage.setItem('protos', JSON.stringify(protos));
//
// if(!!protobuf) {
// protobuf.init({encoderProtos: protos.client, decoderProtos: protos.server});
// }
// if(!!decodeIO_protobuf) {
// decodeIO_encoder = decodeIO_protobuf.loadJson(clientProtos);
// decodeIO_decoder = decodeIO_protobuf.loadJson(serverProtos);
// }
// }
};
module.exports = pomelo;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment