UNPKG

@sex-pomelo/sex-pomelo

Version:

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

117 lines (91 loc) 3.01 kB
"use strict"; const net = require('net'); const dgram = require("dgram"); const utils = require('../util/utils'); const Constants = require('../util/constants'); const UdpSocket = require('./udpsocket'); const Kick = require('./commands/kick'); const Handshake = require('./commands/handshake'); const Heartbeat = require('./commands/heartbeat'); const protocol = require('@sex-pomelo/sex-pomelo-protocol'); let Package = protocol.Package; var Message = protocol.Message; const coder = require('./common/coder'); const EventEmitter = require('events').EventEmitter; let curId = 1; let gConn = null; /** * @namespace UdpConnector */ /** UDP connector * * @class * @constructor * @memberof UdpConnector */ class Connector extends EventEmitter{ constructor(port, host, opts) { super(); this.opts = opts || {}; this.type = opts.udpType || 'udp4'; this.handshake = new Handshake(opts); if(!opts.heartbeat) { opts.heartbeat = Constants.TIME.DEFAULT_UDP_HEARTBEAT_TIME; opts.timeout = Constants.TIME.DEFAULT_UDP_HEARTBEAT_TIMEOUT; } this.heartbeat = new Heartbeat(utils.extends(opts, {disconnectOnTimeout: true})); this.clients = {}; this.host = host; this.port = port; this.decode = coder.decode; this.encode = coder.encode; } start (cb) { let self = this; this.tcpServer = net.createServer(); this.socket = dgram.createSocket(this.type, function(msg, peer) { let key = genKey(peer); if(!self.clients[key]) { let udpsocket = new UdpSocket(curId++, self.socket, peer); self.clients[key] = udpsocket; udpsocket.on('handshake', self.handshake.handle.bind(self.handshake, udpsocket)); udpsocket.on('heartbeat', self.heartbeat.handle.bind(self.heartbeat, udpsocket)); udpsocket.on('disconnect', self.heartbeat.clear.bind(self.heartbeat, udpsocket.id)); udpsocket.on('disconnect', function() { delete self.clients[genKey(udpsocket.peer)]; }); udpsocket.on('closing', Kick.handle.bind(null, udpsocket)); self.emit('connection', udpsocket); } }); this.socket.on('message', function(data, peer) { let socket = self.clients[genKey(peer)]; if(!!socket) { socket.emit('package', data); } }); this.socket.on('error', function(err) { logger.error('udp socket encounters with error: %j', err.stack); return; }); this.socket.bind(this.port, this.host); this.tcpServer.listen(this.port); process.nextTick(cb); } stop (force, cb) { this.socket.close(); process.nextTick(cb); } } module.exports = function(port, host, opts) { if (gConn === null) { gConn = new Connector(port, host, opts); } return gConn; }; let genKey = function(peer) { return peer.address + ":" + peer.port; };