Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
26 changes: 8 additions & 18 deletions lib/Helpers/HelperRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
};
}
}
}
Expand Down
57 changes: 31 additions & 26 deletions lib/Server/WSServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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.
*
Expand All @@ -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.
*
Expand Down
26 changes: 18 additions & 8 deletions lib/Server/helpers/HTTPCookieProcessorHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,66 @@
// 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.
*
* @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 = () => {
Expand Down
17 changes: 9 additions & 8 deletions lib/Server/helpers/WSServerHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}
Expand All @@ -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];
}
Expand All @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions lib/Server/processors/HTTP/HTTPCookieProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 4 additions & 8 deletions lib/Server/processors/HTTP/HTTPRequestProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
}

Expand Down
8 changes: 4 additions & 4 deletions lib/Types/Cookie.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Cookie {
}

/**
* @type {string} A string representing the cookie name.
* @type {string} _name A string representing the cookie name.
*
* @protected
*/
Expand All @@ -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
*/
Expand Down Expand Up @@ -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;
}
Expand Down