pomelo-upgrade
Version:
171 lines (157 loc) • 3.9 kB
JavaScript
'use strict';
const EventEmitter = require('events').EventEmitter;
const handler = require('./common/handler');
const protocol = require('pomelo-protocol');
const logger = require('pomelo-logger-upgrade').getLogger('pomelo', __filename);
const Package = protocol.Package;
const ST_INITED = 0;
const ST_WAIT_ACK = 1;
const ST_WORKING = 2;
const ST_CLOSED = 3;
/**
* Socket class that wraps socket and webSocket to provide unified interface for up level.
*/
class Socket extends EventEmitter
{
constructor(id, socket)
{
super();
this.id = id;
this.socket = socket;
if (!socket._socket)
{
this.remoteAddress = {
ip : socket.address().address,
port : socket.address().port
};
}
else
{
this.remoteAddress = {
ip : socket._socket.remoteAddress,
port : socket._socket.remotePort
};
}
socket.once('close', this.emit.bind(this, 'disconnect'));
socket.on('error', this.emit.bind(this, 'error'));
socket.on('message', (msg) =>
{
// 收到消息
if (msg)
{
msg = Package.decode(msg);
handler(this, msg);
}
});
this.state = ST_INITED;
// TODO: any other events?
}
/**
* Send raw byte data.
* @api private
*/
sendRaw(msg)
{
if (this.state !== ST_WORKING)
{
return;
}
const sendError = err =>{
if (err)
{
logger.error('websocket send binary data failed: %j', err.stack);
}
};
this.socket.send(msg, sendError.bind(this));
}
/**
* Send byte data package to client.
*
* @param {Buffer} msg byte data
*/
send(msg)
{
if (msg instanceof String)
{
msg = Buffer.from(msg);
}
else if (!(msg instanceof Buffer))
{
msg = Buffer.from(JSON.stringify(msg));
}
this.sendRaw(Package.encode(Package.TYPE_DATA, msg));
}
/**
* Send byte data packages to client in batch.
* @param {Buffer} msgs byte data
*/
sendBatch(msgs)
{
const rs = [];
for (let i = 0; i < msgs.length; i++)
{
const src = Package.encode(Package.TYPE_DATA, msgs[i]);
rs.push(src);
}
this.sendRaw(Buffer.concat(rs));
}
/**
* Send message to client no matter whether handshake.
* @api private
*/
sendForce(msg)
{
if (this.state === ST_CLOSED)
{
return;
}
const sendError = err =>{
if (err)
{
logger.error(`sendForce send message to client no matter whether handshake data failed: ${err.stack}`);
}
};
this.socket.send(msg, sendError.bind(this));
}
/**
* Response handshake request
*
* @api private
*/
handshakeResponse(resp)
{
if (this.state !== ST_INITED)
{
return;
}
const sendError = err =>{
if (err)
{
logger.error(`Response handshake request data failed: ${err.stack}`);
}
};
this.socket.send(resp, sendError.bind(this));
this.state = ST_WAIT_ACK;
}
/**
* Close the connection.
*
* @api private
*/
disconnect()
{
if (this.state === ST_CLOSED)
{
return;
}
this.state = ST_CLOSED;
this.socket.emit('close');
this.socket.close();
}
}
module.exports = function(id, socket)
{
if (!(this instanceof Socket))
return new Socket(id, socket);
return this;
};