pinusmod
Version:
[](https://travis-ci.org/node-pinus/pinus)
113 lines (92 loc) • 3.69 kB
text/typescript
import * as net from 'net';
import * as util from 'util';
import * as dgram from 'dgram';
import * as utils from '../util/utils';
import * as Constants from '../util/constants';
import {UdpSocket} from './udpsocket';
import * as Kick from './commands/kick';
import { HandshakeCommand, HandshakeCommandOptions } from './commands/handshake';
import { HeartbeatCommand, HeartbeatCommandOptions } from './commands/heartbeat';
import { Package, Message } from 'pinusmod-protocol';
import * as coder from './common/coder';
import { EventEmitter } from 'events';
import { getLogger } from 'pinusmod-logger';
import { SocketType } from 'dgram';
import { IConnector } from '../interfaces/IConnector';
import * as path from 'path';
let logger = getLogger('pinus', path.basename(__filename));
export interface UDPConnectorOptions extends HandshakeCommandOptions , HeartbeatCommandOptions {
udpType ?: 'udp4';
heartbeat ?: number;
timeout ?: number;
}
let curId = 1;
export class UDPConnector extends EventEmitter implements IConnector {
opts: any;
type: SocketType;
handshake: HandshakeCommand;
heartbeat: HeartbeatCommand;
clients: { [key: string]: any };
host: string;
port: number;
tcpServer: net.Server;
socket: dgram.Socket;
constructor(port: number, host: string, opts: UDPConnectorOptions) {
super();
this.opts = opts || {};
this.type = opts.udpType || 'udp4';
this.handshake = new HandshakeCommand(opts);
if (!opts.heartbeat) {
opts.heartbeat = Constants.TIME.DEFAULT_UDP_HEARTBEAT_TIME;
opts.timeout = Constants.TIME.DEFAULT_UDP_HEARTBEAT_TIMEOUT;
}
this.heartbeat = new HeartbeatCommand(utils.extendsObject(opts, { disconnectOnTimeout: true }));
this.clients = {};
this.host = host;
this.port = port;
}
start(cb: () => void) {
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: Buffer, peer: dgram.RemoteInfo) {
let socket = self.clients[genKey(peer)];
if (!!socket) {
socket.emit('package', data);
}
});
this.socket.on('error', function (err: Error) {
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);
}
decode = coder.decode;
encode = coder.encode;
stop(force: boolean, cb: () => void) {
this.socket.close();
process.nextTick(cb);
}
}
let genKey = function (peer: dgram.RemoteInfo) {
return peer.address + ':' + peer.port;
};