sgapps-server
Version:
SGApps Network Server
494 lines (429 loc) • 24.7 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8">
<title>prototypes/dictionary.js - SGApps Server - Framework</title>
<meta name="description" content="SGApps Server for high performance results" />
<meta name="keywords" content="javascript, js, application-prototype, prototype" />
<meta name="keyword" content="javascript, js, application-prototype, prototype" />
<meta property="og:title" content="SGApps Server - Framework"/>
<meta property="og:type" content="website"/>
<meta property="og:image" content=""/>
<meta property="og:url" content="https://labs.sgapps.io/open-source/sgapps-server"/>
<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
<script src="scripts/nav.js" defer></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
<div class="navicon"></div>
</label>
<label for="nav-trigger" class="overlay"></label>
<nav class="wrap">
<input type="text" id="nav-search" placeholder="Search" />
<h2><a href="index.html">Home</a></h2><h2><a href="https://labs.sgapps.io/open-source/sgapps-server" target="_blank" class="menu-item" id="website_link" >Project Page ( Git Lab )</a></h2><h2><a href="http://gordienco.net/" target="_blank" class="menu-item" id="website_link" >About Me</a></h2><h2><a href="https://labs.sgapps.io/open-source/sgapps-server" target="_blank" class="menu-item" id="github_link" >GitHub</a></h2><h3>Classes</h3><ul><li><a href="AccessLogger.html">AccessLogger</a><ul class='methods'><li data-type='method' style='display: none;'><a href="AccessLogger.html#formattedDate">formattedDate</a></li><li data-type='method' style='display: none;'><a href="AccessLogger.html#getProtocol">getProtocol</a></li><li data-type='method' style='display: none;'><a href="AccessLogger.html#getReferer">getReferer</a></li><li data-type='method' style='display: none;'><a href="AccessLogger.html#getRemoteIp">getRemoteIp</a></li><li data-type='method' style='display: none;'><a href="AccessLogger.html#getSize">getSize</a></li><li data-type='method' style='display: none;'><a href="AccessLogger.html#getUsername">getUsername</a></li><li data-type='method' style='display: none;'><a href="AccessLogger.html#logRequest">logRequest</a></li></ul></li><li><a href="FaceboxTemplate.html">FaceboxTemplate</a><ul class='methods'><li data-type='method' style='display: none;'><a href="FaceboxTemplate.html#render">render</a></li><li data-type='method' style='display: none;'><a href="FaceboxTemplate.html#renderCode">renderCode</a></li><li data-type='method' style='display: none;'><a href="FaceboxTemplate.html#renderFile">renderFile</a></li></ul></li><li><a href="FSLibrary.html">FSLibrary</a></li><li><a href="LoggerBuilder.html">LoggerBuilder</a><ul class='methods'><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#decorateGlobalLogger">decorateGlobalLogger</a></li><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#error">error</a></li><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#info">info</a></li><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#log">log</a></li><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#prettyCli">prettyCli</a></li><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#prompt">prompt</a></li><li data-type='method' style='display: none;'><a href="LoggerBuilder.html#warn">warn</a></li></ul></li><li><a href="SGAppsServer.html">SGAppsServer</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServer.html#all">all</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#connect">connect</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#delete">delete</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#Email">Email</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#finalHandler">finalHandler</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#get">get</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#handle">handle</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#handleErrorRequest">handleErrorRequest</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#handlePostData">handlePostData</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#handleRequest">handleRequest</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#handleStaticRequest">handleStaticRequest</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#head">head</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#options">options</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#patch">patch</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#post">post</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#put">put</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#server">server</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#trace">trace</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.html#use">use</a></li></ul></li><li><a href="SGAppsServer.NodeJsMvc.html">NodeJsMvc</a></li><li class="level-hide"><a href="SGAppsServer.NodeJsMvc.Controller.html">Controller</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#actionExists">actionExists</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#addAction">addAction</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#addView">addView</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#getAction">getAction</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#getView">getView</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#removeAction">removeAction</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#removeView">removeView</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#render">render</a></li><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.html#viewExists">viewExists</a></li></ul></li><li class="level-hide"><a href="SGAppsServer.NodeJsMvc.Controller.Action.html">Action</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServer.NodeJsMvc.Controller.Action.html#run">run</a></li></ul></li><li><a href="SGAppsServerDecoratorsLibrary.html">SGAppsServerDecoratorsLibrary</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerDecoratorsLibrary.html#.AccessLoggerDecorator">AccessLoggerDecorator</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerDecoratorsLibrary.html#.NodeJsMvcDecorator">NodeJsMvcDecorator</a></li></ul></li><li><a href="SGAppsServerDictionary.html">SGAppsServerDictionary</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerDictionary.html#generatePathKey">generatePathKey</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerDictionary.html#push">push</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerDictionary.html#run">run</a></li></ul></li><li><a href="SGAppsServerEmail.html">SGAppsServerEmail</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerEmail.html#.from">from</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerEmail.html#.isValidAddress">isValidAddress</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerEmail.html#.timeout">timeout</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerEmail.html#send">send</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerEmail.html#valid">valid</a></li></ul></li><li><a href="SGAppsServerRequest.html">SGAppsServerRequest</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerRequest.html#_parseDeepFieldName">_parseDeepFieldName</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerRequest.html#getMountUpdatedUrl">getMountUpdatedUrl</a></li></ul></li><li><a href="SGAppsServerRequestCookie.html">SGAppsServerRequestCookie</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerRequestCookie.html#get">get</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerRequestCookie.html#set">set</a></li></ul></li><li><a href="SGAppsServerRequestSession.html">SGAppsServerRequestSession</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerRequestSession.html#destroy">destroy</a></li></ul></li><li><a href="SGAppsServerResponse.html">SGAppsServerResponse</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsServerResponse.html#pipeFile">pipeFile</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerResponse.html#pipeFileStatic">pipeFileStatic</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerResponse.html#redirect">redirect</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerResponse.html#send">send</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerResponse.html#sendError">sendError</a></li><li data-type='method' style='display: none;'><a href="SGAppsServerResponse.html#sendStatusCode">sendStatusCode</a></li></ul></li><li><a href="SGAppsServerShared.html">SGAppsServerShared</a></li><li><a href="SGAppsSessionManager.html">SGAppsSessionManager</a><ul class='methods'><li data-type='method' style='display: none;'><a href="SGAppsSessionManager.html#handleRequest">handleRequest</a></li><li data-type='method' style='display: none;'><a href="SGAppsSessionManager.html#removeExpiredSessions">removeExpiredSessions</a></li></ul></li><li><a href="TemplateManager.html">TemplateManager</a><ul class='methods'><li data-type='method' style='display: none;'><a href="TemplateManager.html#add">add</a></li><li data-type='method' style='display: none;'><a href="TemplateManager.html#addList">addList</a></li><li data-type='method' style='display: none;'><a href="TemplateManager.html#get">get</a></li><li data-type='method' style='display: none;'><a href="TemplateManager.html#remove">remove</a></li><li data-type='method' style='display: none;'><a href="TemplateManager.html#render">render</a></li><li data-type='method' style='display: none;'><a href="TemplateManager.html#templateExists">templateExists</a></li></ul></li><li><a href="TemplateManagerViewer.html">TemplateManagerViewer</a><ul class='methods'><li data-type='method' style='display: none;'><a href="TemplateManagerViewer.html#render">render</a></li><li data-type='method' style='display: none;'><a href="TemplateManagerViewer.html#renderCode">renderCode</a></li></ul></li></ul><h3>Global</h3><ul><li><a href="global.html#LoggerBuilderPrompt">LoggerBuilderPrompt</a></li><li><a href="global.html#MountUpdatedURL">MountUpdatedURL</a></li><li><a href="global.html#RequestHandler">RequestHandler</a></li><li><a href="global.html#RequestPathStructure">RequestPathStructure</a></li><li><a href="global.html#RequestPathStructureMap">RequestPathStructureMap</a></li><li><a href="global.html#RequestSessionDecorator">RequestSessionDecorator</a></li><li><a href="global.html#ResourcesExtensions">ResourcesExtensions</a></li><li><a href="global.html#routeMatch">routeMatch</a></li><li><a href="global.html#SGAppsServerDecorator">SGAppsServerDecorator</a></li><li><a href="global.html#SGAppsServerDictionaryRunCallBack">SGAppsServerDictionaryRunCallBack</a></li><li><a href="global.html#SGAppsServerErrorCallBack">SGAppsServerErrorCallBack</a></li><li><a href="global.html#SGAppsServerErrorOnlyCallback">SGAppsServerErrorOnlyCallback</a></li><li><a href="global.html#SGAppsServerHandlerPostData">SGAppsServerHandlerPostData</a></li><li><a href="global.html#SGAppsServerOptions">SGAppsServerOptions</a></li><li><a href="global.html#SGAppsServerRequestFile">SGAppsServerRequestFile</a></li><li><a href="global.html#SGAppsServerRequestPostDataItem">SGAppsServerRequestPostDataItem</a></li><li><a href="global.html#SGAppsServerRequestSessionCache">SGAppsServerRequestSessionCache</a></li><li><a href="global.html#SGAppsSessionManagerOptions">SGAppsSessionManagerOptions</a></li><li><a href="global.html#TemplateManagerRenderOptions">TemplateManagerRenderOptions</a></li><li><a href="global.html#TemplateManagerTemplate">TemplateManagerTemplate</a></li></ul>
</nav>
<div id="main">
<h1 class="page-title">prototypes/dictionary.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>const parseParams = require('application-prototype/constructors/request/params-parser');
/**
*
* @param {RequestPathStructure} route
* @param {string} url
* @param {boolean} strictRouting
* @param {object} _cache
*/
function routeMatch(route, url, strictRouting, _cache) {
if (
route === '*'
||
route === '/*'
||
route === '^/*'
||
(
!strictRouting
&& (
route === '/'
)
)
) return true;
if (typeof (route) === "string") {
// if (
// route[1] !== url[1]
// ) return false;
if (
url === route
) {
return true;
} else if (
url.indexOf(route) === 0 && !strictRouting
) {
return true;
} else if (
strictRouting
&& url.indexOf(route) === 0
&& (
(
// /path/route/ --- /path/route/
url.length === route.length
) || (
// /path/route? --- /path/route
url[route.length - 1] === '?'
)
)
) {
return true;
} else if (
!strictRouting
&&
//@ts-ignore
url.indexOf(route.subs(0, -1)) === 0
&&
(
url.length === route.length - 1
||
(
(
url[route.length - 1] === '?'
|| url[route.length - 1] === '/'
) && route[route.length - 1] === '/'
)
)
) {
const params = parseParams(url, route, { cache: _cache || {} });
if (
params !== null
) {
return params || true;
}
} else {
return false;
}
} else if (route && route instanceof RegExp) {
const result = route.exec(url);
if (result) {
const { groups } = result;
return groups || true;
} else {
return false;
}
}
return false;
}
/**
* @typedef {object} RequestPathStructureMap
* @property {string} key
* @property {RequestPathStructure} path
* @property {Array<RequestHandler>} handlers
*/
/**
* @class
* @name SGAppsServerDictionary
* @description a dictionary for storing
* @param {object} [options]
* @param {string} [options.name=""]
* @param {boolean} [options.reverse=false]
*/
function SGAppsServerDictionary(options) {
/**
* @memberof SGAppsServerDictionary#
* @name _paths
* @type {Array<RequestPathStructureMap>}
*/
this._paths = [];
/**
* @memberof SGAppsServerDictionary#
* @name _dictionary
* @type {Object<string,Array<RequestHandler>>}
*/
this._dictionary = {};
this._cache = {};
this._options = Object.assign(
{
reverse: false,
name: ""
},
options || {}
);
/**
* @memberof SGAppsServerDictionary#
* @method generatePathKey
* @param {RequestPathStructure} path
* @returns {string}
*/
this.generatePathKey = function (path) {
if (typeof(path) === "string") {
return `s:${path}`;
} else if (path instanceof RegExp) {
return `r:${path.toString()}`;
} else {
return `*:${path}`;
}
};
return this;
}
/**
* @example
* server.get('/', (req, res) => {
* res.send('root');
* })
* // will match "test" "best", everything with est
* server.get(/.*est/, (req, res) => {
* res.send('root');
* })
* server.get('/:name/:surname', (req, res) => {
* const { name, surname } = req.params;
* res.send(`Hi ${name} ${surname}`);
* })
* // apply rules with regexp emulation, they are marked with "^" in the start
* server.get('^/:name([a-z]+)/:age(\d+)', (req, res, next) => {
* const { name, age } = req.params;
* if (age < 18) {
* res.send(`Hi ${name}, you are not allowed`);
* } else {
* next()
* }
* })
* // apply rules with regexp emulation, they are marked with "^" in the start
* server.get('^/([a-z]+)/', (req, res, next) => {
* const { name, age } = req.params;
* if (age < 18) {
* res.send(`Hi ${name}, you are not allowed`);
* } else {
* next()
* }
* })
* // add regular expression with group names
* server.get('^/(?<test>[a-z]+)/', (req, res, next) => {
* const { test } = req.params;
* res.send(`param: ${test}`);
* })
* server.get('/', (req, res) => {
* res.send('root');
* })
*
* @memberof SGAppsServerDictionary#
* @method push
* @param {RequestPathStructure} path
* @param {RequestHandler[]} handlers
*/
SGAppsServerDictionary.prototype.push = function (path, handlers) {
if (path === '') path = '*';
const pathKey = this.generatePathKey(path);
if (typeof(path) === "string" && path[0] === "^") {
// (?<name>...)
const rule = path
.replace(/([^\w\*\$\{\}\|\+\?\#\!<\>\\\(\)\[\]\-\=\,\.\~\:\;\&\^])/g,'\\$1')
.replace(/\/\*$/, '\/.*')
.replace(/\:([a-zA-Z][a-zA-Z\d]*)\((.*?)\)/g, '(?<$1>$2)')
.replace(/\:([a-zA-Z][a-zA-Z\d]*)/g, '(?<$1>[^\/\:]+)') + '$';
//@ts-ignore
const regRule = rule.toRegexp();
if (regRule && (regRule instanceof RegExp)) {
path = regRule;
}
}
if (this._options.reverse) {
this._paths.unshift({
key: pathKey,
path,
// : handlers.map(v => v).reverse()
handlers
});
} else {
this._paths.push({
key: pathKey,
path,
handlers
});
}
};
/**
* @callback SGAppsServerDictionaryRunCallBack
* @param {SGAppsServerRequest} request
* @param {SGAppsServerResponse} response
* @param {SGAppsServer} server
*/
/**
* @memberof SGAppsServerDictionary#
* @method run
* @param {SGAppsServerRequest} request
* @param {SGAppsServerResponse} response
* @param {SGAppsServer} server
* @param {SGAppsServerDictionaryRunCallBack} callback
*/
SGAppsServerDictionary.prototype.run = function (request, response, server, callback) {
let index = 0;
const {
strictRouting
} = server._options;
// const url = request.request.url;
const url = request.urlInfo.pathname.replace(/^\/+/, '/');
const _cache = this._cache;
const _debug = server.logger._debug;
let _errorDetected = null;
let next = () => {
if (_errorDetected) {
server.handleErrorRequest(
request,
response,
_errorDetected
);
} else if (!this._paths[index]) {
callback(request, response, server);
} else {
const matchResult = routeMatch(
this._paths[index].path,
url,
strictRouting,
_cache
);
// TODO apply cache
// IF response is 200 && matched by a string path
// TODO add cache pathname|pathkey
// TODO add cache pathname|handlers
// console.info(
// {
// matchResult,
// url,
// path: this._paths[index].path,
// strictRouting
// }
// );
if (typeof(matchResult) === "object" && matchResult) {
request.params = Object.assign(
request.urlInfo.pathname.split('/'),
matchResult
);
}
if (
!!matchResult
) {
let itemIndex = 0;
let itemNext = () => {
if (_errorDetected) {
next();
} else if (itemIndex >= this._paths[index].handlers.length) {
index++;
next();
} else {
let err, timer = null;
let _startTime = _debug ? ( new Date().valueOf() ) : null;
let _endTime = null;
const path = this._paths[index].path;
if (_debug) {
timer = setTimeout(() => {
if (request._flags.aborted || response._flags.finished || _endTime !== null) return;
const endTime = _endTime || new Date().valueOf();
if (
typeof(request._flags._DEBUG_MAX_HANDLER_EXECUTION_TIME) === "number"
&&
request._flags._DEBUG_MAX_HANDLER_EXECUTION_TIME >= 1
) {
var remain = request._flags._DEBUG_MAX_HANDLER_EXECUTION_TIME - ( endTime - _startTime );
if (remain > 0) {
timer = setTimeout(() => {
if (request._flags.aborted || response._flags.finished || _endTime !== null) return;
const endTime = _endTime || new Date().valueOf();
server.logger.warn(
`[SGAppsServer.Handler] Max Execution time exceeded ( ${
request._flags._DEBUG_MAX_HANDLER_EXECUTION_TIME
} ms ) ; time spend ${_endTime === null ? 'more than' : ''} ${ endTime - _startTime } ms`
);
server.logger.warn(this._paths[index].path);
server.logger.warn(this._paths[index].handlers[itemIndex].toString());
}, remain);
} else {
server.logger.warn(
`[SGAppsServer.Handler] Max Execution time exceeded ( ${
server._options._DEBUG_MAX_HANDLER_EXECUTION_TIME
} ms ) ; time spend ${_endTime === null ? 'more than' : ''} ${ endTime - _startTime } ms`
);
server.logger.warn(this._paths[index].path);
server.logger.warn(this._paths[index].handlers[itemIndex].toString());
}
} else {
server.logger.warn(
`[SGAppsServer.Handler] Max Execution time exceeded ( ${
server._options._DEBUG_MAX_HANDLER_EXECUTION_TIME
} ms ) ; time spend ${_endTime === null ? 'more than' : ''} ${ endTime - _startTime } ms`
);
server.logger.warn(this._paths[index].path);
server.logger.warn(this._paths[index].handlers[itemIndex].toString());
}
}, server._options._DEBUG_MAX_HANDLER_EXECUTION_TIME);
}
try {
this._paths[index].handlers[itemIndex]
.apply(
server,
[
request,
response,
function () {
if (_debug && timer !== null) {
_endTime = new Date().valueOf();
if (server._options._DEBUG_REQUEST_HANDLERS_STATS) {
server.logger.info(
`[STATS] ${request.request.method} ${path} : `, {
time: _endTime - _startTime,
bytesRead: (request.request.socket || {}).bytesRead || 0,
bytesWritten: (request.request.socket || {}).bytesWritten || 0,
url: request.request.url
}
);
}
clearTimeout(timer);
timer = null;
}
itemIndex++;
itemNext();
}
]
);
} catch (err) {
_errorDetected = err;
// TODO Server Error page handler
server.logger.error(err);
if (_debug) {
_endTime = new Date().valueOf();
}
itemNext();
}
}
};
itemNext();
} else {
index++;
next();
}
}
};
next();
};
module.exports = SGAppsServerDictionary;</code></pre>
</article>
</section>
</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.5</a> using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
</footer>
<script>prettyPrint();</script>
<script src="scripts/polyfill.js"></script>
<script src="scripts/linenumber.js"></script>
<script src="scripts/search.js" defer></script>
<script src="scripts/collapse.js" defer></script>
<script src="https://sgapps.io/components/sgapps-labs-examples/toolbar/loader.js"></script>
</body>
</html>