2021-02-03 19:55:41 +02:00
|
|
|
const EventEmitter = require('events');
|
|
|
|
|
2021-01-29 02:40:52 +02:00
|
|
|
const constants = require("./constants");
|
2021-02-02 10:17:49 +02:00
|
|
|
const parser = require('./Parser');
|
2021-03-25 20:24:43 +02:00
|
|
|
const { createLog } = require('./logger');
|
|
|
|
|
|
|
|
const socketLog = createLog([ 'Wormhole', 'Socket' ]);
|
2021-01-29 02:40:52 +02:00
|
|
|
|
2021-02-03 19:55:41 +02:00
|
|
|
class Socket extends EventEmitter {
|
2021-01-26 12:04:53 +02:00
|
|
|
constructor({ initialState='CONNECTING', socket }) {
|
2021-02-03 19:55:41 +02:00
|
|
|
super();
|
|
|
|
|
2021-01-26 12:04:53 +02:00
|
|
|
this._state = initialState;
|
|
|
|
this._socket = socket;
|
2021-01-29 02:40:52 +02:00
|
|
|
this._accepted = false;
|
|
|
|
this._fateDecided = false; // Wether the decision to accept or reject the socket was made
|
2021-01-26 12:04:53 +02:00
|
|
|
|
|
|
|
this._socket.on('data', (e) => {
|
2021-03-25 20:24:43 +02:00
|
|
|
if (!this._isConnected()) return socketLog('ERROR: Received data, but connection is not fully completed');
|
2021-02-04 16:01:14 +02:00
|
|
|
|
2021-03-25 20:24:43 +02:00
|
|
|
let packet;
|
|
|
|
try {
|
|
|
|
packet = this._decodePayload(e.buffer);
|
|
|
|
} catch(e) {
|
|
|
|
return socketLog('ERROR: Received data, but encountered error while parsing: ', e);
|
2021-02-04 16:01:14 +02:00
|
|
|
}
|
|
|
|
|
2021-03-25 20:24:43 +02:00
|
|
|
if (!packet.FIN) return socketLog('WARN: Message fragmentation is not supported, but got fragmented message');
|
2021-02-04 16:01:14 +02:00
|
|
|
|
2021-02-03 19:55:41 +02:00
|
|
|
if (packet.Opcode === constants.opcodes.TEXT_FRAME) {
|
|
|
|
this.emit('text', packet);
|
|
|
|
} else if (packet.Opcode === constants.opcodes.BINARY_FRAME) {
|
|
|
|
this.emit('binary', packet);
|
2021-03-25 20:24:43 +02:00
|
|
|
} else {
|
|
|
|
return socketLog(`WARN: Received unsupported opcode 0x${packet.Opcode.toString(16)}`);
|
2021-02-03 19:55:41 +02:00
|
|
|
}
|
2021-01-26 12:04:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 19:55:41 +02:00
|
|
|
Socket.prototype.send = function(payload) {
|
|
|
|
if (typeof payload === 'string') {
|
|
|
|
this._sendBuffer(Buffer.from(payload));
|
|
|
|
} else if (payload instanceof Buffer) {
|
|
|
|
this._sendBuffer(payload);
|
|
|
|
} else {
|
2021-03-25 20:24:43 +02:00
|
|
|
throw new Error(`Unsupported payload type ${typeof payload}, supported types are: string, Buffer`);
|
2021-02-03 19:55:41 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Socket.prototype._sendBuffer = function(buffer) {
|
2021-02-03 02:18:28 +02:00
|
|
|
const frame = new parser.WebsocketFrame();
|
|
|
|
frame.FIN = 1;
|
|
|
|
frame.RSVx = 0;
|
|
|
|
frame.Opcode = 0x01;
|
|
|
|
|
|
|
|
frame.MASK = 0;
|
2021-02-03 19:55:41 +02:00
|
|
|
const length = buffer.byteLength;
|
2021-02-03 02:18:28 +02:00
|
|
|
if (length > 125) {
|
|
|
|
frame.PayloadLen = 126;
|
2021-03-25 20:24:43 +02:00
|
|
|
if (length >= 65535) frame.PayloadLen = 127;
|
2021-02-03 02:18:28 +02:00
|
|
|
} else if (length <= 125) {
|
|
|
|
frame.PayloadLen = length;
|
|
|
|
}
|
|
|
|
frame.PayloadLenEx = length;
|
2021-02-03 19:55:41 +02:00
|
|
|
frame.PayloadData = buffer;
|
2021-02-03 02:18:28 +02:00
|
|
|
|
|
|
|
this._socket.write(frame.toBuffer());
|
|
|
|
};
|
|
|
|
|
2021-02-02 10:17:49 +02:00
|
|
|
Socket.prototype._decodePayload = function(payload) {
|
2021-02-03 19:55:41 +02:00
|
|
|
return parser.parseWebsocketFrame(new DataView(payload));
|
2021-02-02 10:17:49 +02:00
|
|
|
};
|
|
|
|
|
2021-01-29 02:40:52 +02:00
|
|
|
Socket.prototype._setConnectionState = function(state) {
|
|
|
|
this._state = state;
|
|
|
|
};
|
|
|
|
|
|
|
|
Socket.prototype._setAccepted = function(state) {
|
|
|
|
if (this._fateDecided) throw new Error('Tried to decide fate (wether socket is accepted or not) more than 1 time');
|
|
|
|
|
|
|
|
this._fateDecided = true;
|
|
|
|
this._accepted = state;
|
|
|
|
};
|
|
|
|
|
2021-02-03 19:55:41 +02:00
|
|
|
Socket.prototype._isConnected = function() {
|
2021-03-25 20:24:43 +02:00
|
|
|
return (this._fateDecided && this._isConnected && this._accepted);
|
2021-02-03 19:55:41 +02:00
|
|
|
}
|
|
|
|
|
2021-01-26 12:04:53 +02:00
|
|
|
module.exports = Socket;
|