UNPKG

total.js

Version:

MVC framework for Node.js

1,691 lines (1,452 loc) 497 kB
// Copyright 2012-2021 (c) Peter Širka <petersirka@gmail.com> // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. /** * @module Framework * @version 3.4.13 */ 'use strict'; const Qs = require('querystring'); const Os = require('os'); const Fs = require('fs'); const Zlib = require('zlib'); const Path = require('path'); const Crypto = require('crypto'); const Parser = require('url'); const Child = require('child_process'); const Util = require('util'); const http = require('http'); const ENCODING = 'utf8'; const HEADER_CACHE = 'Cache-Control'; const HEADER_TYPE = 'Content-Type'; const HEADER_LENGTH = 'Content-Length'; const CT_TEXT = 'text/plain'; const CT_HTML = 'text/html'; const CT_JSON = 'application/json'; const COMPRESSION = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'text/xml': true, 'image/svg+xml': true, 'text/x-markdown': true, 'text/html': true }; const COMPRESSIONSPECIAL = { js: 1, css: 1, mjs: 1 }; const RESPONSENOCACHE = { zip: 1, rar: 1 }; const REG_TEMPORARY = /\//g; const REG_MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|Tablet/i; const REG_ROBOT = /search|agent|bot|crawler|spider/i; const REG_VERSIONS = /(href|src)="[a-zA-Z0-9/:\-._]+\.(jpg|js|css|png|apng|gif|svg|html|ico|json|less|sass|scss|swf|txt|webp|heif|heic|jpeg|woff|woff2|xls|xlsx|xml|xsl|xslt|zip|rar|csv|doc|docx|eps|gzip|jpe|jpeg|manifest|mov|mp3|flac|mp4|ogg|package|pdf)"/gi; const REG_COMPILECSS = /url\(.*?\)/g; const REG_ROUTESTATIC = /^(\/\/|https:|http:)+/; const REG_NEWIMPL = /^(async\s)?function(\s)?([a-zA-Z$][a-zA-Z0-9$]+)?(\s)?\([a-zA-Z0-9$]+\)|^function anonymous\(\$/; const REG_RANGE = /bytes=/; const REG_EMPTY = /\s/g; const REG_ACCEPTCLEANER = /\s|\./g; const REG_SANITIZE_BACKSLASH = /\/\//g; const REG_WEBSOCKET_ERROR = /ECONNRESET|EHOSTUNREACH|EPIPE|is closed/i; const REG_WINDOWSPATH = /\\/g; const REG_SCRIPTCONTENT = /<|>|;/; const REG_HTTPHTTPS = /^(\/)?(http|https):\/\//i; const REG_NOCOMPRESS = /[.|-]+min(@[a-z0-9]*)?\.(css|js)$/i; const REG_WWW = /^www\./i; const REG_TEXTAPPLICATION = /text|application/; const REG_ENCODINGCLEANER = /[;\s]charset=utf-8/g; const REG_SKIPERROR = /epipe|invalid\sdistance/i; const REG_OLDCONF = /-/g; const REG_UTF8 = /[^\x20-\x7E]+/; const REG_ENCODEDSPACE = /\+/g; const FLAGS_INSTALL = ['get']; const FLAGS_DOWNLOAD = ['get', 'dnscache']; const QUERYPARSEROPTIONS = { maxKeys: 33 }; const EMPTYARRAY = []; const EMPTYOBJECT = {}; const EMPTYREQUEST = { uri: {} }; const SINGLETONS = {}; const REPOSITORY_HEAD = '$head'; const REPOSITORY_META_TITLE = '$title'; const REPOSITORY_META_DESCRIPTION = '$description'; const REPOSITORY_META_KEYWORDS = '$keywords'; const REPOSITORY_META_AUTHOR = '$author'; const REPOSITORY_META_IMAGE = '$image'; const REPOSITORY_PLACE = '$place'; const REPOSITORY_SITEMAP = '$sitemap'; const REPOSITORY_COMPONENTS = '$components'; const ATTR_END = '"'; const ETAG = '858'; const CONCAT = [null, null]; const CLUSTER_CACHE_SET = { TYPE: 'cache', method: 'set' }; const CLUSTER_CACHE_REMOVE = { TYPE: 'cache', method: 'remove' }; const CLUSTER_CACHE_REMOVEALL = { TYPE: 'cache', method: 'removeAll' }; const CLUSTER_CACHE_CLEAR = { TYPE: 'cache', method: 'clear' }; const CLUSTER_SNAPSHOT = { TYPE: 'snapshot' }; const GZIPFILE = { memLevel: 9 }; const GZIPSTREAM = { memLevel: 1 }; const MODELERROR = {}; const IMAGES = { jpg: 1, png: 1, gif: 1, apng: 1, jpeg: 1, heif: 1, heic: 1, webp: 1 }; const KEYSLOCALIZE = { html: 1, htm: 1 }; const PROXYOPTIONS = { end: true }; const PROXYKEEPALIVE = new http.Agent({ keepAlive: true, timeout: 60000 }); const JSFILES = { js: 1, mjs: 1 }; var PREFFILE = 'preferences.json'; var PATHMODULES = require.resolve('./index'); PATHMODULES = PATHMODULES.substring(0, PATHMODULES.length - 8); Object.freeze(EMPTYOBJECT); Object.freeze(EMPTYARRAY); Object.freeze(EMPTYREQUEST); global.EMPTYOBJECT = EMPTYOBJECT; global.EMPTYARRAY = EMPTYARRAY; global.NOW = new Date(); global.THREAD = ''; global.isWORKER = false; global.REQUIRE = function(path) { return require(F.directory + '/' + path); }; function flowwrapper(name) { if (!name) name = 'default'; if (F.flows[name]) return F.flows[name]; var flow = new framework_flow.make(name); return F.flows[name] = flow; } global.FLOWSTREAM = function(name) { global.framework_flow = require('./flow'); global.FLOW = flowwrapper; return flowwrapper(name); }; var DEF = global.DEF = {}; DEF.currencies = {}; var PROTORES, PROTOREQ; var RANGE = { start: 0, end: 0 }; var HEADERS = {}; var SUCCESSHELPER = { success: true }; // Cached headers for repeated usage HEADERS.responseCode = {}; HEADERS.responseCode[HEADER_TYPE] = CT_TEXT; HEADERS.redirect = {}; HEADERS.redirect[HEADER_TYPE] = CT_HTML + '; charset=utf-8'; HEADERS.redirect[HEADER_LENGTH] = '0'; HEADERS.sse = {}; HEADERS.sse[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.sse['Pragma'] = 'no-cache'; HEADERS.sse['Expires'] = '-1'; HEADERS.sse[HEADER_TYPE] = 'text/event-stream'; HEADERS.sse['X-Powered-By'] = 'Total.js'; HEADERS.file_lastmodified = {}; HEADERS.file_lastmodified['Access-Control-Allow-Origin'] = '*'; HEADERS.file_lastmodified[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.file_lastmodified['X-Powered-By'] = 'Total.js'; HEADERS.file_release_compress = {}; HEADERS.file_release_compress[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.file_release_compress['Vary'] = 'Accept-Encoding'; HEADERS.file_release_compress['Access-Control-Allow-Origin'] = '*'; HEADERS.file_release_compress['Last-Modified'] = 'Mon, 01 Jan 2001 08:00:00 GMT'; HEADERS.file_release_compress['Content-Encoding'] = 'gzip'; HEADERS.file_release_compress['X-Powered-By'] = 'Total.js'; HEADERS.file_release_compress_range = {}; HEADERS.file_release_compress_range['Accept-Ranges'] = 'bytes'; HEADERS.file_release_compress_range[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.file_release_compress_range['Vary'] = 'Accept-Encoding'; HEADERS.file_release_compress_range['Access-Control-Allow-Origin'] = '*'; HEADERS.file_release_compress_range['Last-Modified'] = 'Mon, 01 Jan 2001 08:00:00 GMT'; HEADERS.file_release_compress_range['Content-Encoding'] = 'gzip'; HEADERS.file_release_compress_range[HEADER_LENGTH] = '0'; HEADERS.file_release_compress_range['Content-Range'] = ''; HEADERS.file_release_compress_range['X-Powered-By'] = 'Total.js'; HEADERS.file_release = {}; HEADERS.file_release[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.file_release['Vary'] = 'Accept-Encoding'; HEADERS.file_release['Access-Control-Allow-Origin'] = '*'; HEADERS.file_release['Last-Modified'] = 'Mon, 01 Jan 2001 08:00:00 GMT'; HEADERS.file_release['X-Powered-By'] = 'Total.js'; HEADERS.file_release_range = {}; HEADERS.file_release_range['Accept-Ranges'] = 'bytes'; HEADERS.file_release_range[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.file_release_range['Vary'] = 'Accept-Encoding'; HEADERS.file_release_range['Access-Control-Allow-Origin'] = '*'; HEADERS.file_release_range['Last-Modified'] = 'Mon, 01 Jan 2001 08:00:00 GMT'; HEADERS.file_release_range[HEADER_LENGTH] = '0'; HEADERS.file_release_range['Content-Range'] = ''; HEADERS.file_release_range['X-Powered-By'] = 'Total.js'; HEADERS.file_debug_compress = {}; HEADERS.file_debug_compress[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.file_debug_compress['Vary'] = 'Accept-Encoding'; HEADERS.file_debug_compress['Access-Control-Allow-Origin'] = '*'; HEADERS.file_debug_compress['Pragma'] = 'no-cache'; HEADERS.file_debug_compress['Expires'] = '-1'; HEADERS.file_debug_compress['Content-Encoding'] = 'gzip'; HEADERS.file_debug_compress['X-Powered-By'] = 'Total.js'; HEADERS.file_debug_compress_range = {}; HEADERS.file_debug_compress_range['Accept-Ranges'] = 'bytes'; HEADERS.file_debug_compress_range[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.file_debug_compress_range['Vary'] = 'Accept-Encoding'; HEADERS.file_debug_compress_range['Access-Control-Allow-Origin'] = '*'; HEADERS.file_debug_compress_range['Content-Encoding'] = 'gzip'; HEADERS.file_debug_compress_range['Pragma'] = 'no-cache'; HEADERS.file_debug_compress_range['Expires'] = '-1'; HEADERS.file_debug_compress_range[HEADER_LENGTH] = '0'; HEADERS.file_debug_compress_range['Content-Range'] = ''; HEADERS.file_debug_compress_range['X-Powered-By'] = 'Total.js'; HEADERS.file_debug = {}; HEADERS.file_debug[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.file_debug['Vary'] = 'Accept-Encoding'; HEADERS.file_debug['Pragma'] = 'no-cache'; HEADERS.file_debug['Expires'] = '-1'; HEADERS.file_debug['Access-Control-Allow-Origin'] = '*'; HEADERS.file_debug['X-Powered-By'] = 'Total.js'; HEADERS.file_debug_range = {}; HEADERS.file_debug_range['Accept-Ranges'] = 'bytes'; HEADERS.file_debug_range[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.file_debug_range['Vary'] = 'Accept-Encoding'; HEADERS.file_debug_range['Access-Control-Allow-Origin'] = '*'; HEADERS.file_debug_range['Pragma'] = 'no-cache'; HEADERS.file_debug_range['Expires'] = '-1'; HEADERS.file_debug_range[HEADER_LENGTH] = '0'; HEADERS.file_debug_range['Content-Range'] = ''; HEADERS.file_debug_range['X-Powered-By'] = 'Total.js'; HEADERS.content_mobile_release = {}; HEADERS.content_mobile_release[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.content_mobile_release['Vary'] = 'Accept-Encoding, User-Agent'; HEADERS.content_mobile_release['Content-Encoding'] = 'gzip'; HEADERS.content_mobile_release['Expires'] = '-1'; HEADERS.content_mobile_release['X-Powered-By'] = 'Total.js'; HEADERS.content_mobile = {}; HEADERS.content_mobile[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.content_mobile['Vary'] = 'Accept-Encoding, User-Agent'; HEADERS.content_mobile['Expires'] = '-1'; HEADERS.content_mobile['X-Powered-By'] = 'Total.js'; HEADERS.content_compress = {}; HEADERS.content_compress[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.content_compress['Vary'] = 'Accept-Encoding'; HEADERS.content_compress['Content-Encoding'] = 'gzip'; HEADERS.content_compress['Expires'] = '-1'; HEADERS.content_compress['X-Powered-By'] = 'Total.js'; HEADERS.content = {}; HEADERS.content[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.content['Vary'] = 'Accept-Encoding'; HEADERS.content['Expires'] = '-1'; HEADERS.content['X-Powered-By'] = 'Total.js'; HEADERS.stream_release_compress = {}; HEADERS.stream_release_compress[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.stream_release_compress['Access-Control-Allow-Origin'] = '*'; HEADERS.stream_release_compress['Content-Encoding'] = 'gzip'; HEADERS.stream_release_compress['X-Powered-By'] = 'Total.js'; HEADERS.stream_release = {}; HEADERS.stream_release[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.stream_release['Access-Control-Allow-Origin'] = '*'; HEADERS.stream_release['X-Powered-By'] = 'Total.js'; HEADERS.stream_debug_compress = {}; HEADERS.stream_debug_compress[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.stream_debug_compress['Pragma'] = 'no-cache'; HEADERS.stream_debug_compress['Expires'] = '-1'; HEADERS.stream_debug_compress['Access-Control-Allow-Origin'] = '*'; HEADERS.stream_debug_compress['Content-Encoding'] = 'gzip'; HEADERS.stream_debug_compress['X-Powered-By'] = 'Total.js'; HEADERS.stream_debug = {}; HEADERS.stream_debug[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.stream_debug['Pragma'] = 'no-cache'; HEADERS.stream_debug['Expires'] = '-1'; HEADERS.stream_debug['Access-Control-Allow-Origin'] = '*'; HEADERS.stream_debug['X-Powered-By'] = 'Total.js'; HEADERS.binary_compress = {}; HEADERS.binary_compress[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.binary_compress['Content-Encoding'] = 'gzip'; HEADERS.binary_compress['X-Powered-By'] = 'Total.js'; HEADERS.binary = {}; HEADERS.binary[HEADER_CACHE] = 'public'; HEADERS.binary['X-Powered-By'] = 'Total.js'; HEADERS.authorization = { user: '', password: '', empty: true }; HEADERS.fsStreamRead = { flags: 'r', mode: '0666', autoClose: true }; HEADERS.fsStreamReadRange = { flags: 'r', mode: '0666', autoClose: true, start: 0, end: 0 }; HEADERS.responseLocalize = {}; HEADERS.responseLocalize['Access-Control-Allow-Origin'] = '*'; HEADERS.responseNotModified = {}; HEADERS.responseNotModified[HEADER_CACHE] = 'public, max-age=11111111'; HEADERS.responseNotModified['X-Powered-By'] = 'Total.js'; HEADERS.response503 = {}; HEADERS.response503[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.response503[HEADER_TYPE] = CT_HTML; HEADERS.response503['X-Powered-By'] = 'Total.js'; HEADERS.response503ddos = {}; HEADERS.response503ddos[HEADER_CACHE] = 'private, no-cache, no-store, max-age=0'; HEADERS.response503ddos[HEADER_TYPE] = CT_TEXT; HEADERS.response503ddos['X-Powered-By'] = 'Total.js'; Object.freeze(HEADERS.authorization); var _controller = ''; var _owner = ''; var _flags; var _prefix; // GO ONLINE MODE !global.framework_internal && (global.framework_internal = require('./internal')); !global.framework_builders && (global.framework_builders = require('./builders')); !global.framework_utils && (global.framework_utils = require('./utils')); !global.framework_mail && (global.framework_mail = require('./mail')); !global.framework_image && (global.framework_image = require('./image')); !global.framework_session && (global.framework_session = require('./session')); require('./tangular'); function sessionwrapper(name) { if (!name) name = 'default'; if (F.sessions[name]) return F.sessions[name]; var session = new framework_session.Session(name); session.load(); if (F.sessionscount) F.sessionscount++; else F.sessionscount = 1; return F.sessions[name] = session; } global.SESSION = function(name) { global.framework_session = require('./session'); global.SESSION = sessionwrapper; return sessionwrapper(name); }; var TMPENV = framework_utils.copy(process.env); TMPENV.istotaljsworker = true; HEADERS.workers = { cwd: '', silent: false, env: TMPENV }; HEADERS.workers2 = { cwd: '', silent: true, env: TMPENV }; global.Builders = framework_builders; var U = global.Utils = global.utils = global.U = global.framework_utils; global.Mail = framework_mail; global.WTF = (message, name, uri) => F.problem(message, name, uri); global.NOBIN = global.NOSQLBINARY = (name) => F.nosql(name).binary; global.NOSQLSTORAGE = (name) => F.nosql(name).storage; global.NOCOUNTER = global.NOSQLCOUNTER = (name) => F.nosql(name).counter; function nomemwrapper(name) { return global.framework_nosql.inmemory(name); } global.NOMEM = global.NOSQLMEMORY = function(name) { if (!global.framework_nosql) global.framework_nosql = require('./nosql'); global.NOMEM = global.NOSQLMEMORY = global.framework_nosql.inmemory; return nomemwrapper(name); }; global.CONFIG = function(name, val) { return arguments.length === 1 ? CONF[name] : (CONF[name] = val); }; var prefid; global.PREF = {}; global.PREF.set = function(name, value) { if (value === undefined) return F.pref[name]; if (value === null) { delete F.pref[name]; } else F.pref[name] = global.PREF[name] = value; prefid && clearTimeout(prefid); prefid = setTimeout(F.onPrefSave, 1000, F.pref); }; global.CACHE = function(name, value, expire, persistent) { return arguments.length === 1 ? F.cache.get2(name) : F.cache.set(name, value, expire, persistent); }; global.CREATE = (group, name) => framework_builders.getschema(group, name).default(); global.SINGLETON = (name, def) => SINGLETONS[name] || (SINGLETONS[name] = (new Function('return ' + (def || '{}')))()); global.FUNCTION = (name) => F.functions[name] || NOOP; global.FINISHED = framework_internal.onFinished; global.DESTROY = framework_internal.destroyStream; function filestoragewrapper(name) { var key = 'storage_' + name; return F.databases[key] ? F.databases[key] : (F.databases[key] = new framework_nosql.DatabaseBinary({ name: name }, F.path.databases('fs-' + name + '/'), '.file')); } global.FILESTORAGE = function(name) { if (!global.framework_nosql) global.framework_nosql = require('./nosql'); global.FILESTORAGE = filestoragewrapper; return filestoragewrapper(name); }; global.UID16 = function(type) { var index; if (type) { if (UIDGENERATOR.types[type]) index = UIDGENERATOR.types[type] = UIDGENERATOR.types[type] + 1; else { UIDGENERATOR.multiple = true; index = UIDGENERATOR.types[type] = 1; } } else index = UIDGENERATOR.index++; return UIDGENERATOR.date16 + index.padLeft(3, '0') + UIDGENERATOR.instance + UIDGENERATOR.date16.length + (index % 2 ? 1 : 0) + 'c'; // "c" version }; global.UID = function(type) { var index; if (type) { if (UIDGENERATOR.types[type]) index = UIDGENERATOR.types[type] = UIDGENERATOR.types[type] + 1; else { UIDGENERATOR.multiple = true; index = UIDGENERATOR.types[type] = 1; } } else index = UIDGENERATOR.index++; return UIDGENERATOR.date + index.padLeft(3, '0') + UIDGENERATOR.instance + UIDGENERATOR.date.length + (index % 2 ? 1 : 0) + 'b'; // "b" version }; global.UIDF = function(type) { var index; if (type) { if (UIDGENERATOR.typesnumber[type]) index = UIDGENERATOR.typesnumber[type] = UIDGENERATOR.typesnumber[type] + 1; else { UIDGENERATOR.multiplenumber = true; index = UIDGENERATOR.typesnumber[type] = 1; } } else index = UIDGENERATOR.indexnumber++; var div = index > 1000 ? 10000 : 1000; return (UIDGENERATOR.datenumber + (index / div)); }; global.ERROR = function(name) { return name == null ? F.errorcallback : function(err) { err && F.error(err, name); }; }; global.AUTH = function(fn) { F.onAuthorize = framework_builders.AuthOptions.wrap(fn); }; global.WEBSOCKETCLIENT = function(callback) { var ws = require('./websocketclient').create(); callback && callback.call(ws, ws); return ws; }; global.$CREATE = function(schema) { var o = framework_builders.getschema(schema); return o ? o.default() : null; }; global.$MAKE = function(schema, model, filter, callback, novalidate, argument) { var o = framework_builders.getschema(schema); var w = null; if (typeof(filter) === 'function') { var tmp = callback; callback = filter; filter = tmp; } if (filter instanceof Array) { w = {}; for (var i = 0; i < filter.length; i++) w[filter[i]] = i + 1; filter = null; } else if (filter instanceof Object) { if (!(filter instanceof RegExp)) { filter = null; w = filter; } } return o ? o.make(model, filter, callback, argument, novalidate, w) : undefined; }; global.$QUERY = function(schema, options, callback, controller) { var o = framework_builders.getschema(schema); if (o) o.query(options, callback, controller); else callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return !!o; }; global.$GET = global.$READ = function(schema, options, callback, controller) { var o = framework_builders.getschema(schema); if (o) o.get(options, callback, controller); else callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return !!o; }; global.$WORKFLOW = function(schema, name, options, callback, controller) { var o = framework_builders.getschema(schema); if (o) o.workflow2(name, options, callback, controller); else callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return !!o; }; global.$TRANSFORM = function(schema, name, options, callback, controller) { var o = framework_builders.getschema(schema); if (o) o.transform2(name, options, callback, controller); else callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return !!o; }; global.$REMOVE = function(schema, options, callback, controller) { var o = framework_builders.getschema(schema); if (typeof(options) === 'function') { controller = callback; callback = options; options = EMPTYOBJECT; } if (o) o.remove(options, callback, controller); else callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return !!o; }; global.$SAVE = function(schema, model, options, callback, controller, novalidate) { return performschema('$save', schema, model, options, callback, controller, novalidate); }; global.$INSERT = function(schema, model, options, callback, controller, novalidate) { return performschema('$insert', schema, model, options, callback, controller, novalidate); }; global.$UPDATE = function(schema, model, options, callback, controller, novalidate) { return performschema('$update', schema, model, options, callback, controller, novalidate); }; global.$PATCH = function(schema, model, options, callback, controller, novalidate) { return performschema('$patch', schema, model, options, callback, controller, novalidate); }; // GET Users/Neviem --> @query @workflow global.$ACTION = function(schema, model, callback, controller) { if (typeof(model) === 'function') { controller = callback; callback = model; model = null; } var meta = F.temporary.other[schema]; var tmp, index; if (!meta) { index = schema.indexOf('-->'); var op = (schema.substring(index + 3).trim().trim() + ' ').split(/\s@/).trim(); tmp = schema.substring(0, index).split(/\s|\t/).trim(); if (tmp.length !== 2) { callback('Invalid "{0}" type.'.format(schema)); return; } meta = {}; meta.method = tmp[0].toUpperCase(); meta.schema = tmp[1]; if (meta.schema[0] === '*') meta.schema = meta.schema.substring(1); meta.op = []; meta.opcallbackindex = -1; var name = meta.schema.split('/'); var o = GETSCHEMA(name[0], name[1]); if (!o) { callback(new ErrorBuilder().push('', 'Schema "{0}" not found'.format(meta.schema))); return; } for (var i = 0; i < op.length; i++) { tmp = {}; var item = op[i]; if (item[0] === '@') item = item.substring(1); index = item.indexOf('('); if (index !== -1) { meta.opcallbackindex = i; tmp.response = true; item = item.substring(0, index).trim(); } tmp.name = item; tmp.name2 = '$' + tmp.name; if (o.meta[item] === undefined) { if (o.meta['workflow#' + item] !== undefined) tmp.type = '$workflow'; else if (o.meta['transform#' + item] !== undefined) tmp.type = '$transform'; else if (o.meta['operation#' + item] !== undefined) tmp.type = '$operation'; else if (o.meta['hook#' + item] !== undefined) tmp.type = '$hook'; else { callback(new ErrorBuilder().push('', 'Schema "{0}" doesn\'t contain "{1}" operation.'.format(meta.schema, item))); return; } } if (tmp.type) tmp.type2 = tmp.type.substring(1); meta.op.push(tmp); } meta.multiple = meta.op.length > 1; meta.schema = o; meta.validate = meta.method !== 'GET'; F.temporary.other[schema] = meta; } if (meta.validate) { var req = controller ? controller.req : null; if (meta.method === 'PATCH' || meta.method === 'DELETE') { if (!req) req = {}; req.$patch = true; } var data = {}; data.meta = meta; data.callback = callback; data.controller = controller; meta.schema.make(model, null, performsschemaaction_async, data, null, null, req); } else performsschemaaction(meta, null, callback, controller); }; function performsschemaaction_async(err, response, data) { if (err) data.callback(err); else performsschemaaction(data.meta, response, data.callback, data.controller); } function performsschemaaction(meta, model, callback, controller) { if (meta.multiple) { if (!model) model = meta.schema.default(); model.$$controller = controller; var async = model.$async(callback, meta.opcallbackindex === - 1 ? null : meta.opcallbackindex); for (var i = 0; i < meta.op.length; i++) { var op = meta.op[i]; if (op.type) async[op.type](op.name); else async[op.name2](); } } else { var op = meta.op[0]; if (model) { model.$$controller = controller; if (op.type) model[op.type](op.name, EMPTYOBJECT, callback); else model[op.name2](EMPTYOBJECT, callback); } else { if (op.type) meta.schema[op.type2 + '2'](op.name, EMPTYOBJECT, callback, controller); else meta.schema[op.name](EMPTYOBJECT, callback, controller); } } } // type, schema, model, options, callback, controller function performschema(type, schema, model, options, callback, controller, novalidate) { if (typeof(options) === 'function') { novalidate = controller; controller = callback; callback = options; options = null; } var o = framework_builders.getschema(schema); if (!o) { callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return false; } var workflow = {}; workflow[type.substring(1)] = 1; var req = controller ? controller.req : null; var keys; if (type === '$patch') { keys = Object.keys(model); if (req) req.$patch = true; else req = { $patch: true }; } o.make(model, null, function(err, model) { if (err) { callback && callback(err); } else { model.$$keys = keys; model.$$controller = controller; model[type](options, callback); if (req && req.$patch && req.method && (req.method !== 'PATCH' & req.method !== 'DELETE')) delete req.$patch; } }, null, novalidate, workflow, req); return !!o; } global.$ASYNC = function(schema, callback, index, controller) { if (index && typeof(index) === 'object') { controller = index; index = undefined; } var o = framework_builders.getschema(schema).default(); if (!o) { callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return EMPTYOBJECT; } controller && (o.$$controller = controller); return o.$async(callback, index); }; global.$OPERATION = function(schema, name, options, callback, controller) { var o = framework_builders.getschema(schema); if (o) o.operation2(name, options, callback, controller); else callback && callback(new Error('Schema "{0}" not found.'.format(getSchemaName(schema)))); return !!o; }; global.DB = global.DATABASE = function(a, b, c, d) { return typeof(F.database) === 'object' ? F.database : F.database(a, b, c, d); }; global.OFF = function() { return arguments.length > 1 ? F.removeListener.apply(F, arguments) : F.removeAllListeners.apply(F, arguments); }; global.NEWSCHEMA = function(group, name, make) { if (typeof(name) === 'function') { make = name; name = undefined; } if (!name) { var arr = group.split('/'); if (arr.length === 2) { name = arr[1]; group = arr[0]; } else { name = group; group = 'default'; } } var schema = framework_builders.newschema(group, name); make && make.call(schema, schema); return schema; }; global.CLEANUP = function(stream, callback) { FINISHED(stream, function() { DESTROY(stream); if (callback) { callback(); callback = null; } }); }; global.SUCCESS = function(success, value) { if (typeof(success) === 'function') { return function(err, value) { success(err, SUCCESS(err, value)); }; } var err; if (success instanceof Error) { err = success.toString(); success = false; } else if (success instanceof framework_builders.ErrorBuilder) { if (success.hasError()) { err = success.output(); success = false; } else success = true; } else if (success == null) success = true; SUCCESSHELPER.success = !!success; SUCCESSHELPER.value = value === SUCCESSHELPER ? value.value : value == null ? undefined : (value && value.$$schema ? value.$clean() : value); SUCCESSHELPER.error = err ? err : undefined; return SUCCESSHELPER; }; global.TRY = function(fn, err) { try { fn(); return true; } catch (e) { err && err(e); return false; } }; global.OBSOLETE = function(name, message) { if (F.config.nowarnings) return; console.log(NOW.format('yyyy-MM-dd HH:mm:ss') + ' :: OBSOLETE / IMPORTANT ---> "' + name + '"', message); if (global.F) F.stats.other.obsolete++; }; global.DEBUG = false; global.TEST = false; global.RELEASE = false; global.is_client = false; global.is_server = true; var directory = U.$normalize(require.main ? Path.dirname(require.main.filename) : process.cwd()); // F.service() changes the values below: var DATE_EXPIRES = new Date().add('y', 1).toUTCString(); const _randomstring = 'abcdefghijklmnoprstuwxy'.split(''); function random2string() { return _randomstring[(Math.random() * _randomstring.length) >> 0] + _randomstring[(Math.random() * _randomstring.length) >> 0]; } const WEBSOCKET_COMPRESS = Buffer.from([0x00, 0x00, 0xFF, 0xFF]); const WEBSOCKET_COMPRESS_OPTIONS = { windowBits: Zlib.Z_DEFAULT_WINDOWBITS }; const UIDGENERATOR = { types: {}, typesnumber: {} }; function UIDGENERATOR_REFRESH() { var ticks = NOW.getTime(); var dt = Math.round(((ticks - 1580511600000) / 1000 / 60)); UIDGENERATOR.date = dt + ''; UIDGENERATOR.date16 = dt.toString(16); var seconds = ((NOW.getSeconds() / 60) + '').substring(2, 4); UIDGENERATOR.datenumber = +((((ticks - 1580511600000) / 1000 / 60) >> 0) + seconds); // 1580511600000 means 1.1.2020 UIDGENERATOR.indexnumber = 1; UIDGENERATOR.index = 1; UIDGENERATOR.instance = random2string(); var keys; if (UIDGENERATOR.multiple) { keys = Object.keys(UIDGENERATOR.types); for (var i = 0; i < keys.length; i++) UIDGENERATOR.types[keys[i]] = 0; } if (UIDGENERATOR.multiplenumber) { keys = Object.keys(UIDGENERATOR.typesnumber); for (var i = 0; i < keys.length; i++) UIDGENERATOR.typesnumber[keys[i]] = 0; } } UIDGENERATOR_REFRESH(); const EMPTYBUFFER = Buffer.alloc(0); global.EMPTYBUFFER = EMPTYBUFFER; const controller_error_status = function(controller, status, problem) { if (status !== 500 && problem) controller.problem(problem); if (controller.res.success || controller.res.headersSent || !controller.isConnected) return controller; controller.precache && controller.precache(null, null, null); controller.req.path = EMPTYARRAY; controller.req.$total_success(); controller.req.$total_route = F.lookup(controller.req, '#' + status, EMPTYARRAY, 0); controller.req.$total_exception = problem; controller.req.$total_execute(status, true); return controller; }; var PERF = {}; function Framework() { var self = this; self.$id = null; // F.id ==> property self.version = 3413; self.version_header = '3.4.13'; self.version_node = process.version.toString(); self.syshash = (__dirname + '-' + Os.hostname() + '-' + Os.platform() + '-' + Os.arch() + '-' + Os.release() + '-' + Os.tmpdir() + JSON.stringify(process.versions)).md5(); self.pref = global.PREF; global.CONF = self.config = { debug: true, trace: true, trace_console: true, //nowarnings: process.argv.indexOf('restart') !== -1, nowarnings: true, name: 'Total.js', version: '1.0.0', author: '', secret: self.syshash, secret_uid: self.syshash.substring(10), 'security.txt': 'Contact: mailto:support@totaljs.com\nContact: https://www.totaljs.com/contact/', etag_version: '', directory_src: '/.src/', directory_bundles: '/bundles/', directory_controllers: '/controllers/', directory_components: '/components/', directory_views: '/views/', directory_definitions: '/definitions/', directory_temp: '/tmp/', directory_models: '/models/', directory_schemas: '/schemas/', directory_operations: '/operations/', directory_resources: '/resources/', directory_public: '/public/', directory_public_virtual: '/app/', directory_modules: '/modules/', directory_source: '/source/', directory_logs: '/logs/', directory_tests: '/tests/', directory_databases: '/databases/', directory_workers: '/workers/', directory_packages: '/packages/', directory_private: '/private/', directory_isomorphic: '/isomorphic/', directory_configs: '/configs/', directory_services: '/services/', directory_themes: '/themes/', directory_tasks: '/tasks/', directory_updates: '/updates/', // all HTTP static request are routed to directory-public static_url: '', static_url_script: '/js/', static_url_style: '/css/', static_url_image: '/img/', static_url_video: '/video/', static_url_font: '/fonts/', static_url_download: '/download/', static_url_components: '/components.', static_accepts: { flac: true, jpg: true, jpeg: true, png: true, gif: true, ico: true, js: true, mjs: true, css: true, txt: true, xml: true, woff: true, woff2: true, otf: true, ttf: true, eot: true, svg: true, zip: true, rar: true, pdf: true, docx: true, xlsx: true, doc: true, xls: true, html: true, htm: true, appcache: true, manifest: true, map: true, ogv: true, ogg: true, mp4: true, mp3: true, webp: true, webm: true, swf: true, package: true, json: true, md: true, m4v: true, jsx: true, heif: true, heic: true, ics: true }, // 'static-accepts-custom': [], default_crypto_iv: Buffer.from(self.syshash).slice(0, 16), default_xpoweredby: 'Total.js', default_layout: 'layout', default_theme: '', default_proxy: '', default_request_maxkeys: 33, default_request_maxkey: 25, // default maximum request size / length // default 10 kB default_request_maxlength: 10, default_websocket_maxlength: 2, default_websocket_encodedecode: true, default_maxopenfiles: 100, default_timezone: 'utc', default_root: '', default_response_maxage: '11111111', default_errorbuilder_status: 200, // Default originators default_cors: null, // Seconds (2 minutes) default_cors_maxage: 120, // in milliseconds default_request_timeout: 3000, default_dependency_timeout: 1500, default_restbuilder_timeout: 10000, // otherwise is used ImageMagick (Heroku supports ImageMagick) // gm = graphicsmagick or im = imagemagick or magick (new version of ImageMagick) default_image_converter: 'gm', // command-line name default_image_quality: 93, default_image_consumption: 0, // disabled because e.g. GM v1.3.32 throws some error about the memory allow_static_files: true, allow_gzip: true, allow_websocket: true, allow_websocket_compression: true, allow_compile: true, allow_compile_script: true, allow_compile_style: true, allow_compile_html: true, allow_localize: true, allow_stats_snapshot: true, allow_performance: false, allow_custom_titles: false, allow_cache_snapshot: false, allow_cache_cluster: false, allow_debug: false, allow_head: false, allow_filter_errors: true, allow_clear_temp: true, allow_ssc_validation: true, allow_workers_silent: false, allow_sessions_unused: '-20 minutes', allow_reqlimit: 0, allow_persistent_images: false, nosql_worker: false, nosql_inmemory: null, // String Array nosql_cleaner: 1440, nosql_logger: true, logger: false, // Used in F.service() // All values are in minutes default_interval_clear_resources: 20, default_interval_clear_cache: 10, default_interval_clear_dnscache: 30, default_interval_precompile_views: 61, default_interval_websocket_ping: 3, default_interval_uptodate: 5, set ['mail-smtp'] (val) { CONF['mail_smtp'] = val; return null; }, set ['mail-smtp-options'] (val) { CONF['mail_smtp_options'] = val; return null; }, set ['mail-address-reply'] (val) { CONF['mail_address_reply'] = val; return null; }, set ['mail-address-from'] (val) { CONF['mail_address_from'] = val; return null; }, set ['mail-address-copy'] (val) { CONF['mail_address_copy'] = val; return null; } }; global.REPO = global.G = self.global = {}; global.MAIN = {}; global.TEMP = {}; self.$bundling = true; self.resources = {}; self.connections = {}; global.FUNC = self.functions = {}; self.themes = {}; self.versions = null; self.workflows = {}; self.uptodates = null; self.schedules = {}; self.isDebug = true; self.isTest = false; self.isLoaded = false; self.isWorker = true; self.isCluster = process.env.PASSENGER_APP_ENV ? false : require('cluster').isWorker; self.routes = { sitemap: null, web: [], system: {}, files: [], filesfallback: null, cors: [], corsall: false, websockets: [], middleware: {}, redirects: {}, resize: {}, request: [], views: {}, merge: {}, mapping: {}, packages: {}, blocks: {}, proxies: [], resources: {} }; self.owners = []; self.modificators = null; self.modificators2 = null; DEF.helpers = self.helpers = {}; self.modules = {}; self.models = {}; self.sources = {}; self.controllers = {}; self.dependencies = {}; self.isomorphic = {}; self.components = { has: false, css: false, js: false, views: {}, instances: {}, version: null, links: '', groups: {}, files: {} }; self.convertors = []; self.convertors2 = null; self.tests = []; self.errors = []; self.timeouts = []; self.problems = []; self.changes = []; self.server = null; self.port = 0; self.ip = ''; DEF.validators = self.validators = { email: new RegExp('^[a-zA-Z0-9-_.+]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'), url: /^http(s)?:\/\/[^,{}\\]*$/i, phone: /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,8}$/im, zip: /^[0-9a-z\-\s]{3,20}$/i, uid: /^\d{14,}[a-z]{3}[01]{1}|^\d{9,14}[a-z]{2}[01]{1}a|^\d{4,18}[a-z]{2}\d{1}[01]{1}b|^[0-9a-f]{4,18}[a-z]{2}\d{1}[01]{1}c|^[0-9a-z]{4,18}[a-z]{2}\d{1}[01]{1}d$/ }; self.workers = {}; self.sessions = {}; self.flows = {}; self.databases = {}; self.databasescleaner = {}; self.directory = HEADERS.workers2.cwd = HEADERS.workers.cwd = directory; self.isLE = Os.endianness ? Os.endianness() === 'LE' : true; self.isHTTPS = false; // Fix for workers crash (port in use) when debugging main process with --inspect or --debug // See: https://github.com/nodejs/node/issues/14325 and https://github.com/nodejs/node/issues/9435 for (var i = 0; i < process.execArgv.length; i++) { // Setting inspect/debug port to random unused if ((/inspect|debug/).test(process.execArgv[i])) { process.execArgv[i] = '--inspect=0'; break; } } HEADERS.workers.execArgv = process.execArgv; // It's hidden // self.waits = {}; self.temporary = { path: {}, shortcache: {}, notfound: {}, processing: {}, range: {}, views: {}, versions: {}, dependencies: {}, // temporary for module dependencies other: {}, keys: {}, // for crypto keys internal: {}, // controllers/modules names for the routing owners: {}, ready: {}, ddos: {}, service: { redirect: 0, request: 0, file: 0, usage: 0 } }; self.stats = { error: 0, performance: { request: 0, message: 0, external: 0, file: 0, open: 0, dbrm: 0, dbwm: 0, online: 0, usage: 0, mail: 0 }, other: { websocketPing: 0, websocketCleaner: 0, obsolete: 0, mail: 0 }, request: { request: 0, pending: 0, web: 0, xhr: 0, file: 0, websocket: 0, get: 0, options: 0, head: 0, post: 0, put: 0, patch: 0, upload: 0, schema: 0, operation: 0, blocked: 0, 'delete': 0, mobile: 0, desktop: 0 }, response: { ddos: 0, view: 0, json: 0, websocket: 0, timeout: 0, custom: 0, binary: 0, pipe: 0, file: 0, image: 0, destroy: 0, stream: 0, streaming: 0, plain: 0, empty: 0, redirect: 0, forward: 0, proxy: 0, notModified: 0, sse: 0, errorBuilder: 0, error400: 0, error401: 0, error403: 0, error404: 0, error408: 0, error409: 0, error431: 0, error500: 0, error501: 0, error503: 0 } }; // intialize cache self.cache = new FrameworkCache(); self.path = global.PATH = new FrameworkPath(); self._request_check_redirect = false; self._request_check_referer = false; self._request_check_POST = false; self._request_check_robot = false; self._request_check_mobile = false; self._request_check_proxy = false; self._length_middleware = 0; self._length_request_middleware = 0; self._length_files = 0; self._length_wait = 0; self._length_themes = 0; self._length_cors = 0; self._length_subdomain_web = 0; self._length_subdomain_websocket = 0; self._length_convertors = 0; self.isVirtualDirectory = false; self.isTheme = false; self.isWindows = Os.platform().substring(0, 3).toLowerCase() === 'win'; self.$events = {}; self.commands = { reload_preferences: [loadpreferences] }; } // ====================================================== // PROTOTYPES // ====================================================== Framework.prototype = { get datetime() { return global.NOW; }, set datetime(val) { global.NOW = val; }, get cluster() { return require('./cluster'); }, get id() { return F.$id; }, set id(value) { CLUSTER_CACHE_SET.ID = value; CLUSTER_CACHE_REMOVE.ID = value; CLUSTER_CACHE_REMOVEALL.ID = value; CLUSTER_CACHE_CLEAR.ID = value; F.$id = value; return F.$id; } }; var framework = new Framework(); global.framework = global.F = module.exports = framework; global.CMD = function(key, a, b, c, d) { if (F.commands[key]) { for (var i = 0; i < F.commands[key].length; i++) F.commands[key][i](a, b, c, d); } }; F.callback_redirect = function(url) { this.url = url; }; F.dir = function(path) { F.directory = path; directory = path; }; F.refresh = function() { NOW = new Date(); F.$events.clear && EMIT('clear', 'temporary', F.temporary); F.temporary.path = {}; F.temporary.range = {}; F.temporary.views = {}; F.temporary.other = {}; F.temporary.keys = {}; global.$VIEWCACHE && global.$VIEWCACHE.length && (global.$VIEWCACHE = []); // Clears command cache Image.clear(); CONF.allow_debug && F.consoledebug('clear temporary cache'); var keys = Object.keys(F.temporary.internal); for (var i = 0; i < keys.length; i++) if (!F.temporary.internal[keys[i]]) delete F.temporary.internal[keys[i]]; F.$events.clear && EMIT('clear', 'resources'); F.resources = {}; CONF.allow_debug && F.consoledebug('clear resources'); F.$events.clear && EMIT('clear', 'dns'); CMD('clear_dnscache'); CONF.allow_debug && F.consoledebug('clear DNS cache'); return F; }; F.prototypes = function(fn) { if (!global.framework_nosql) global.framework_nosql = require('./nosql'); var proto = {}; proto.Chunker = framework_utils.Chunker.prototype; proto.Controller = Controller.prototype; proto.Database = framework_nosql.Database.prototype; proto.DatabaseBinary = framework_nosql.DatabaseBinary.prototype; proto.DatabaseBuilder = framework_nosql.DatabaseBuilder.prototype; proto.DatabaseBuilder2 = framework_nosql.DatabaseBuilder2.prototype; proto.DatabaseCounter = framework_nosql.DatabaseCounter.prototype; proto.DatabaseStorage = framework_nosql.DatabaseStorage.prototype; proto.DatabaseTable = framework_nosql.DatabaseTable.prototype; proto.ErrorBuilder = framework_builders.ErrorBuilder.prototype; proto.HttpFile = framework_internal.HttpFile.prototype; proto.HttpRequest = PROTOREQ; proto.HttpResponse = PROTORES; proto.Image = framework_image.Image.prototype; proto.Message = Mail.Message.prototype; proto.MiddlewareOptions = MiddlewareOptions.prototype; proto.OperationOptions = framework_builders.OperationOptions.prototype; proto.Page = framework_builders.Page.prototype; proto.Pagination = framework_builders.Pagination.prototype; proto.RESTBuilder = framework_builders.RESTBuilder.prototype; proto.RESTBuilderResponse = framework_builders.RESTBuilderResponse.prototype; proto.SchemaBuilder = framework_builders.SchemaBuilder.prototype; proto.SchemaOptions = framework_builders.SchemaOptions.prototype; proto.UrlBuilder = framework_builders.UrlBuilder.prototype; proto.WebSocket = WebSocket.prototype; proto.WebSocketClient = WebSocketClient.prototype; proto.AuthOptions = framework_builders.AuthOptions.prototype; fn.call(proto, proto); return F; }; global.ON = F.on = function(name, fn) { if (name === 'init' || name === 'ready' || name === 'load') { if (F.isLoaded) { fn.call(F); return; } } else if (name.indexOf('#') !== -1) { var arr = name.split('#'); switch (arr[0]) { case 'middleware': F.temporary.ready[name] && fn.call(F); break; case 'component': F.temporary.ready[name] && fn.call(F); break; case 'model': F.temporary.ready[name] && fn.call(F, F.models[arr[1]]); break; case 'source': F.temporary.ready[name] && fn.call(F, F.sources[arr[1]]); break; case 'package': case 'module': F.temporary.ready[name] && fn.call(F, F.modules[arr[1]]); break; case 'controller': F.temporary.ready[name] && fn.call(F, F.controllers[arr[1]]); break; } } switch (name) { case 'cache-set': case 'controller-render-meta': case 'request-end': case 'websocket-begin': case 'websocket-end': case 'request-begin': case 'upload-begin': case 'upload-end': OBSOLETE(name, 'Name of event has been replaced to "{0}"'.format(name.replace(/-/g, '_'))); break; case 'cache-expire': OBSOLETE(name, 'Name of event has been replaced to "cache_expired"'); break; } if (isWORKER && name === 'service' && !F.cache.interval) F.cache.init_timer(); if (F.$events[name]) F.$events[name].push(fn); else F.$events[name] = [fn]; return F; }; global.EMIT = F.emit = function(name, a, b, c, d, e, f, g) { var evt = F.$events[name]; if (evt) { var clean = false; for (var i = 0, length = evt.length; i < length; i++) { if (evt[i].$once) clean = true; evt[i].call(F, a, b, c, d, e, f, g); } if (clean) { evt = evt.remove(n => n.$once); if (evt.length) F.$events[name] = evt; else F.$events[name] = undefined; } } return F; }; global.ONCE = F.once = function(name, fn) { fn.$once = true; return F.on(name, fn); }; F.removeListener = function(name, fn) { var evt = F.$events[name]; if (evt) { evt = evt.remove(n => n === fn); if (evt.length) F.$events[name] = evt; else F.$events[name] = undefined; } return F; }; F.removeAllListeners = function(name) { if (name) F.$events[name] = undefined; else F.$events = {}; return F; }; /** * Internal function * @return {String} Returns current (dependency type and name) owner. */ F.$owner = function() { return _owner; }; F.isSuccess = function(obj) { return obj === SUCCESSHELPER; }; F.convert = function(value, convertor) { if (convertor) { if (F.convertors.findIndex('name', value) !== -1) { if (convertor == null) F.convertors = F.convertors.remove('name', value); return false; } if (convertor === Number) convertor = U.parseFloat; else if (convertor === Boolean) convertor = U.parseBoolean; else if (typeof(convertor) === 'string') { switch (convertor.toLowerCase()) { case 'json': convertor = U.parseJSON; break; case 'float': case 'number': case 'double': convertor = U.parseFloat; break; case 'int': case 'integer': convertor = U.parseInt2; break; default: return console.log('Unknown convertor type:', convertor); } } F.convertors.push({ name: value, convertor: convertor }); F._length_convertors = F.convertors.length; return true; } if (value) { for (var i = 0, length = F.convertors.length; i < length; i++) { if (value[F.convertors[i].name] != null) value[F.convertors[i].name] = F.convertors[i].convertor(value[F.convertors[i].name]); } } return value; }; /** * Get a controller * @param {String} name * @return {Object} */ F.controller = function(name) { return F.controllers[name] || null; }; /** * Use configuration * @param {String} filename * @return {Framework} */ F.useConfig = function(name) { OBSOLETE('F.useConfig', 'F.useConfig will be moreved in Total.js v4'); return F.$configure_configs(name, true); }; Mail.use = function(smtp, options, callback) { if (typeof(options) === 'function') { callback = options; options = undefined; } Mail.try(smtp, options, function(err) { if (!err) { delete F.temporary.mail_settings; CONF.mail_smtp = smtp; CONF.mail_smtp_options = options; } if (callback) callback(err); else if (err) F.error(err, 'F.useSMTP()', null); }); }; F.useSMTP = function(smtp, options, callback) { OBSOLETE('F.useSMTP', 'Use `Mail.use() instead of F.useSMTP()'); Mail.use(smtp, options, callback); return F; }; /** * Sort all routes * @return {Framework} */ F.$routesSort = function(type) { F.routes.web.sort((a, b) => a.priority > b.priority ? -1 : a.priority < b.priority ? 1 : 0); F.routes.websockets.sort((a, b) => a.priority > b.priority ? -1 : a.priority < b.priority ? 1 : 0); var cache = {}; var length = F.routes.web.length; var url; for (var i = 0; i < length; i++) { var route = F.routes.web[i]; var name = F.temporary.internal[route.controller]; if (name) route.controller = name; if (!route.isMOBILE || route.isUPLOAD || route.isXHR || route.isJSON || route.isSYSTEM || route.isXML || route.flags.indexOf('get') === -1) continue; url = route.url.join