diff --git a/CHANGELOG.md b/CHANGELOG.md index 3486c65..6f2a185 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. +## [0.1.4] + +### Changed +- Changed the helper functions parameter binding mechanism with consequential overall performance boost. + ## [0.1.3] ### Added diff --git a/lib/Helpers/HelperRepository.js b/lib/Helpers/HelperRepository.js index d6aecfa..61e6dde 100644 --- a/lib/Helpers/HelperRepository.js +++ b/lib/Helpers/HelperRepository.js @@ -6,13 +6,6 @@ const { InvalidArgumentException } = require('../Exceptions'); -/** - * @typedef {Object} HelperInjectionOptions An object representing all the options accepted by the "inject" method of the "HelperRepository" class. - * - * @property {?*[]} bind An optional array of variable to bind to the helper function that will be injected. - * @property {?Object.<*, *>} context An optional object containing some parameters that will be available as the first parameter in the helper function. - */ - /** * Allows to store and inject helper functions. */ @@ -102,31 +95,28 @@ class HelperRepository extends BaseRepository { * * @param {Object} obj An object the helper functions found will be injected in. * @param {?string} [namespace] A string containing the namespace the functions. - * @param {?HelperInjectionOptions} [options] An object containing some additional options this method should take care of. + * @param {?Object} [context] An object containing some additional parameters to pass to the helper function whenever invoked. * * @throws {InvalidArgumentException} If an invalid object is given. * @throws {InvalidArgumentException} If an invalid namespace is given. + * @throws {InvalidArgumentException} If an invalid context object is given. */ - static inject(obj, namespace = null, options = null){ + static inject(obj, namespace = null, context = null){ if ( obj === null || typeof obj !== 'object' ){ throw new InvalidArgumentException('Invalid object.', 1); } - if ( options !== null && typeof options !== 'object' ){ - throw new InvalidArgumentException('Invalid options.', 3); + if ( context === null || typeof context !== 'object' ){ + throw new InvalidArgumentException('Invalid context.', 3); } namespace = namespace === null || namespace === '' ? 'com.lala.helpers:*' : ( 'com.lala.helpers:' + namespace ); // Get all the helpers registered under the given namespace. const helpers = super.getAll(namespace); - const bind = options !== null && Array.isArray(options.bind) ? options.bind : [this]; - if ( options !== null && options.context !== null && typeof options.context === 'object' ){ - // Context variables have been defined, add them as the first argument of the helper function. - bind.splice(1, 0, options.context); - } // Inject helper functions. - // OPTIMIZE: Binding is slow, find a better alternative. for ( const name in helpers ){ if ( helpers.hasOwnProperty(name) ){ - obj[name] = helpers[name].bind(...bind); + obj[name] = function(...rest){ + return helpers[name](context, ...rest); + }; } } } diff --git a/lib/Server/WSServer.js b/lib/Server/WSServer.js index c99aaa8..39a9785 100644 --- a/lib/Server/WSServer.js +++ b/lib/Server/WSServer.js @@ -207,10 +207,8 @@ class WSServer extends HTTPServer { connection.rawSend = connection.send.bind(connection); // Add helper function used to handle this connection. HelperRepository.inject(connection, 'com.lala.server.WSServer.connection', { - bind: [this], - context: { - connection: connection - } + server: this, + connection: connection }); this.emit('WSConnection', connection); } @@ -262,28 +260,6 @@ class WSServer extends HTTPServer { await processor.process(exception, message, connection); } - /** - * Sends all the messages that have been queued. - * - * @param {WebSocket} connection An instance of the class "WebSocket" provided by the "ws" module and representing the client connection. - * - * @protected - */ - _sendQueuedMessages(connection){ - if ( connection.hasOwnProperty('indexedProperties') && !isEmptyObject(connection.indexedProperties) ){ - // If at least one indexed property is found, send all the messages that has been queue according to these properties. - this._messageQueue.send(connection, connection.indexedProperties).then(() => { - this.emit('messageQueuePushed', connection); - }); - } - if ( connection.hasOwnProperty('properties') && !isEmptyObject(connection.properties) ){ - // If at least one standard property has been defined, then send all the messages that have been queued for these properties. - this._messageQueue.send(connection, connection.properties).then(() => { - this.emit('messageQueuePushed', connection); - }); - } - } - /** * Handles client messages. * @@ -621,6 +597,15 @@ class WSServer extends HTTPServer { return this._messageQueue; } + /** + * Returns the object that stores the connections to this server. + * + * @returns {ConnectionsIndex} An instance of the "ConnectionsIndex" class representing the storage class being used. + */ + getWSConnectionIndex(){ + return this._WSConnectionsIndex; + } + /** * Returns the classes used in processor validation. * @@ -637,6 +622,26 @@ class WSServer extends HTTPServer { }); } + /** + * Sends all the messages that have been queued. + * + * @param {WebSocket} connection An instance of the class "WebSocket" provided by the "ws" module and representing the client connection. + */ + sendQueuedMessages(connection){ + if ( connection.hasOwnProperty('indexedProperties') && !isEmptyObject(connection.indexedProperties) ){ + // If at least one indexed property is found, send all the messages that has been queue according to these properties. + this._messageQueue.send(connection, connection.indexedProperties).then(() => { + this.emit('messageQueuePushed', connection); + }); + } + if ( connection.hasOwnProperty('properties') && !isEmptyObject(connection.properties) ){ + // If at least one standard property has been defined, then send all the messages that have been queued for these properties. + this._messageQueue.send(connection, connection.properties).then(() => { + this.emit('messageQueuePushed', connection); + }); + } + } + /** * Sends a direct message to a given client. * diff --git a/lib/Server/helpers/HTTPCookieProcessorHelpers.js b/lib/Server/helpers/HTTPCookieProcessorHelpers.js index 3ceb8d0..2495087 100644 --- a/lib/Server/helpers/HTTPCookieProcessorHelpers.js +++ b/lib/Server/helpers/HTTPCookieProcessorHelpers.js @@ -3,9 +3,16 @@ // Including Lala's modules. const HelperRepository = require('../../Helpers/HelperRepository'); +/** + * @typedef {Object} HTTPCookieProcessorHelpersContext An object containing the context variables required by helper functions. + * + * @property {HTTPCookieProcessor} processor The reference to the processor instance where the helper has been injected from. + */ + /** * Sets a cookie on the client side. * + * @param {HTTPCookieProcessorHelpersContext} context An object containing all the variables needed by this function to work within the invoking context. * @param {string} name A string containing the cookie unique name. * @param {string} value A string containing some data to store in the cookie. * @param {?CookieOptions} [options] An object containing some additional attributes this cookie should take care of. @@ -13,46 +20,49 @@ const HelperRepository = require('../../Helpers/HelperRepository'); * @throws {InvalidArgumentException} If an invalid cookie name is given. * @throws {InvalidArgumentException} If a non-string value is given as cookie value. */ -function setCookie(name, value, options = null){ - this.setCookie(name, value, options); +function setCookie(context, name, value, options = null){ + context.processor.setCookie(name, value, options); } /** * Removes a given cookie. * + * @param {HTTPCookieProcessorHelpersContext} context An object containing all the variables needed by this function to work within the invoking context. * @param {string} name A string containing the cookie unique name. * @param {?CookieOptions} [options] An object containing some additional attributes this cookie should take care of, note that expiration day is ignored here. * * @throws {InvalidArgumentException} If an invalid cookie name is given. */ -function removeCookie(name, options = null){ - this.removeCookie(name, options); +function removeCookie(context, name, options = null){ + context.processor.removeCookie(name, options); } /** * Returns a cookie matching the given name. * + * @param {HTTPCookieProcessorHelpersContext} context An object containing all the variables needed by this function to work within the invoking context. * @param {string} name A string containing the name of the cookie to return. * * @returns {?Cookie} An instance of the class "Cookie" representing the cookie found or null if no cookie matching this name is found. * * @throws {InvalidArgumentException} If an invalid cookie name is given. */ -function getCookie(name){ - return this.getCookie(name); +function getCookie(context, name){ + return context.processor.getCookie(name); } /** * Returns the value of a cookie matching the given name. * + * @param {HTTPCookieProcessorHelpersContext} context An object containing all the variables needed by this function to work within the invoking context. * @param {string} name A string containing the name of the cookie to return. * * @returns {?string} A string containing the cookie value or null if no cookie matching this name has been found. * * @throws {InvalidArgumentException} If an invalid cookie name is given. */ -function getCookieValue(name){ - return this.getCookieValue(name); +function getCookieValue(context, name){ + return context.processor.getCookieValue(name); } module.exports.registerHelpers = () => { diff --git a/lib/Server/helpers/WSServerHelpers.js b/lib/Server/helpers/WSServerHelpers.js index 8170a6e..d763eec 100644 --- a/lib/Server/helpers/WSServerHelpers.js +++ b/lib/Server/helpers/WSServerHelpers.js @@ -9,6 +9,7 @@ const { /** * @typedef {Object} WSServerHelperConnectionContext An object containing the context variables required by helper functions. * + * @property {WSServer} server The reference to the WebSocket server instance where the helper has been injected from. * @property {WebSocket} connection An instance of the class "WebSocket" representing a WebSocket client connected to the server. */ @@ -27,7 +28,7 @@ function addTag(context, tag){ throw new InvalidArgumentException('Invalid tag.', 1); } context.connection.indexedProperties.tags.add(tag); - this._WSConnectionsIndex.index(context.connection, null, 'indexedProperties'); + context.server.getWSConnectionIndex().index(context.connection, null, 'indexedProperties'); return context.connection; } @@ -51,7 +52,7 @@ function addTags(context, tags){ context.connection.indexedProperties.tags.add(tags[i]); } } - this._WSConnectionsIndex.index(context.connection, null, 'indexedProperties'); + context.server.getWSConnectionIndex().index(context.connection, null, 'indexedProperties'); return context.connection; } @@ -70,7 +71,7 @@ function removeTag(context, tag){ throw new InvalidArgumentException('Invalid tag.', 1); } context.connection.indexedProperties.tags.delete(tag); - this._WSConnectionsIndex.index(context.connection, null, 'indexedProperties'); + context.server.getWSConnectionIndex().index(context.connection, null, 'indexedProperties'); return context.connection; } @@ -92,7 +93,7 @@ function removeTags(context, tags){ for ( let i = 0 ; i < length ; i++ ){ context.connection.indexedProperties.tags.delete(tags[i]); } - this._WSConnectionsIndex.index(context.connection, null, 'indexedProperties'); + context.server.getWSConnectionIndex().index(context.connection, null, 'indexedProperties'); return context.connection; } @@ -118,9 +119,9 @@ function setAttribute(context, name, value, index = true){ } const stack = index === true ? context.connection.indexedProperties : context.connection.properties; stack[name] = value; - this._sendQueuedMessages(context.connection); + context.server.sendQueuedMessages(context.connection); if ( index === true ){ - this._WSConnectionsIndex.index(context.connection, null, 'indexedProperties'); + context.server.getWSConnectionIndex().index(context.connection, null, 'indexedProperties'); } return context.connection; } @@ -141,7 +142,7 @@ function removeAttribute(context, name){ } if ( context.connection.indexedProperties.hasOwnProperty(name) ){ delete context.connection.indexedProperties[name]; - this._WSConnectionsIndex.index(context.connection, null, 'indexedProperties'); + context.server.getWSConnectionIndex().index(context.connection, null, 'indexedProperties'); }else if ( context.connection.properties.hasOwnProperty(name) ){ delete context.connection.properties[name]; } @@ -160,7 +161,7 @@ function removeAttribute(context, name){ * @async */ async function send(context, message, options = null){ - const processor = this._WSOutputProcessorFactory.craft(); + const processor = context.server.getWSOutputProcessorFactory().craft(); await processor.process(message, context.connection, options); } diff --git a/lib/Server/processors/HTTP/HTTPCookieProcessor.js b/lib/Server/processors/HTTP/HTTPCookieProcessor.js index 7ed1cd2..fce5f16 100644 --- a/lib/Server/processors/HTTP/HTTPCookieProcessor.js +++ b/lib/Server/processors/HTTP/HTTPCookieProcessor.js @@ -507,10 +507,10 @@ class HTTPCookieProcessor extends Processor { this.processLanguage(request); // Injects some helper functions useful when dealing with cookies. HelperRepository.inject(request, 'com.lala.server.processor.HTTPCookieProcessor.request', { - bind: [this] + processor: this }); HelperRepository.inject(response, 'com.lala.server.processor.HTTPCookieProcessor.response', { - bind: [this] + processor: this }); // Export this class instance in the request object. request.cookieProcessor = this; diff --git a/lib/Server/processors/HTTP/HTTPRequestProcessor.js b/lib/Server/processors/HTTP/HTTPRequestProcessor.js index f8e5950..270d21f 100644 --- a/lib/Server/processors/HTTP/HTTPRequestProcessor.js +++ b/lib/Server/processors/HTTP/HTTPRequestProcessor.js @@ -405,16 +405,12 @@ class HTTPRequestProcessor extends RequestProcessor { this._addAccept(request); // Add helper functions. HelperRepository.inject(request, 'com.lala.server.processor.HTTPRequestProcessor.request', { - context: { - request: request, - response: response - } + request: request, + response: response }); HelperRepository.inject(response, 'com.lala.server.processor.HTTPRequestProcessor.response', { - context: { - request: request, - response: response - } + request: request, + response: response }); } diff --git a/lib/Types/Cookie.js b/lib/Types/Cookie.js index 1ee562a..5f04057 100644 --- a/lib/Types/Cookie.js +++ b/lib/Types/Cookie.js @@ -68,7 +68,7 @@ class Cookie { } /** - * @type {string} A string representing the cookie name. + * @type {string} _name A string representing the cookie name. * * @protected */ @@ -82,7 +82,7 @@ class Cookie { this._value = typeof value === 'string' ? value : ''; /** - * @type {?Date} _expire A instance of teh class "Date" representing the date when this cookie will expire, if set to null, this cookie is meant to live forever. + * @type {?Date} [_expire] A instance of teh class "Date" representing the date when this cookie will expire, if set to null, this cookie is meant to live forever. * * @protected */ @@ -193,10 +193,10 @@ class Cookie { switch ( this._sameSite ){ case Cookie.sameSitePolicy.STRICT: { name = 'Strict'; - } + }break; case Cookie.sameSitePolicy.LAX: { name = 'Lax'; - } + }break; } return name; }