UNPKG

@sex-pomelo/sex-pomelo

Version:

[![NPM version][npm-image-pomelo]][npm-url-pomelo] [![NPM version][npm-image-down]][npm-url-pomelo]

162 lines (134 loc) 3.73 kB
"use strict"; const EventEmitter = require('events').EventEmitter; const sio = require('socket.io')(); //const server = require('http').createServer(); // const sio = require('socket.io')(server,{ // cors: { // origin: ["http://127.0.0.1:3001",], // methods: ["GET", "POST"], // credentials: false // } // }); const SioSocket = require('./siosocket'); const PKG_ID_BYTES = 4; const PKG_ROUTE_LENGTH_BYTES = 1; const PKG_HEAD_BYTES = PKG_ID_BYTES + PKG_ROUTE_LENGTH_BYTES; let curId = 1; let gConn = null; /** * @namespace SioConnector */ /** * Connector that manager low level connection and protocol bewteen server and client. * Develper can provide their own connector to switch the low level prototol, such as tcp or probuf. * * @class * @constructor * @memberof SioConnector */ class Connector extends EventEmitter { constructor(port, host, opts) { super(); this.port = port; this.host = host; this.opts = opts; this.heartbeats = opts.heartbeats || true; this.closeTimeout = opts.closeTimeout || 60; this.heartbeatTimeout = opts.heartbeatTimeout || 60; this.heartbeatInterval = opts.heartbeatInterval || 25; } /** * Start connector to listen the specified port */ start(cb) { let self = this; sio.on('connection', function(socket) { let siosocket = new SioSocket(curId++, socket); self.emit('connection', siosocket); siosocket.on('closing', function(reason) { siosocket.send({ route: 'onKick', reason: reason }); }); }); // issue https://github.com/NetEase/pomelo-cn/issues/174 if(!!this.opts) { this.wsocket = sio.listen(this.port, this.opts); } else { this.wsocket = sio.listen(this.port, { transports: [ 'websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling', 'flashsocket' ], pingTimeout: this.heartbeatTimeout, pingInterval: this.heartbeatInterval }); } process.nextTick(cb); } /** * Stop connector */ stop (force, cb) { this.wsocket.server.close(); process.nextTick(cb); } encode(reqId, route, msg) { if(reqId) { return composeResponse(reqId, route, msg); } else { return composePush(route, msg); } } /** * Decode client message package. * * Package format: * message id: 4bytes big-endian integer * route length: 1byte * route: route length bytes * body: the rest bytes * * @param {String} data socket.io package from client * @return {Object} message object */ decode (msg) { let index = 0; let id = parseIntField(msg, index, PKG_ID_BYTES); index += PKG_ID_BYTES; let routeLen = parseIntField(msg, index, PKG_ROUTE_LENGTH_BYTES); let route = msg.substr(PKG_HEAD_BYTES, routeLen); let body = msg.substr(PKG_HEAD_BYTES + routeLen); return { id: id, route: route, body: JSON.parse(body) }; } } module.exports = function(port, host, opts) { if (gConn === null) { gConn = new Connector(port, host, opts); } return gConn; }; let composeResponse = function(msgId, route, msgBody) { return { id: msgId, body: msgBody }; }; let composePush = function(route, msgBody) { return JSON.stringify({route: route, body: msgBody}); }; let parseIntField = function(str, offset, len) { let res = 0; for(let i=0; i<len; i++) { if(i > 0) { res <<= 8; } res |= str.charCodeAt(offset + i) & 0xff; } return res; };