mocksserver-ws-plugin
Version:
A plugin for the Mocks-Server project that provides WebSocket integration. See https://www.mocks-server.org for more information.
181 lines (166 loc) • 5.57 kB
JavaScript
/**
* @module src/plugin
*/
const ws = require('ws');
const HandlerCollector = require('./collector');
/**
* This is the websocket plugin class.
* It must be registered as a plugin in the Mocks server configuration.
*
* @see {@link https://www.mocks-server.org/docs/plugins/installation/}
*/
class WebsocketPlugin {
/**
* The instance attribute.
*
* @type {?WebsocketPlugin}
* @private
*/
static _instance = null;
/**
* The plugin ID.
*
* @see {@link https://www.mocks-server.org/docs/plugins/development/#plugin-id}
* @type {string}
*/
static get id() {
return 'websocket';
}
/**
* The public plugin instance.
* This attribute allows the plugin to be accessed from any location in the running server, e.g. in the middleware.
*
* @type {?WebsocketPlugin}
*/
static get instance() {
return this._instance;
}
/**
* Creates a new plugin instance.
*
* @see {@link https://www.mocks-server.org/docs/plugins/development/#constructorcore}
* @param {Object} core - The Mocks Server core object.
*/
constructor(core) {
/**
* The handler registry option.
* The register handler classes specified in the mock server configuration are stored here.
* This is done in the plugin section of the configuration under the WebSocket command in the handler attribute.
* The handler key must be set to an object that contains a mapping from the relative path to the associated handler class.
*
* An example configuration looks like this:
*
* plugins: {
* websocket: {
* handler: {
* "/path": HandlerClass,
* ...
* }
* }
* }
*
* @type {Object}
* @private
*/
this._handlerOption = core.config.addOption({
name: 'handler',
type: 'object',
default: {}
});
/**
* The websocket server instance.
*
* @type {?ws.Server}
* @private
*/
this._wsServer = null;
/**
* The handler collector instance.
*
* @type {?HandlerCollector}
* @private
*/
this._handlerCollector = null;
// Assign the own object to the static instance attribute.
this.constructor._instance = this;
core.logger.info('Plugin Websockets created.');
}
/**
* The public handler collector instance.
*
* @type {?HandlerCollector}
*/
get handlerCollector() {
return this._handlerCollector;
}
/**
* Initializes the plugin.
* Creates a new websocket server instance and prepares the socket for receiving lifecycle events.
*
* @see {@link https://www.mocks-server.org/docs/plugins/development/#initcore}
* @param {Object} core - The Mocks Server core object.
* @
*/
init(core) {
this._wsServer = new ws.Server({noServer: true});
this._handlerCollector = new HandlerCollector(this._handlerOption.value);
this._wsServer.on('connection', (socket, request) => {
const handler = this._handlerCollector._createHandler(request.url, socket, core);
handler.onConnect(core);
socket.on('message', message => {
try {
if (typeof message !== 'string') {
message = message.toString();
}
try {
const obj = JSON.parse(message);
handler.onJsonMessage(obj, core);
return;
}
catch(e) {
if (e instanceof SyntaxError) {
handler.onMessage(message, core);
return;
}
throw e;
}
}
catch(e) {
core.logger.error(e);
}
});
socket.on('close', () => {
handler.onClose(core);
this._handlerCollector._deleteHandler(handler);
});
});
core.logger.info('Plugin Websockets initialized.');
}
/**
* Starts the plugin.
* Prepares the underlying server to upgrade an incoming connection to websocket protocol.
*
* @see {@link https://www.mocks-server.org/docs/plugins/development/#startcore}
* @param {Object} core - The Mocks Server core object.
*/
start(core) {
core.server._server.on('upgrade', (request, socket, head) => {
if (request.headers['upgrade'] === 'websocket') {
this._wsServer.handleUpgrade(request, socket, head, socket => {
this._wsServer.emit('connection', socket, request);
})
}
});
core.logger.info('Plugin Websockets started.');
}
/**
* Stops the plugin.
*
* @see {@link https://www.mocks-server.org/docs/plugins/development/#stopcore}
* @param {Object} core
*/
stop(core) {
core.logger.info('Plugin Websockets stopped.');
}
}
module.exports = WebsocketPlugin;