UNPKG

occaecatidicta

Version:
145 lines (121 loc) 3.92 kB
import * as util from 'util'; import { EventEmitter } from 'events'; import { createServer } from 'http'; let httpServer = createServer(); import { SioSocket } from './siosocket'; import { IConnector } from '../interfaces/IConnector'; import * as socket_io from 'socket.io'; let PKG_ID_BYTES = 4; let PKG_ROUTE_LENGTH_BYTES = 1; let PKG_HEAD_BYTES = PKG_ID_BYTES + PKG_ROUTE_LENGTH_BYTES; let curId = 1; export type SIOConnectorOptions = socket_io.ServerOptions; /** * 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. */ export class SIOConnector extends EventEmitter implements IConnector { port: number; host: string; opts: SIOConnectorOptions; private server: SocketIO.Server; constructor(port: number, host: string, opts: SIOConnectorOptions) { super(); this.port = port; this.host = host; this.opts = opts; opts.pingTimeout = opts.pingTimeout || 60; opts.pingInterval = opts.pingInterval || 25; } /** * Start connector to listen the specified port */ start(cb: () => void) { let self = this; // issue https://github.com/NetEase/omelox-cn/issues/174 let opts: SIOConnectorOptions; if (!!this.opts) { opts = this.opts; } else { opts = { transports: [ 'websocket', 'polling-xhr', 'polling-jsonp', 'polling' ] } as any; } opts.path = '/socket.io'; let sio = socket_io(httpServer, opts); let port = this.port; httpServer.listen(port, function () { console.log('sio Server listening at port %d', port); }); sio.on('connection', (socket) => { // this.wsocket.sockets.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 }); }); }); process.nextTick(cb); } /** * Stop connector */ stop(force: boolean, cb: () => void) { this.server.close(); process.nextTick(cb); } encode(reqId: number, route: string, msg: any) { 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: any) { 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) }; } } let composeResponse = function (msgId: number, route: string, msgBody: any) { return { id: msgId, body: msgBody }; }; let composePush = function (route: string, msgBody: any) { return JSON.stringify({ route: route, body: msgBody }); }; let parseIntField = function (str: string, offset: number, len: number) { let res = 0; for (let i = 0; i < len; i++) { if (i > 0) { res <<= 8; } res |= str.charCodeAt(offset + i) & 0xff; } return res; };