total5 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js ADDED
@@ -0,0 +1,2851 @@
1
+ // Total.js framework
2
+ // The MIT License
3
+ // Copyright 2012-2023 (c) Peter Širka <petersirka@gmail.com>
4
+
5
+ 'use strict';
6
+
7
+ const NODE_MODULES = { buffer: 1, child_process: 1, process: 1, fs: 1, events: 1, http: 1, https: 1, http2: 1, util: 1, net: 1, os: 1, path: 1, punycode: 1, readline: 1, repl: 1, stream: 1, string_decoder: 1, tls: 1, trace_events: 1, tty: 1, dgram: 1, url: 1, v8: 1, vm: 1, wasi: 1, worker_threads: 1, zlib: 1, crypto: 1, dns: 1 };
8
+ const EMPTYOBJECT = {};
9
+ const EMPTYARRAY = [];
10
+
11
+ const REG_SKIPERRORS = /epipe|invalid\sdistance|err_ipc_channel_closed/i;
12
+ const REG_HTTPHTTPS = /^(http|https):\/\//i;
13
+ const SOCKETWINDOWS = '\\\\?\\pipe';
14
+ const CLUSTER_STATS = { TYPE: 'stats' };
15
+ const IGNORE_AUDIT = { password: 1, token: 1, accesstoken: 1, access_token: 1, pin: 1 };
16
+
17
+ var CONCAT = new Array(2);
18
+
19
+ Object.freeze(EMPTYOBJECT);
20
+ Object.freeze(EMPTYARRAY);
21
+
22
+ // Globals
23
+ global.F = global.Total = {};
24
+ global.DEBUG = true;
25
+ global.CONF = {};
26
+ global.REPO = {};
27
+ global.MAIN = {};
28
+ global.TEMP = {};
29
+ global.FUNC = {};
30
+ global.EMPTYOBJECT = EMPTYOBJECT;
31
+ global.EMPTYARRAY = EMPTYARRAY;
32
+ global.NOW = new Date();
33
+ global.DEF = {};
34
+
35
+ (function(F) {
36
+
37
+ F.id = '';
38
+ F.clusterid = '';
39
+ F.is5 = F.version = 5000;
40
+ F.isBundle = false;
41
+ F.isLoaded = false;
42
+ F.version_header = '5';
43
+ F.version_node = process.version + '';
44
+ F.EMPTYOBJECT = EMPTYOBJECT;
45
+ F.EMPTYARRAY = EMPTYARRAY;
46
+
47
+ F.resources = {}; // Loaded resources
48
+ F.connections = {}; // WebSocket connections
49
+ F.schedules = {}; // Registered schedulers
50
+ F.modules = {};
51
+ F.plugins = {};
52
+ F.actions = {};
53
+ F.apiservices = {};
54
+ F.processing = {};
55
+ F.transformations = {};
56
+ F.consumption = {};
57
+ F.flowstreams = {};
58
+ F.filestorages = {};
59
+ F.jsonschemas = {};
60
+ F.querybuilders = {};
61
+ F.openclients = {};
62
+ F.nodemodules = {};
63
+ F.workers = {};
64
+ F.config = CONF;
65
+ F.def = DEF;
66
+ F.repo = REPO;
67
+ F.timeouts = [];
68
+ F.errors = [];
69
+ F.paused = [];
70
+ F.crons = [];
71
+
72
+ F.internal = {
73
+ ticks: 0,
74
+ counter: 0,
75
+ uid: 1,
76
+ interval: null // setInterval identifier
77
+ };
78
+
79
+ F.routes = {
80
+ fallback: {},
81
+ virtual: {},
82
+ api: {},
83
+ routes: [],
84
+ routescache: {},
85
+ websockets: [],
86
+ websocketscache: {},
87
+ files: [],
88
+ filescache: {},
89
+ timeout: null,
90
+ middleware: {},
91
+ imagesmiddleware: {},
92
+ proxies: []
93
+ };
94
+
95
+ // Internal cache
96
+ F.temporary = {
97
+ path: {},
98
+ actions: {},
99
+ cache: {},
100
+ notfound: {},
101
+ processing: {},
102
+ views: {},
103
+ viewscache: [],
104
+ directories: {},
105
+ versions: {},
106
+ dependencies: {}, // temporary for module dependencies
107
+ other: {},
108
+ cryptokeys: {}, // for crypto keys
109
+ internal: {}, // controllers/modules names for the routing
110
+ ready: {},
111
+ ddos: {},
112
+ service: { redirect: 0, request: 0, file: 0, usage: 0 },
113
+ pending: [],
114
+ tmp: {},
115
+ merged: {},
116
+ minified: {},
117
+ tmsblocked: {},
118
+ dnscache: {},
119
+ blocked: {},
120
+ bans: {},
121
+ calls: {},
122
+ utils: {},
123
+ mail: {},
124
+ images: {},
125
+ querybuilders: {},
126
+ templates: {},
127
+ smtp: {},
128
+ datetime: {} // date time formatters
129
+ };
130
+
131
+ // Internal stats
132
+ F.stats = {
133
+
134
+ compilation: 0,
135
+ error: 0,
136
+
137
+ performance: {
138
+ publish: 0,
139
+ subscribe: 0,
140
+ calls: 0,
141
+ download: 0,
142
+ upload: 0,
143
+ request: 0,
144
+ message: 0,
145
+ file: 0,
146
+ open: 0,
147
+ online: 0,
148
+ usage: 0,
149
+ mail: 0,
150
+ dbrm: 0,
151
+ dbwm: 0,
152
+ external: 0
153
+ },
154
+
155
+ other: {
156
+ websocketping: 0,
157
+ websocketcleaner: 0,
158
+ obsolete: 0,
159
+ mail: 0
160
+ },
161
+
162
+ request: {
163
+ request: 0,
164
+ external: 0,
165
+ pending: 0,
166
+ web: 0,
167
+ xhr: 0,
168
+ file: 0,
169
+ websocket: 0,
170
+ get: 0,
171
+ options: 0,
172
+ head: 0,
173
+ post: 0,
174
+ put: 0,
175
+ patch: 0,
176
+ upload: 0,
177
+ schema: 0,
178
+ operation: 0,
179
+ blocked: 0,
180
+ 'delete': 0,
181
+ mobile: 0,
182
+ desktop: 0,
183
+ size: 0
184
+ },
185
+ response: {
186
+ ddos: 0,
187
+ html: 0,
188
+ xml: 0,
189
+ json: 0,
190
+ websocket: 0,
191
+ timeout: 0,
192
+ custom: 0,
193
+ binary: 0,
194
+ pipe: 0,
195
+ file: 0,
196
+ image: 0,
197
+ destroy: 0,
198
+ stream: 0,
199
+ streaming: 0,
200
+ text: 0,
201
+ empty: 0,
202
+ redirect: 0,
203
+ forward: 0,
204
+ proxy: 0,
205
+ notmodified: 0,
206
+ sse: 0,
207
+ errorbuilder: 0,
208
+ error400: 0,
209
+ error401: 0,
210
+ error403: 0,
211
+ error404: 0,
212
+ error409: 0,
213
+ error431: 0,
214
+ error500: 0,
215
+ error501: 0,
216
+ error503: 0,
217
+ size: 0
218
+ }
219
+ };
220
+
221
+ F.path = {};
222
+ F.path.root = path => path ? F.path.$join(F.directory, path) : F.directory;
223
+ F.path.logs = path => path ? F.path.$join(F.temporary.directories.logs, path) : F.temporary.directories.logs;
224
+ F.path.public = path => path ? F.path.$join(F.temporary.directories.public, path) : F.temporary.directories.public;
225
+ F.path.private = path => path ? F.path.$join(F.temporary.directories.private, path) : F.temporary.directories.private;
226
+ F.path.databases = path => path ? F.path.$join(F.temporary.directories.databases, path) : F.temporary.directories.databases;
227
+ F.path.plugins = path => path ? F.path.$join(F.temporary.directories.plugins, path) : F.temporary.directories.plugins;
228
+ F.path.templates = path => path ? F.path.$join(F.temporary.directories.templates, path) : F.temporary.directories.templates;
229
+ F.path.flowstreams = path => path ? F.path.$join(F.temporary.directories.flowstreams, path) : F.temporary.directories.flowstreams;
230
+ F.path.modules = path => path ? F.path.$join(F.temporary.directories.modules, path) : F.temporary.directories.modules;
231
+ F.path.directory = (type, path) => path ? F.path.$join(F.temporary.directories[type], path) : F.temporary.directories[type];
232
+ F.path.tmp = F.path.temp = path => path ? F.path.$join(F.temporary.directories.tmp, path) : F.temporary.directories.tmp;
233
+ F.path.exists = (path, callback) => callback ? (F.Fs.lstat(path, (err, stats) => callback(err ? false : true, stats ? stats.size : 0, stats ? stats.isFile() : false))) : new Promise(resolve => F.path.exists(path, resolve));
234
+
235
+ F.path.$join = function(directory, path) {
236
+ var key = '$' + directory;
237
+ if (!F.temporary.path[key])
238
+ F.path.verify(directory);
239
+ return F.Path.join(directory, path || '');
240
+ };
241
+
242
+ F.path.route = function(path, directory = 'root') {
243
+
244
+ // Absolute
245
+ if (path[0] === '~')
246
+ return path.substring(1);
247
+
248
+ // Plugins
249
+ if (path[0] === '_') {
250
+ let tmp = path.substring(1);
251
+ let index = tmp.indexOf('/', 1);
252
+ return F.path.plugins(tmp.substring(0, index) + (directory === 'root' ? '' : ('/' + directory)) + '/' + tmp.substring(index + 2));
253
+ }
254
+
255
+ return F.path[directory](path);
256
+ };
257
+
258
+ F.path.unlink = unlink;
259
+ F.path.rmdir = rmdir;
260
+ F.path.verify = function(path) {
261
+
262
+ var key = '$verify' + path;
263
+
264
+ if (F.temporary.path[key])
265
+ return;
266
+
267
+ F.path.mkdir(path);
268
+ F.temporary.path[key] = true;
269
+ };
270
+
271
+ F.path.mkdir = function(path) {
272
+ try {
273
+ if (!pathexists(path))
274
+ F.Fs.mkdirSync(path, { recursive: true });
275
+ } catch (e) {}
276
+ };
277
+
278
+ })(global.F);
279
+
280
+ function mailsendforce(message) {
281
+ message.send2();
282
+ }
283
+
284
+ function pathexists(filename, isfile) {
285
+ try {
286
+ var val = F.Fs.statSync(filename);
287
+ return val ? (isfile ? val.isFile() : true) : false;
288
+ } catch (e) {
289
+ return false;
290
+ }
291
+ }
292
+
293
+ function rmdir(arr, callback) {
294
+
295
+ if (typeof(arr) === 'string')
296
+ arr = [arr];
297
+
298
+ if (!arr.length) {
299
+ callback && callback();
300
+ return;
301
+ }
302
+
303
+ var path = arr.shift();
304
+ if (path) {
305
+ F.TUtils.ls(path, function(files, directories) {
306
+ directories.reverse();
307
+ directories.push(path);
308
+ files.wait((item, next) => F.Fs.unlink(item, next), function() {
309
+ directories.wait((item, next) => F.Fs.rmdir(item, next), () => rmdir(arr, callback));
310
+ });
311
+ });
312
+ } else if (callback)
313
+ callback();
314
+ }
315
+
316
+ function unlink(arr, callback) {
317
+
318
+ if (typeof(arr) === 'string')
319
+ arr = [arr];
320
+
321
+ if (!arr.length) {
322
+ callback && callback();
323
+ return;
324
+ }
325
+
326
+ var filename = arr.shift();
327
+ if (filename)
328
+ F.Fs.unlink(filename, () => unlink(arr, callback));
329
+ else if (callback)
330
+ callback();
331
+ }
332
+
333
+ (function(CONF) {
334
+
335
+ CONF.name = 'Total.js';
336
+ CONF.version = '1.0.0';
337
+ CONF.author = '';
338
+ CONF.secret = F.syshash;
339
+ CONF.secret_encryption = '';
340
+ CONF.secret_totalapi = '';
341
+ CONF.secret_csrf = '';
342
+ CONF.secret_tapi = '';
343
+ CONF.secret_tms = '';
344
+
345
+ // New internal configuration
346
+ CONF.$root = '';
347
+ CONF.$cors = ''; // hostnames separated by comma
348
+ CONF.$api = '/api/'; // a default API endpoint
349
+ CONF.$sourcemap = true;
350
+ CONF.$httpreqlimit = 0; // request limit per ip
351
+ CONF.$httpcompress = true;
352
+ CONF.$httpetag = '';
353
+ CONF.$httpmaxsize = 256; // kB
354
+ CONF.$httprangebuffer = 5120; // 5 MB
355
+ CONF.$httptimeout = 5; // 5 seconds
356
+ CONF.$httpfiles = { flac: true, jpg: true, jpeg: true, png: true, gif: true, ico: true, wasm: 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, ui: true, md: true, m4v: true, jsx: true, heif: true, heic: true, ics: true, ts: true, m3u8: true, wav: true, xsd: true, xsl: true, xslt: true, ipynb: true, ijsnb: true };
357
+ CONF.$httpchecktypes = true; // for multipart data only
358
+ CONF.$httpmaxage = 60; // in seconds
359
+ CONF.$httpmaxkeys = 33;
360
+ CONF.$httpmaxkey = 25;
361
+ CONF.$blacklist = '';
362
+ CONF.$xpoweredby = 'Total.js';
363
+ CONF.$maxopenfiles = 100;
364
+ CONF.$minifyjs = true;
365
+ CONF.$minifycss = true;
366
+ CONF.$minifyhtml = true;
367
+ CONF.$localize = true;
368
+ CONF.$port = 'auto';
369
+ CONF.$ip = '0.0.0.0';
370
+ CONF.$unixsocket = '';
371
+ CONF.$timezone = 'utc';
372
+ CONF.$insecure = false;
373
+ CONF.$performance = false;
374
+ CONF.$filtererrors = true;
375
+ CONF.$cleartemp = true;
376
+ CONF.$customtitles = false;
377
+ CONF.$version = '';
378
+ CONF.$clearcache = 10;
379
+ CONF.$imageconverter = 'gm';
380
+ CONF.$imagememory = 0; // disabled because e.g. GM v1.3.32 throws some error about the memory
381
+ CONF.$stats = true;
382
+
383
+ CONF.$npmcache = '/var/www/.npm';
384
+ CONF.$python = 'python3';
385
+ CONF.$wsmaxsize = 256; // kB
386
+ CONF.$wscompress = true;
387
+ CONF.$wsencodedecode = false;
388
+ CONF.$wsmaxlatency = 2000;
389
+ CONF.$proxytimeout = 5; // 5 seconds
390
+ // CONF.$proxyrequest = '';
391
+ CONF.$cookiesamesite = 'Lax';
392
+ CONF.$cookiesecure = false;
393
+ CONF.$csrfexpiration = '30 minutes';
394
+
395
+ CONF.$tapi = true;
396
+ CONF.$tapiurl = 'eu';
397
+ CONF.$tapimail = false;
398
+ CONF.$tapilogger = false;
399
+ CONF.$imprint = true;
400
+
401
+ CONF.$tms = false;
402
+ CONF.$tmsmaxsize = 256; // kB
403
+ CONF.$tmsurl = '/$tms/';
404
+ CONF.$tmsclearblocked = 60; // in minutes
405
+
406
+ process.env.TZ = CONF.$timezone;
407
+
408
+ })(global.CONF);
409
+
410
+ (function(DEF) {
411
+
412
+ DEF.onSuccess = function(value) {
413
+ return { success: true, value: value };
414
+ };
415
+
416
+ DEF.onCSRFcreate = function(ctrl) {
417
+ var data = [ctrl.ip, (ctrl.headers['user-agent'] || '').hash(true), NOW.add(F.config.$csrfexpiration).getTime()];
418
+ return F.config.secret_csrf ? JSON.stringify(data).encrypt(F.config.secret_csrf) : '';
419
+ };
420
+
421
+ DEF.onCSRFcheck = function(ctrl) {
422
+ if (F.config.secret_csrf) {
423
+ var token = ctrl.headers['x-csrf-token'] || ctrl.query.csrf;
424
+ var is = false;
425
+ if (token && token.length > 10) {
426
+ var data = token.decrypt(F.config.secret_csrf);
427
+ if (data)
428
+ data = data.parseJSON();
429
+ is = data && data[0] === ctrl.ip && data[2] >= NOW.getTime() && data[1] === (ctrl.headers['user-agent'] || '').hash(true) ? true : false;
430
+ }
431
+ return is;
432
+ }
433
+ return true;
434
+ };
435
+
436
+ DEF.onAudit = function(name, data) {
437
+ F.stats.performance.open++;
438
+ data.dtcreated = NOW = new Date();
439
+ F.Fs.appendFile(F.path.logs((name || 'audit') + '.log'), JSON.stringify(data) + '\n', NOOP);
440
+ };
441
+
442
+ DEF.onMail = function(email, subject, body, callback, reply) {
443
+
444
+ var tmp;
445
+
446
+ if (typeof(callback) === 'string') {
447
+ tmp = reply;
448
+ reply = callback;
449
+ callback = tmp;
450
+ }
451
+
452
+ var msg = new F.TMail.Message(subject, body);
453
+
454
+ if (email.indexOf(',') !== -1)
455
+ email = email.split(',').trim();
456
+
457
+ if (email instanceof Array) {
458
+ for (let m of email)
459
+ msg.to(m);
460
+ } else
461
+ msg.to(email);
462
+
463
+ msg.from(F.config.mail_from || F.config.smtp.from || F.config.smtp.user);
464
+ callback && msg.callback(callback);
465
+
466
+ if (reply)
467
+ msg.reply(reply);
468
+ else {
469
+ tmp = F.config.mail_reply;
470
+ if (tmp && tmp.length > 3)
471
+ msg.reply(tmp);
472
+ }
473
+
474
+ tmp = F.config.mail_cc;
475
+ if (tmp && tmp.length > 3)
476
+ msg.cc(tmp);
477
+
478
+ tmp = F.config.mail_bcc;
479
+ if (tmp && tmp.length > 3)
480
+ msg.bcc(tmp);
481
+
482
+ msg.$sending = setImmediate(mailsendforce, msg);
483
+ return msg;
484
+ };
485
+
486
+ DEF.onViewCompile = function(name, html) {
487
+ return html;
488
+ };
489
+
490
+ DEF.onError = function(err, name, url) {
491
+
492
+ NOW = new Date();
493
+
494
+ if (err instanceof F.TBuilders.ErrorBuilder) {
495
+ if (!name)
496
+ name = err[0].name;
497
+ } else if (!name && err.name)
498
+ name = err.name;
499
+
500
+ err = err.toString();
501
+ console.log('ERROR ======= ' + (NOW.format('yyyy-MM-dd HH:mm:ss')) + ': ' + (name ? name + ' ---> ' : '') + err + (url ? (' (' + url + ')') : ''), err.stack ? err.stack : '');
502
+
503
+ var obj = { error: err, name: name, url: url, date: NOW };
504
+
505
+ if (F.errors.push(obj) > 10)
506
+ F.errors.shift();
507
+
508
+ F.$events.error && F.emit('error', obj);
509
+ F.stats.error++;
510
+ };
511
+
512
+ DEF.helpers = {};
513
+ DEF.currencies = {};
514
+
515
+ DEF.parsers = {};
516
+ DEF.parsers.json = value => value.parseJSON(true);
517
+ DEF.parsers.urlencoded = value => value.parseEncoded();
518
+
519
+ // Unused
520
+ DEF.parsers.xml = value => value.parseXML(true);
521
+
522
+ // Validators
523
+ DEF.validators = {
524
+ email: new RegExp('^[a-zA-Z0-9-_.+]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'),
525
+ url: /^http(s)?:\/\/[^,{}\\]*$/i,
526
+ phone: /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,8}$/im,
527
+ zip: /^[0-9a-z\-\s]{3,20}$/i,
528
+ 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|^[0-9a-zA-Z]{5,10}\d{1}[01]{1}f|^[0-9a-zA-Z]{10}[A-J]{1}r$/,
529
+ xss: /<.*>/,
530
+ sqlinjection: /'(''|[^'])*'|\b(ALTER|CREATE|DELETE|DROP|EXEC(UTE){0,1}|INSERT( +INTO){0,1}|MERGE|SELECT|UPDATE|UNION( +ALL){0,1})\b/
531
+ };
532
+
533
+ })(global.DEF);
534
+
535
+ F.loadconfig = function(value) {
536
+
537
+ var cfg = F.TUtils.parseConfig(value);
538
+ var smtp = null;
539
+
540
+ for (let key in cfg) {
541
+
542
+ let val = cfg[key];
543
+ let tmp;
544
+
545
+ switch (key) {
546
+ case 'totalapi':
547
+ key = '$tapi';
548
+ break;
549
+ case '$tms':
550
+ break;
551
+ case 'smtp':
552
+ case 'mail':
553
+ if (typeof(val) === 'string')
554
+ val = new Function('return ' + val)();
555
+ smtp = val || {};
556
+ if (!smtp.server)
557
+ smtp.server = smtp.smtp || smtp.host || smtp.hostname || smtp.url;
558
+ break;
559
+ case 'mail_smtp':
560
+ if (!smtp)
561
+ smtp = {};
562
+ smtp.server = val;
563
+ break;
564
+ case 'mail_smtp_options':
565
+
566
+ if (typeof(val) === 'string')
567
+ val = new Function('return ' + val)();
568
+
569
+ if (!smtp)
570
+ smtp = {};
571
+
572
+ for (let k in val)
573
+ smtp[k] = val[k];
574
+
575
+ break;
576
+ case '$cryptoiv':
577
+ cfg[key] = val ? Buffer.from(val, (/[A-Z=\/+]/).test(val) ? 'base64' : 'hex') : null;
578
+ break;
579
+ case '$root':
580
+ cfg[key] = val ? F.TUtils.normalize(val) : '';
581
+ break;
582
+ case 'mail_from':
583
+ break;
584
+ case '$port':
585
+ cfg[key] = +val;
586
+ break;
587
+ case '$timezone':
588
+ process.env.TZ = val;
589
+ break;
590
+ case '$httpfiles':
591
+ tmp = val.split(',').trim();
592
+ for (var m of tmp)
593
+ F.config.$httpfiles[m] = true;
594
+ continue;
595
+ }
596
+
597
+ F.config[key] = cfg[key];
598
+ }
599
+
600
+ if (!F.config.secret_uid)
601
+ F.config.secret_uid = (F.config.name).crc32(true) + '';
602
+
603
+ if (F.config.$performance)
604
+ F.Http.globalAgent.maxSockets = 9999;
605
+
606
+ if (!F.config.$httpetag)
607
+ F.config.$httpetag = F.config.version.replace(/\.|\s/g, '');
608
+
609
+ if (smtp)
610
+ F.config.smtp = smtp;
611
+
612
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = F.config.$insecure ? '0' : '1';
613
+ F.logger(F.config.$logger == true);
614
+ F.dir();
615
+ F.emit('$cors');
616
+ F.emit('$tms');
617
+ F.emit('$reconfigure');
618
+ };
619
+
620
+ F.loadresource = function(name, value) {
621
+
622
+ if (value == null) {
623
+ // download
624
+ RESTBuilder.GET(name).callback(function(err, response) {
625
+
626
+ if (err)
627
+ throw new Error(err.toString());
628
+
629
+ if (response && (response instanceof Array || typeof(response) === 'object')) {
630
+ if (response instanceof Array) {
631
+ for (let item of response)
632
+ F.loadresource(item.id || item.key || item.code || item.language, item.value || item.name || item.text || item.body);
633
+ } else {
634
+ for (let key in response)
635
+ F.loadresource(key, response[key]);
636
+ }
637
+ }
638
+
639
+ });
640
+ return;
641
+ }
642
+
643
+ var lines = value.split('\n');
644
+ var response = {};
645
+
646
+ for (let line of lines) {
647
+
648
+ if (!line || line[0] === '#' || line.substring(0, 2) === '//')
649
+ continue;
650
+
651
+ let index = line.indexOf(':');
652
+ if (index === -1) {
653
+ index = line.indexOf('\t:');
654
+ if (index === -1)
655
+ continue;
656
+ }
657
+
658
+ response[line.substring(0, index).trim()] = line.substring(index + 2).trim();
659
+ }
660
+
661
+ F.resources[name] = response;
662
+ };
663
+
664
+ F.loadenv = function(value) {
665
+ var obj = value.parseEnv();
666
+ for (var key in obj) {
667
+ if (!process.env.hasOwnProperty(key))
668
+ process.env[key] = obj[key];
669
+ }
670
+ };
671
+
672
+ F.translate = function(language, value) {
673
+
674
+ var index = -1;
675
+
676
+ while (true) {
677
+
678
+ index = value.indexOf('@(', index);
679
+
680
+ if (index === -1)
681
+ break;
682
+
683
+ var counter = 0;
684
+ for (let i = index + 2; i < value.length; i++) {
685
+
686
+ var c = value[i];
687
+
688
+ if (c == '(') {
689
+ counter++;
690
+ } else if (c === ')') {
691
+
692
+ if (counter) {
693
+ counter--;
694
+ continue;
695
+ }
696
+
697
+ var text = value.substring(index, i + 1);
698
+ var translate = text.substring(2, text.length - 1);
699
+ var translated = F.resource(language, 'T' + translate.hash(true).toString(36));
700
+ value = value.replaceAll(text, translated || translate);
701
+ index += translated.length - 2;
702
+ break;
703
+ }
704
+ }
705
+ }
706
+
707
+ return value;
708
+ };
709
+
710
+ F.resource = function(language, key) {
711
+ var dict = F.resources[language];
712
+ if (dict && dict[key])
713
+ return dict[key];
714
+ return language === 'default' ? '' : F.resource('default', key);
715
+ };
716
+
717
+ F.localize = function(fn) {
718
+ F.def.onLocalize = fn;
719
+ };
720
+
721
+ F.auth = function(fn) {
722
+ if (typeof(fn) === 'object')
723
+ F.TBuilders.builtinauth(fn);
724
+ else
725
+ F.def.onAuthorize = fn;
726
+ };
727
+
728
+ F.load = async function(types, callback) {
729
+
730
+ if (!types)
731
+ types = '';
732
+
733
+ var beg = Date.now();
734
+
735
+ F.dir();
736
+
737
+ await F.TBundles.extract();
738
+ await F.clear(true);
739
+
740
+ process.send && process.send('total:ready');
741
+
742
+ if (typeof(types) === 'string')
743
+ types = types.split(',').trim();
744
+
745
+ var list = async (path, extension = 'js') => new Promise(resolve => F.TUtils.ls(path, files => resolve(files), (path, isdir) => isdir ? true : (path.indexOf('-bk') === -1 && path.indexOf('_bk') === -1 && F.TUtils.getExtension(path) === extension)));
746
+ var read = async (path) => new Promise(resolve => F.Fs.readFile(path, 'utf8', (err, response) => resolve(response ? response : '')));
747
+
748
+ var update = function(type, arr) {
749
+ for (let i = 0; i < arr.length; i++) {
750
+ let id = '';
751
+ if (type === 'modules')
752
+ id = F.TUtils.getName(arr[i]).replace(/\.js$/, '');
753
+ arr[i] = { id: id, type: type, filename: arr[i] };
754
+ }
755
+ return arr;
756
+ };
757
+
758
+ if (types.length && !types.includes('stats')) {
759
+ F.config.$stats = false;
760
+ F.config.$sourcemap = false;
761
+ } else
762
+ F.config.$sourcemap = DEBUG;
763
+
764
+ if (!types.length || types.includes('env')) {
765
+ let env = await read(F.path.root('.env'));
766
+ env && F.loadenv(env);
767
+ }
768
+
769
+ if (!types.length || types.includes('config')) {
770
+ let config = await read(F.path.root('config'));
771
+ config && F.loadconfig(config);
772
+ }
773
+
774
+ if (!types.length || types.includes('resources')) {
775
+ let resources = await list(F.path.root('resources'), 'resource');
776
+ for (let resource of resources)
777
+ F.loadresource(F.TUtils.getName(resource).replace(/\.resource$/i, ''), await read(resource));
778
+ }
779
+
780
+ if (!types.length || types.includes('jsonschemas')) {
781
+ let jsonschemas = await list(F.path.root('jsonschemas'), 'json');
782
+ for (let jsonschema of jsonschemas) {
783
+ let json = await read(jsonschema);
784
+ json = json.parseJSON();
785
+ json && F.newjsonschema(F.TUtils.getName(jsonschema).replace(/\.json$/i, ''), json);
786
+ }
787
+ jsonschemas = await list(F.path.root('jsonschemas'), 'txt');
788
+ for (let jsonschema of jsonschemas) {
789
+ let txt = await read(jsonschema);
790
+ txt && F.newjsonschema(F.TUtils.getName(jsonschema).replace(/\.txt$/i, ''), txt);
791
+ }
792
+ }
793
+
794
+ let loader = ['modules', 'actions', 'schemas', 'models', 'definitions', 'controllers', 'middleware', 'sources'];
795
+ var files = [];
796
+ var tmp;
797
+
798
+ for (let type of loader) {
799
+ if (!types.length || types.includes(type)) {
800
+ tmp = await list(F.path.root(type), type === 'flowstreams' ? 'flow' : 'js');
801
+ if (tmp.length)
802
+ files.push.apply(files, update(type, tmp));
803
+ }
804
+ }
805
+
806
+ if (!types.length || types.includes('plugins')) {
807
+ var plugins = async () => new Promise(resolve => F.Fs.readdir(F.path.directory('plugins'), (err, response) => resolve(response || [])));
808
+ tmp = await plugins();
809
+
810
+ for (let plugin of tmp) {
811
+
812
+ if (plugin.indexOf('-bk') !== -1 || plugin.indexOf('_bk') !== -1)
813
+ continue;
814
+
815
+ files.push({ id: F.TUtils.getName(plugin).replace(/\.js$/, ''), type: 'plugins', filename: F.path.directory('plugins', plugin + '/index.js') });
816
+
817
+ let loader = ['controllers', 'actions', 'schemas', 'models', 'definitions', 'sources', 'flowstreams', 'middleware'];
818
+ for (let type of loader) {
819
+ tmp = await list(F.path.root('plugins/' + plugin + '/' + type), type === 'flowstreams' ? 'flow' : 'js');
820
+ if (tmp.length)
821
+ files.push.apply(files, update(type, tmp));
822
+ }
823
+ }
824
+ }
825
+
826
+ files.sort(function(a) {
827
+
828
+ if (a.type === 'middleware')
829
+ return 1;
830
+
831
+ if (a.type === 'middleware')
832
+ return -1;
833
+
834
+ return 0;
835
+ });
836
+
837
+ for (let file of files) {
838
+
839
+ let tmp = null;
840
+
841
+ switch (file.type) {
842
+ case 'modules':
843
+ tmp = require(file.filename);
844
+
845
+ if (!tmp.id)
846
+ tmp.id = file.id;
847
+
848
+ if (tmp.id)
849
+ F.modules[tmp.id] = tmp;
850
+
851
+ tmp.install && tmp.install();
852
+ break;
853
+
854
+ case 'plugins':
855
+ tmp = require(file.filename);
856
+ F.plugins[file.id] = tmp;
857
+ if (!tmp.id)
858
+ tmp.id = file.id;
859
+ tmp.install && tmp.install();
860
+ break;
861
+
862
+ case 'controllers':
863
+ case 'schemas':
864
+ case 'actions':
865
+ case 'models':
866
+ case 'definitions':
867
+ case 'middleware':
868
+ tmp = require(file.filename);
869
+ tmp.install && tmp.install();
870
+ break;
871
+ }
872
+ }
873
+
874
+ if (!types.length || types.includes('flowstreams'))
875
+ F.TFlow.init();
876
+
877
+ if (!types.length || types.includes('stats'))
878
+ F.loadstats();
879
+
880
+ F.loadservices();
881
+ F.stats.compilation = Date.now() - beg;
882
+ F.stats.compiled = files.length;
883
+ F.isLoaded = true;
884
+ DEBUG && F.TSourceMap.refresh();
885
+ callback && callback();
886
+
887
+ F.emit('ready');
888
+ F.emit('load');
889
+ };
890
+
891
+ F.require = function(name) {
892
+
893
+ if (name.startsWith('node:'))
894
+ return require(name);
895
+
896
+ if (NODE_MODULES[name])
897
+ return require('node:' + name);
898
+
899
+ let mod = null;
900
+
901
+ try {
902
+ mod = require(name);
903
+ } catch (e) {
904
+ mod = require(F.Path.join(F.config.$nodemodules, name));
905
+ }
906
+
907
+ if (!mod)
908
+ throw new Error('NPM module "' + name + '" not found');
909
+
910
+ return mod;
911
+ };
912
+
913
+ F.runscript = function(filename) {
914
+ F.Fs.readFile(filename || PATH.root('debug.js'), function(err, data) {
915
+ if (data) {
916
+ var scr = data.toString('utf8').trim();
917
+ var fn;
918
+ if (data) {
919
+ try {
920
+ fn = new Function('require', scr);
921
+ } catch (e) {
922
+ console.error(e);
923
+ }
924
+ fn && fn(require);
925
+ }
926
+ }
927
+ });
928
+ };
929
+
930
+ F.import = function(url, callback) {
931
+
932
+ if (callback == null)
933
+ return new Promise((resolve, reject) => F.import(url, (err, response) => err ? reject(err) : resolve(response)));
934
+
935
+ var filename = F.path.tmp(F.clusterid + url.makeid() + '.js');
936
+
937
+ if (F.temporary.dependencies[url]) {
938
+ callback && callback(null, require(filename));
939
+ return;
940
+ }
941
+
942
+ F.download(url, filename, function(err, response) {
943
+ var m;
944
+ if (!err) {
945
+ m = require(filename);
946
+ F.temporary.dependencies[url] = 1;
947
+ }
948
+ callback && callback(err, m, response);
949
+ });
950
+ };
951
+
952
+ F.download = function(url, filename, callback, timeout) {
953
+
954
+ if (!callback)
955
+ return new Promise((resolve, reject) => F.download(url, filename, (err, response) => err ? reject(err) : resolve(response), timeout));
956
+
957
+ var opt = {};
958
+
959
+ if (typeof(url) === 'object')
960
+ opt.unixsocket = url;
961
+ else
962
+ opt.url = url;
963
+
964
+ opt.custom = true;
965
+ opt.resolve = true;
966
+ opt.timeout = timeout;
967
+ opt.callback = function(err, response) {
968
+
969
+ if (response)
970
+ response.filename = filename;
971
+
972
+ if (err) {
973
+ callback && callback(err, response);
974
+ callback = null;
975
+ return;
976
+ }
977
+
978
+ var stream = F.Fs.createWriteStream(filename);
979
+
980
+ var done = function(err) {
981
+ if (callback) {
982
+ callback(err, response);
983
+ callback = null;
984
+ }
985
+ };
986
+
987
+ response.stream.pipe(stream);
988
+ response.stream.on('error', done);
989
+ stream.on('error', done);
990
+ F.cleanup(stream, done);
991
+ };
992
+
993
+ REQUEST(opt);
994
+ };
995
+
996
+ F.cleanup = function(stream, callback) {
997
+
998
+ if (!callback)
999
+ return new Promise(resolve => F.cleanup(stream, resolve));
1000
+
1001
+ F.TUtils.onfinished(stream, function() {
1002
+ F.TUtils.destroystream(stream);
1003
+ if (callback) {
1004
+ callback();
1005
+ callback = null;
1006
+ }
1007
+ });
1008
+ };
1009
+
1010
+ F.python = function(filename, callback) {
1011
+ if (!callback)
1012
+ return new Promise((resolve, reject) => F.python(filename, (err, response) => err ? reject(err) : response));
1013
+ F.Child.exec(F.config.$python + ' ' + filename, { cwd: F.Path.dirname(filename) }, callback);
1014
+ };
1015
+
1016
+ F.pipinstall = function(name, callback) {
1017
+
1018
+ if (!callback)
1019
+ return new Promise((resolve, reject) => F.npminstall(name, err => err ? reject(err) : resolve()));
1020
+
1021
+ var args = {};
1022
+ args.cwd = F.directory;
1023
+ F.Child.exec(F.config.$python + ' -m pip install ' + name, args, function(err, response, output) {
1024
+ callback && callback(err ? (output || err) : null, null);
1025
+ });
1026
+
1027
+ };
1028
+
1029
+ F.npminstall = function(name, callback) {
1030
+
1031
+ if (!callback)
1032
+ return new Promise((resolve, reject) => F.npminstall(name, err => err ? reject(err) : resolve()));
1033
+
1034
+ var path = F.config.$nodemodules;
1035
+ F.path.mkdir(path, true);
1036
+
1037
+ var index = name.lastIndexOf('@');
1038
+ var folder = index === -1 ? name : name.substring(0, index);
1039
+
1040
+ F.Fs.readFile(F.path.join(path, folder, 'package.json'), 'utf8', function(err, response) {
1041
+
1042
+ var is = false;
1043
+
1044
+ if (response) {
1045
+ response = response.parseJSON();
1046
+ is = response && (index === -1 || response.version === name.substring(index + 1));
1047
+ }
1048
+
1049
+ if (is) {
1050
+ callback && callback();
1051
+ } else {
1052
+
1053
+ var args = {};
1054
+
1055
+ if (process.getuid && process.getuid() === 33)
1056
+ args.env = { NPM_CONFIG_CACHE: F.config.$npmcache };
1057
+
1058
+ args.cwd = path;
1059
+
1060
+ F.Child.exec('npm install ' + name, args, function(err, response, output) {
1061
+ callback && callback(err ? (output || err) : null);
1062
+ });
1063
+ }
1064
+ });
1065
+
1066
+ };
1067
+
1068
+ F.shell = function(cmd, callback, cwd) {
1069
+
1070
+ var args = {};
1071
+
1072
+ if (typeof(callback) === 'string') {
1073
+ cwd = callback;
1074
+ callback = null;
1075
+ }
1076
+
1077
+ args.cwd = cwd || F.directory;
1078
+
1079
+ if (F.config.$shell)
1080
+ args.shell = F.config.$shell;
1081
+
1082
+ if (callback)
1083
+ F.Child.exec(cmd, args, callback);
1084
+ else
1085
+ return new Promise((resolve, reject) => F.Child.exec(cmd, args, (err, response) => err ? reject(err) : resolve(response)));
1086
+ };
1087
+
1088
+ F.console = function() {
1089
+
1090
+ if (!F.config.$imprint)
1091
+ return;
1092
+
1093
+ var memory = process.memoryUsage();
1094
+ var nodemodules = require.resolve('./index');
1095
+
1096
+ nodemodules = nodemodules.substring(0, nodemodules.length - (8 + 7));
1097
+
1098
+ print('====================================================');
1099
+ print('PID : ' + process.pid);
1100
+ print('Node.js : ' + process.version);
1101
+ print('Total.js : v' + F.version);
1102
+ print('OS : ' + F.Os.platform() + ' ' + F.Os.release());
1103
+ print('Memory : ' + memory.heapUsed.filesize(2) + ' / ' + memory.heapTotal.filesize(2));
1104
+ print('User : ' + F.Os.userInfo().username);
1105
+ print('====================================================');
1106
+ print('Name : ' + F.config.name);
1107
+ print('Version : ' + F.config.version);
1108
+ F.config.author && print('Author : ' + F.config.author);
1109
+ print('Date ({0}) : '.format(process.env.TZ) + NOW.format('yyyy-MM-dd HH:mm:ss'));
1110
+ print('Mode : ' + (DEBUG ? 'debug' : 'release'));
1111
+ print('Compiled : ' + F.stats.compiled + ' files (' + F.stats.compilation + 'ms)');
1112
+ // F.threads && print('Threads : ' + Object.keys(F.threads).join(', '));
1113
+ // global.THREAD && print('Thread : ' + global.THREAD);
1114
+ print('====================================================');
1115
+ F.config.$root && print('Root : ' + F.config.$root);
1116
+ print('Directory : ' + process.cwd());
1117
+ print('node_modules : ' + nodemodules);
1118
+ print('====================================================\n');
1119
+
1120
+ if (!F.isWorker && F.server) {
1121
+
1122
+ var hostname = F.unixsocket ? ('Socket: ' + F.unixsocket) : '{2}://{0}:{1}/'.format(F.config.$ip, F.config.$port, F.isHTTPS ? 'https' : 'http');
1123
+
1124
+ if (!F.unixsocket && F.ip === '0.0.0.0') {
1125
+ var ni = F.Os.networkInterfaces();
1126
+ if (ni.en0) {
1127
+ for (var i = 0; i < ni.en0.length; i++) {
1128
+ var nii = ni.en0[i];
1129
+ // nii.family === 'IPv6' ||
1130
+ if (nii.family === 'IPv4') {
1131
+ hostname += '\n{2}://{0}:{1}/'.format(nii.address, F.port, F.isHTTPS ? 'https' : 'http');
1132
+ break;
1133
+ }
1134
+ }
1135
+ }
1136
+ }
1137
+
1138
+ print(hostname);
1139
+ print('');
1140
+ }
1141
+ };
1142
+
1143
+ F.loadservices = function() {
1144
+
1145
+ F.internal.interval && clearInterval(F.internal.interval);
1146
+
1147
+ // This timer solving timeouts
1148
+ F.internal.interval = setInterval(function() {
1149
+
1150
+ F.internal.ticks++;
1151
+ global.NOW = new Date();
1152
+
1153
+ for (let key in F.flowstreams)
1154
+ F.flowstreams[key].service(F.internal.ticks);
1155
+
1156
+ if (F.internal.ticks == 6 || F.internal.ticks == 12)
1157
+ F.TWebSocket.ping();
1158
+
1159
+ // 1 minute
1160
+ if (F.internal.ticks == 12) {
1161
+ F.internal.ticks = 0;
1162
+ F.internal.counter++;
1163
+ F.service(F.internal.counter);
1164
+ F.$events.service && F.emit('service', F.internal.counter);
1165
+ }
1166
+
1167
+ F.TFlow.ping();
1168
+
1169
+ if (!F.temporary.pending.length) {
1170
+ F.stats.request.pending = 0;
1171
+ return;
1172
+ }
1173
+
1174
+ let index = 0;
1175
+
1176
+ while (true) {
1177
+ let ctrl = F.temporary.pending[index];
1178
+ if (ctrl) {
1179
+ if (ctrl.destroyed || ctrl.res.headersSent || ctrl.res.writableEnded) {
1180
+ F.temporary.pending.splice(index, 1);
1181
+ } else if (ctrl.timeout <= 0) {
1182
+
1183
+ F.stats.response.timeout++;
1184
+
1185
+ if (F.timeouts.push((NOW = new Date()).toJSON() + ' ' + ctrl.url) > 5)
1186
+ F.timeouts.shift();
1187
+
1188
+ ctrl.fallback(408);
1189
+ F.temporary.pending.splice(index, 1);
1190
+ } else {
1191
+ F.stats.request.pending++;
1192
+ ctrl.timeout -= 5; // 5 seconds
1193
+ index++;
1194
+ }
1195
+ } else
1196
+ break;
1197
+ }
1198
+
1199
+ F.stats.request.pending = F.temporary.pending.length;
1200
+
1201
+ }, 5000);
1202
+
1203
+ };
1204
+
1205
+ F.http = function(opt) {
1206
+
1207
+ if (!opt)
1208
+ opt = {};
1209
+
1210
+ // opt.unixsocket {String}
1211
+ // opt.ip {String}
1212
+ // opt.port {Number}
1213
+
1214
+ // opt.load {String}
1215
+ // config, env, modules, controllers, actions, schemas, models, definitions, sources, middleware, resources, plugins, stats
1216
+ // none - loads only web server
1217
+
1218
+ if (F.isLoaded) {
1219
+ F.httpload(opt);
1220
+ return;
1221
+ }
1222
+
1223
+ if (opt.config) {
1224
+ let cfg = [];
1225
+ for (let key in opt.config)
1226
+ cfg.push({ id: key, value: opt.config[key] });
1227
+ F.loadconfig(cfg);
1228
+ }
1229
+
1230
+ F.load(opt.load || opt.type || '', () => F.httpload(opt));
1231
+ };
1232
+
1233
+ F.httpload = function(opt) {
1234
+
1235
+ if (F.server) {
1236
+ F.server.close(function() {
1237
+ F.server = null;
1238
+ F.httpload(opt);
1239
+ });
1240
+ return;
1241
+ }
1242
+
1243
+ F.server = F.Http.createServer(F.THttp.listen);
1244
+ F.server.on('upgrade', F.TWebSocket.listen);
1245
+
1246
+ var unixsocket = opt.unixsocket || F.config.$unixsocket;
1247
+ if (unixsocket) {
1248
+
1249
+ try {
1250
+ F.Fs.unlinkSync(unixsocket);
1251
+ } catch (e) {}
1252
+
1253
+ if (F.isWindows && unixsocket.indexOf(SOCKETWINDOWS) === -1)
1254
+ unixsocket = F.Path.join(SOCKETWINDOWS, unixsocket);
1255
+
1256
+ F.config.$unixsocket = F.unixsocket = unixsocket;
1257
+
1258
+ var listen = function(count) {
1259
+ F.server.listen(unixsocket, function() {
1260
+
1261
+ // Check if the socket exists
1262
+ if (F.isWindows)
1263
+ return;
1264
+
1265
+ F.Fs.lstat(unixsocket, function(err) {
1266
+
1267
+ if (count > 9)
1268
+ throw new Error('HTTP server can not listen the path "{0}"'.format(unixsocket));
1269
+
1270
+ if (err)
1271
+ setTimeout(listen, 500, count + 1);
1272
+ else if (opt.unixsocket777)
1273
+ F.Fs.chmodSync(unixsocket, 0o777);
1274
+ });
1275
+
1276
+ });
1277
+ };
1278
+
1279
+ listen(1);
1280
+
1281
+ } else {
1282
+
1283
+ if (opt.port)
1284
+ F.config.$port = opt.port;
1285
+
1286
+ if (F.config.$port === 'auto') {
1287
+ let port = process.env.PORT;
1288
+ if (!port) {
1289
+ for (let arg of process.argv) {
1290
+ if ((/^\d{3,5}$/).test(arg)) {
1291
+ port = arg;
1292
+ break;
1293
+ }
1294
+ }
1295
+ }
1296
+ if (port)
1297
+ port = +port;
1298
+ if (isNaN(port))
1299
+ port = 8000;
1300
+ F.config.$port = port;
1301
+ }
1302
+
1303
+ if (opt.ip)
1304
+ F.config.$ip = opt.ip;
1305
+
1306
+ F.server.listen(F.config.$port, F.config.$ip);
1307
+ }
1308
+
1309
+ F.config.$performance && F.server.on('connection', httptuningperformance);
1310
+
1311
+ if (!process.connected && F.console)
1312
+ F.console();
1313
+
1314
+ };
1315
+
1316
+ F.logger = function(enable) {
1317
+
1318
+ if (enable == null)
1319
+ enable = true;
1320
+
1321
+ if (enable) {
1322
+
1323
+ if (console.$backup)
1324
+ return;
1325
+
1326
+ } else {
1327
+
1328
+ if (!console.$backup)
1329
+ return;
1330
+
1331
+ console.log = console.$backup.log;
1332
+ console.warn = console.$backup.warn;
1333
+ console.error = console.$backup.error;
1334
+ console.time = console.$backup.time;
1335
+ console.timeEnd = console.$backup.timeEnd;
1336
+ console.$backup = null;
1337
+ return;
1338
+ }
1339
+
1340
+ var Console = require('node:console').Console;
1341
+
1342
+ var path = F.path.root();
1343
+
1344
+ if (path.substring(path.length - 5, path.length - 1) === '.src')
1345
+ path = F.Path.join(path.substring(0, path.length - 5), 'logs/');
1346
+ else
1347
+ path = F.Path.join(path, 'logs/');
1348
+
1349
+ F.path.mkdir(path);
1350
+
1351
+ var output = F.Fs.createWriteStream(F.Path.join(path, 'debug.log'), { flags: 'a' });
1352
+ var logger = new Console({ stdout: output, stderr: output });
1353
+
1354
+ console.$backup = {};
1355
+ console.$backup.log = console.log;
1356
+ console.$backup.warn = console.warn;
1357
+ console.$backup.error = console.error;
1358
+ console.$backup.time = console.time;
1359
+ console.$backup.timeEnd = console.timeEnd;
1360
+
1361
+ console.log = function() {
1362
+ logger.log.apply(logger, arguments);
1363
+ };
1364
+
1365
+ console.warn = function() {
1366
+ logger.warn.apply(logger, arguments);
1367
+ };
1368
+
1369
+ console.error = function() {
1370
+ logger.error.apply(logger, arguments);
1371
+ };
1372
+
1373
+ console.time = function() {
1374
+ logger.time.apply(logger, arguments);
1375
+ };
1376
+
1377
+ console.timeEnd = function() {
1378
+ logger.timeEnd.apply(logger, arguments);
1379
+ };
1380
+ };
1381
+
1382
+ F.componentator = function(name, components, removeprev = true, attrs = '') {
1383
+
1384
+ if (typeof(removeprev) === 'string') {
1385
+ attrs = removeprev;
1386
+ removeprev = true;
1387
+ }
1388
+
1389
+ var meta = {};
1390
+
1391
+ meta.components = components;
1392
+ meta.name = name;
1393
+
1394
+ F.$events.componentator && F.emit('componentator', meta);
1395
+
1396
+ var url = 'https://componentator.com/download.js?id=' + meta.components + (attrs ? ('&' + attrs) : '');
1397
+ var nameid = meta.name.slug();
1398
+ var relative = 'ui-' + (removeprev ? (nameid + '-') : '') + url.makeid() + '.min.js';
1399
+ var filename = F.path.public(relative);
1400
+
1401
+ F.repo[meta.name] = '/' + relative;
1402
+
1403
+ if (removeprev) {
1404
+ F.Fs.readdir(F.path.public(), function(err, files) {
1405
+
1406
+ var rem = [];
1407
+ for (var m of files) {
1408
+ if (m !== relative && m.indexOf('ui-' + nameid + '-') !== -1)
1409
+ rem.push(F.path.public(m));
1410
+ }
1411
+
1412
+ if (rem.length)
1413
+ F.path.unlink(rem);
1414
+
1415
+ });
1416
+ }
1417
+
1418
+ F.Fs.lstat(filename, function(err) {
1419
+ if (err)
1420
+ F.download(url, filename, err => err ? F.error(err, 'COMPONENTATOR') : null);
1421
+ });
1422
+
1423
+ };
1424
+
1425
+ F.error = function(err, name, url) {
1426
+
1427
+ if (!arguments.length)
1428
+ return F.errorcallback;
1429
+
1430
+ if (err)
1431
+ F.def.onError(err, name, url);
1432
+ };
1433
+
1434
+ F.errorcallback = function(err) {
1435
+ err && F.error(err);
1436
+ };
1437
+
1438
+ F.merge = function(url) {
1439
+
1440
+ var arr = [];
1441
+
1442
+ for (let i = 1; i < arguments.length; i++) {
1443
+ let links = arguments[i];
1444
+
1445
+ if (typeof(links) === 'string') {
1446
+ let tmp = links.split('+').trim();
1447
+ for (let link of tmp) {
1448
+
1449
+ if (REG_HTTPHTTPS.test(link)) {
1450
+ arr.push(link);
1451
+ continue;
1452
+ }
1453
+
1454
+ if (link[0] !== '~' && link[0] !== '_') {
1455
+ let ext = F.TUtils.getExtension(link);
1456
+ if (ext === 'js')
1457
+ link = F.path.public('/js/' + link);
1458
+ else
1459
+ link = F.path.public('/css/' + link);
1460
+ arr.push(link);
1461
+ } else
1462
+ arr.push(F.path.route(link, 'public'));
1463
+ }
1464
+ continue;
1465
+ }
1466
+
1467
+ if (!(links instanceof Array))
1468
+ links = [links];
1469
+ for (let link of links)
1470
+ arr.push(link);
1471
+ }
1472
+
1473
+ if (url[0] !== '/')
1474
+ url = '/' + url;
1475
+
1476
+ url = url.toLowerCase();
1477
+
1478
+ var ext = F.TUtils.getExtension(url);
1479
+ var key = url.substring(1).replace(/\//g, '-').replace(/\.(js|html|css)$/, '') + '-min.' + ext;
1480
+ var filename = F.path.tmp(F.clusterid + 'merged_' + key);
1481
+
1482
+ F.routes.virtual[url] = async function(ctrl) {
1483
+ if (DEBUG) {
1484
+ var buffer = await F.TMinificators.merge(true, arr);
1485
+ ctrl.binary(buffer, F.TUtils.contentTypes[ext] || F.TUtils.contentTypes.bin);
1486
+ } else {
1487
+ F.lock('merging_' + key, async function(next) {
1488
+ if (F.temporary.merged[key]) {
1489
+ if (F.temporary.notfound[url]) {
1490
+ ctrl.fallback(404);
1491
+ next();
1492
+ return;
1493
+ }
1494
+ } else {
1495
+ if (F.temporary.notfound[url])
1496
+ delete F.temporary.notfound[url];
1497
+ F.temporary.merged[key] = true;
1498
+ await F.TMinificators.merge(filename, arr);
1499
+ }
1500
+ ctrl.response.minify = false;
1501
+ ctrl.file(filename);
1502
+ next();
1503
+ });
1504
+ }
1505
+ };
1506
+
1507
+ return url;
1508
+ };
1509
+
1510
+ F.lock = function(key, callback) {
1511
+ if (F.processing[key]) {
1512
+ F.processing[key].push(callback);
1513
+ } else {
1514
+ F.processing[key] = [];
1515
+ callback(function() {
1516
+ var pending = F.processing[key];
1517
+ delete F.processing[key];
1518
+ for (let fn of pending)
1519
+ fn(F.TUtils.noop);
1520
+ });
1521
+ }
1522
+ };
1523
+
1524
+ F.touch = function(url) {
1525
+ if (url) {
1526
+ delete F.temporary.minified[url];
1527
+ delete F.temporary.tmp[url];
1528
+ delete F.temporary.notfound[url];
1529
+ } else {
1530
+ F.temporary.minified = {};
1531
+ F.temporary.tmp = {};
1532
+ F.temporary.notfound = {};
1533
+ }
1534
+ };
1535
+
1536
+ F.unauthorized = function($) {
1537
+
1538
+ var user = $.user;
1539
+ if (user) {
1540
+
1541
+ if (user.sa || user.su)
1542
+ return false;
1543
+
1544
+ var compare = user.permissions || user.roles;
1545
+ var args = arguments;
1546
+
1547
+ if (compare) {
1548
+ if (compare instanceof Array) {
1549
+ for (let i = 0; i < compare.length; i++) {
1550
+ for (let j = 1; j < args.length; j++) {
1551
+ if (args[j] === compare[i])
1552
+ return false;
1553
+ }
1554
+ }
1555
+ } else {
1556
+ for (let j = 1; j < args.length; j++) {
1557
+ if (compare[args[j]])
1558
+ return false;
1559
+ }
1560
+ }
1561
+ }
1562
+ }
1563
+
1564
+ $.invalid(401);
1565
+ return true;
1566
+ };
1567
+
1568
+ F.middleware = function(name, fn, assign) {
1569
+
1570
+ if (!fn) {
1571
+ let types = ['routes', 'files', 'websockets'];
1572
+ for (let type of types) {
1573
+ for (let route of F.routes[type]) {
1574
+ let index = route.middleware.indexOf(name);
1575
+ if (index !== -1)
1576
+ route.middleware.splice(index, 1);
1577
+ }
1578
+ }
1579
+ delete F.routes.middleware[name];
1580
+ return;
1581
+ }
1582
+
1583
+ F.routes.middleware[name] = fn;
1584
+
1585
+ if (assign) {
1586
+
1587
+ if (typeof(assign) === 'string')
1588
+ assign = assign.split(',').trim();
1589
+
1590
+ var routes = ['routes', 'files', 'websockets'];
1591
+
1592
+ for (let a of assign) {
1593
+
1594
+ if (a === '*') {
1595
+ for (let type of routes) {
1596
+ for (let route of F.routes[type]) {
1597
+ if (!route.middleware.includes(name))
1598
+ route.middleware.push(name);
1599
+ }
1600
+ }
1601
+ } else {
1602
+
1603
+ if (a === 'websocket' || a === 'file' || a === 'route')
1604
+ a += 's';
1605
+ else if (a === 'dynamic')
1606
+ a = 'routes';
1607
+
1608
+ let routes = F.routes[a];
1609
+ if (routes) {
1610
+ for (let route of routes) {
1611
+ if (!route.middleware.includes(name))
1612
+ route.middleware.push(name);
1613
+ }
1614
+ }
1615
+ }
1616
+ }
1617
+ }
1618
+ };
1619
+
1620
+ F.pauseserver = function(name, enable) {
1621
+
1622
+ var index;
1623
+
1624
+ if (enable !== undefined) {
1625
+ if (enable) {
1626
+ if (!F.paused.includes(name))
1627
+ F.paused.push(name);
1628
+ } else {
1629
+ index = F.paused.indexOf(name);
1630
+ if (index !== -1)
1631
+ F.paused.splice(index, 1);
1632
+ }
1633
+ return enable;
1634
+ }
1635
+
1636
+ index = F.paused.indexOf(name);
1637
+
1638
+ if (index != -1) {
1639
+ F.paused.splice(index, 1);
1640
+ enable = false;
1641
+ } else {
1642
+ F.paused.push(name);
1643
+ enable = true;
1644
+ }
1645
+
1646
+ return enable === true;
1647
+ };
1648
+
1649
+ F.uid = function() {
1650
+ let ts = Date.now() / 100;
1651
+ let h = F.TUtils.convert62(ts);
1652
+ let index = F.internal.uid++;
1653
+ return h + F.TUtils.convert62(index + 99) + F.internal.uidc + h.length + (index % 2 ? 1 : 0) + 'f'; // "f" version
1654
+ };
1655
+
1656
+ F.cron = function(line, fn) {
1657
+ let obj = {};
1658
+ obj.check = F.TCron.make(line);
1659
+ obj.exec = fn;
1660
+ obj.remove = function() {
1661
+ let index = F.crons.indexOf(this);
1662
+ if (index !== -1)
1663
+ F.crons.splice(index, 0);
1664
+ };
1665
+ F.crons.push(obj);
1666
+ return obj;
1667
+ };
1668
+
1669
+ // Service
1670
+ F.service = function(count) {
1671
+
1672
+ // Clears expired cache
1673
+ F.cache.refresh();
1674
+
1675
+ // Clears temporary memory for non-exist files
1676
+ F.temporary.notfound = {};
1677
+
1678
+ // UID state
1679
+ F.internal.uid = 1;
1680
+ F.internal.uidc = F.TUtils.random_text(1);
1681
+
1682
+ if (F.config.$httpreqlimit)
1683
+ F.temporary.ddos = {};
1684
+
1685
+ if (count % F.config.$clearcache === 0) {
1686
+
1687
+ F.temporary.actions = {};
1688
+ F.temporary.path = {};
1689
+ F.temporary.views = {};
1690
+ F.temporary.utils = {};
1691
+ F.temporary.calls = {};
1692
+ F.temporary.images = {};
1693
+ F.temporary.templates = {};
1694
+ F.temporary.querybuilders = {};
1695
+
1696
+ for (let key in F.filestorages)
1697
+ F.filestorages[key].cache = {};
1698
+ }
1699
+
1700
+ if (count % 5 === 0) {
1701
+ global.TEMP = {};
1702
+ F.TMail.refresh();
1703
+ }
1704
+
1705
+ // Bans
1706
+ for (let key in F.temporary.bans) {
1707
+ if (key !== 'is') {
1708
+ let tmp = F.temporary.bans[key];
1709
+ if (tmp.expire < NOW)
1710
+ delete F.temporary.bans[key];
1711
+ else
1712
+ F.temporary.bans.is = true;
1713
+ }
1714
+ }
1715
+
1716
+ // Update expires date
1717
+ if (count % 60 === 0)
1718
+ F.config.$httpexpire = NOW.add('y', 1).toUTCString();
1719
+
1720
+ if (count % F.config.$tmsclearblocked === 0)
1721
+ F.temporary.tmsblocked = {};
1722
+
1723
+ if (count % 30 === 0)
1724
+ F.temporary.dnscache = {};
1725
+
1726
+ let blocked = F.temporary.blocked;
1727
+ if (blocked.is) {
1728
+ blocked.is = false;
1729
+ for (let key in blocked) {
1730
+ if (key !== 'is') {
1731
+ let tmp = blocked[key];
1732
+ if (tmp.expire < NOW)
1733
+ delete blocked[key];
1734
+ else
1735
+ blocked.is = true;
1736
+ }
1737
+ }
1738
+ }
1739
+
1740
+ F.temporary.service.publish = F.stats.performance.publish;
1741
+ F.temporary.service.subscribe = F.stats.performance.subscribe;
1742
+ F.temporary.service.call = F.stats.performance.call;
1743
+ F.temporary.service.request = F.stats.performance.request;
1744
+ F.temporary.service.file = F.stats.performance.file;
1745
+ F.temporary.service.message = F.stats.performance.message;
1746
+ F.temporary.service.mail = F.stats.performance.mail;
1747
+ F.temporary.service.open = F.stats.performance.open;
1748
+ F.temporary.service.dbrm = F.stats.performance.dbrm;
1749
+ F.temporary.service.dbwm = F.stats.performance.dbwm;
1750
+ F.temporary.service.external = F.stats.performance.external;
1751
+ F.temporary.service.upload = F.stats.performance.upload;
1752
+ F.temporary.service.download = F.stats.performance.download;
1753
+
1754
+ F.stats.request.size += F.stats.performance.download;
1755
+ F.stats.response.size += F.stats.performance.upload;
1756
+ F.stats.performance.publish = 0;
1757
+ F.stats.performance.subscribe = 0;
1758
+ F.stats.performance.call = 0;
1759
+ F.stats.performance.upload = 0;
1760
+ F.stats.performance.download = 0;
1761
+ F.stats.performance.external = 0;
1762
+ F.stats.performance.dbrm = 0;
1763
+ F.stats.performance.dbwm = 0;
1764
+ F.stats.performance.request = 0;
1765
+ F.stats.performance.file = 0;
1766
+ F.stats.performance.open = 0;
1767
+ F.stats.performance.message = 0;
1768
+ F.stats.performance.mail = 0;
1769
+
1770
+ F.usage && F.usage();
1771
+ F.temporary.service.usage = 0;
1772
+
1773
+ if (count % 10 === 0 && global.gc)
1774
+ setTimeout(cleargc, 1000);
1775
+
1776
+ // Exec crons
1777
+ for (let cron of F.crons) {
1778
+ if (cron.check(NOW))
1779
+ cron.exec(NOW);
1780
+ }
1781
+
1782
+ };
1783
+
1784
+ function cleargc() {
1785
+ global.gc();
1786
+ }
1787
+
1788
+ F.clear = function(init = true, callback) {
1789
+
1790
+ if (callback == null)
1791
+ return new Promise(resolve => F.clear(init, () => resolve()));
1792
+
1793
+ var dir = F.path.tmp();
1794
+ var plus = F.clusterid;
1795
+
1796
+ if (dir[dir.length - 1] !== '/')
1797
+ dir += '/';
1798
+
1799
+ if (F.is)
1800
+ dir = dir.replaceAll('/', '\\');
1801
+
1802
+ if (init) {
1803
+ if (F.config.$cleartemp) {
1804
+ // clears only JS and CSS files
1805
+ F.TUtils.ls(dir, function(files) {
1806
+ F.path.unlink(files, callback);
1807
+ }, function(filename, folder) {
1808
+ if (folder || (plus && !filename.substring(dir.length).startsWith(plus)))
1809
+ return false;
1810
+ var ext = F.TUtils.getExtension(filename);
1811
+ return ext === 'js' || ext === 'css' || ext === 'tmp' || ext === 'upload' || ext === 'html' || ext === 'htm';
1812
+ });
1813
+ return;
1814
+ }
1815
+ }
1816
+
1817
+ if (!pathexists(dir)) {
1818
+ callback && callback();
1819
+ return;
1820
+ }
1821
+
1822
+ F.TUtils.ls(dir, function(files, directories) {
1823
+
1824
+ if (init) {
1825
+ var arr = [];
1826
+ for (let file of files) {
1827
+ var filename = file.substring(dir.length);
1828
+ if (plus && !filename.startsWith(plus))
1829
+ continue;
1830
+
1831
+ if (filename.indexOf('/') === -1 && !filename.endsWith('.cache'))
1832
+ arr.push(file);
1833
+ }
1834
+
1835
+ files = arr;
1836
+ directories = directories.remove(function(name) {
1837
+ name = F.TUtils.getName(name);
1838
+ return name[0] !== '~';
1839
+ });
1840
+ }
1841
+
1842
+ F.path.unlink(files, () => F.path.rmdir(directories, callback));
1843
+ });
1844
+
1845
+ if (!init)
1846
+ F.touch();
1847
+ };
1848
+
1849
+ F.view = function(name, model, prepare) {
1850
+ var view = new F.TViewEngine.View();
1851
+ prepare && prepare(view);
1852
+ return view.render(name, model);
1853
+ };
1854
+
1855
+ F.memorize = function(name, delay, skip) {
1856
+
1857
+ if (!name)
1858
+ name = '';
1859
+
1860
+ if (delay && typeof(delay) !== 'number') {
1861
+ var tmp;
1862
+ tmp = skip;
1863
+ skip = delay;
1864
+ delay = tmp;
1865
+ }
1866
+
1867
+ var data = {};
1868
+ var filename = F.path.databases('memorize' + (name ? ('_' + name) : '') + '.json');
1869
+
1870
+ try {
1871
+ data = F.Fs.readFileSync(filename, 'utf8').parseJSON(true);
1872
+ } catch (e) {}
1873
+
1874
+ var replacer;
1875
+ var timeout;
1876
+ var ignore = {};
1877
+
1878
+ if (skip) {
1879
+ if (typeof(skip) === 'string')
1880
+ skip = skip.split(',').trim();
1881
+ for (var m of skip)
1882
+ ignore[m] = 1;
1883
+ replacer = (key, value) => ignore[key] ? undefined : value;
1884
+ }
1885
+
1886
+ var save = () => F.Fs.writeFile(filename, replacer ? JSON.stringify(data, replacer, '\t') : JSON.stringify(data, null, '\t'), ERROR('MEMORIZE(\'' + name + '\').save()'));
1887
+
1888
+ data.save = function() {
1889
+ timeout && clearTimeout(timeout);
1890
+ timeout = setTimeout(save, delay || 10000);
1891
+ };
1892
+
1893
+ data.set = function(key, value) {
1894
+ data[key] = value;
1895
+ data.save();
1896
+ };
1897
+
1898
+ return data;
1899
+ };
1900
+
1901
+ F.newjsonschema = function(name, obj) {
1902
+ var type = typeof(name);
1903
+
1904
+ if (type === 'string' && typeof(obj) === 'string') {
1905
+ obj = obj.toJSONSchema();
1906
+ obj.$id = name;
1907
+ } else if (type === 'string') {
1908
+ if (obj == null) {
1909
+ obj = name.toJSONSchema();
1910
+ name = obj.$id;
1911
+ }
1912
+ } else if (type === 'object') {
1913
+ obj = name;
1914
+ name = obj.$id;
1915
+ }
1916
+
1917
+ F.jsonschemas[name] = F.jsonschemas[obj.$id] = obj;
1918
+ obj.transform = F.TUtils.jsonschematransform;
1919
+ return obj;
1920
+ };
1921
+
1922
+ F.newtransform = function(name, action, id) {
1923
+ if (action == null) {
1924
+ let items = F.transformations[name];
1925
+ let index = items.TfindIndex('id', id);
1926
+ if (index !== -1) {
1927
+ items.splice(index, 1);
1928
+ if (!items.length)
1929
+ delete F.transformations[name];
1930
+ }
1931
+ } else {
1932
+ let obj = {};
1933
+ obj.id = id;
1934
+ obj.action = action;
1935
+ obj.remove = function() {
1936
+ let arr = F.transformations[name];
1937
+ if (arr) {
1938
+ let index = arr.indexOf(obj);
1939
+ if (index !== -1) {
1940
+ arr.splice(index, 1);
1941
+ if (!arr.length)
1942
+ delete F.transformations[name];
1943
+ }
1944
+ }
1945
+ };
1946
+ if (F.transformations[name])
1947
+ F.transformations[name].push(obj);
1948
+ else
1949
+ F.transformations[name] = [obj];
1950
+ return obj;
1951
+ }
1952
+ };
1953
+
1954
+ function transform(items, opt, index) {
1955
+ var t = items[index];
1956
+ if (t) {
1957
+ opt.next = () => transform(items, opt, index + 1);
1958
+ t.action(opt, opt.value);
1959
+ } else
1960
+ opt.$callback(opt.error.items.length ? opt.error : null, opt.value);
1961
+ }
1962
+
1963
+ F.transform = function(name, value, callback, controller) {
1964
+
1965
+ if (typeof(callback) !== 'function')
1966
+ return new Promise((resolve, reject) => F.transform(name, value, (err, response) => err ? reject(err) : resolve(response), controller));
1967
+
1968
+ var items = F.transformations[name];
1969
+ if (items) {
1970
+ let opt = new F.TBuilders.Options(controller, new F.TBuilders.ErrorBuilder());
1971
+ opt.value = value;
1972
+ opt.$callback = callback;
1973
+ transform(items, opt, 0);
1974
+ } else
1975
+ callback(null, value);
1976
+ };
1977
+
1978
+ function auditjsonserialization(key, value) {
1979
+ if (!IGNORE_AUDIT[key] && value != null && value !== '')
1980
+ return value;
1981
+ }
1982
+
1983
+ F.audit = function(name, $, message, type) {
1984
+
1985
+ if (typeof(name) === 'object') {
1986
+ type = message;
1987
+ message = $;
1988
+ $ = name;
1989
+ name = null;
1990
+ }
1991
+
1992
+ var data = {};
1993
+
1994
+ if ($.user) {
1995
+ data.userid = $.user.id;
1996
+ data.username = $.user.name || $.user.nick || $.user.alias;
1997
+ }
1998
+
1999
+ if ($.controller) {
2000
+ if ($.controller.sessionid)
2001
+ data.sessionid = $.controller.sessionid;
2002
+ }
2003
+
2004
+ data.ua = $.ua;
2005
+ data.ip = $.ip;
2006
+ data.url = $.url;
2007
+
2008
+ if (type)
2009
+ data.type = type || 'info';
2010
+
2011
+ if ($.id)
2012
+ data.schema = $.id;
2013
+
2014
+ if ($.model)
2015
+ data.data = JSON.stringify({ params: $.params, query: $.query, model: $.model }, auditjsonserialization);
2016
+
2017
+ if (F.clusterid)
2018
+ data.instance = F.clusterid;
2019
+
2020
+ if (message)
2021
+ data.message = message;
2022
+
2023
+ data.app = F.config.url || F.config.name;
2024
+
2025
+ if (F.config.$tapilogger && F.config.$tapi && F.config.secret_totalapi)
2026
+ API('TAPI/logger', data).callback(ERROR('totalapi'));
2027
+ else
2028
+ F.def.onAudit(name, data, $);
2029
+ };
2030
+
2031
+ F.restore = function(filename, target, callback, filter) {
2032
+
2033
+ if (!callback)
2034
+ return new Promise((resolve, reject) => F.restore(filename, target, (err, response) => err ? reject(err) : resolve(response), filter));
2035
+
2036
+ var buffer_key = Buffer.from(':');
2037
+ var buffer_new = Buffer.from('\n');
2038
+ var buffer_dir = Buffer.from('#');
2039
+ var cache = {};
2040
+ var data = null;
2041
+ var type = 0;
2042
+ var item = null;
2043
+ var stream = typeof(filename) === 'string' ? F.Fs.createReadStream(filename) : filename;
2044
+ var index = 0;
2045
+ var parser = {};
2046
+ var open = {};
2047
+ var pending = 0;
2048
+ var end = false;
2049
+ var output = {};
2050
+ var concat = [];
2051
+
2052
+ output.files = 0;
2053
+ output.size = 0;
2054
+ output.path = target;
2055
+
2056
+ parser.parse_key = function() {
2057
+ index = data.indexOf(buffer_key);
2058
+ if (index !== -1) {
2059
+ index++;
2060
+ item = data.slice(0, index - 1).toString('utf8').trim();
2061
+ data = data.slice(index + (data[index] === 32 ? 1 : 0));
2062
+ type = 1;
2063
+ parser.next();
2064
+ }
2065
+ };
2066
+
2067
+ parser.parse_meta = function() {
2068
+
2069
+ var path = F.Path.join(target, item);
2070
+
2071
+ // Is directory?
2072
+ if (data[0] === buffer_dir[0]) {
2073
+ if (!cache[path]) {
2074
+ cache[path] = true;
2075
+ if (!filter || filter(item, true) !== false)
2076
+ F.path.mkdir(path);
2077
+ }
2078
+ type = 3;
2079
+ parser.next();
2080
+ return;
2081
+ }
2082
+
2083
+ let filename = null;
2084
+
2085
+ if (!cache[path]) {
2086
+
2087
+ cache[path] = true;
2088
+
2089
+ var npath = path.substring(0, path.lastIndexOf(F.is ? '\\' : '/'));
2090
+ filename = filter && filter(item, false);
2091
+
2092
+ if (!filter || filename || filename == null) {
2093
+ F.path.mkdir(npath);
2094
+ } else {
2095
+ type = 5; // skip
2096
+ parser.next();
2097
+ return;
2098
+ }
2099
+ }
2100
+
2101
+ if (typeof(filename) === 'string')
2102
+ path = F.Path.join(target, filename);
2103
+
2104
+ // File
2105
+ type = 2;
2106
+ var tmp = open[item] = {};
2107
+ tmp.path = path;
2108
+ tmp.name = item;
2109
+ tmp.writer = F.Fs.createWriteStream(path);
2110
+ tmp.zlib = F.Zlib.createGunzip();
2111
+ tmp.zlib.$self = tmp;
2112
+ pending++;
2113
+ output.files++;
2114
+
2115
+ tmp.zlib.on('error', function(e) {
2116
+ pending--;
2117
+ let tmp = this.$self;
2118
+ tmp.writer.end();
2119
+ tmp.writer = null;
2120
+ tmp.zlib = null;
2121
+ delete open[tmp.name];
2122
+ F.error(e, 'bundling', path);
2123
+ });
2124
+
2125
+ tmp.zlib.on('data', function(chunk) {
2126
+ output.size += chunk.length;
2127
+ this.$self.writer.write(chunk);
2128
+ });
2129
+
2130
+ tmp.zlib.on('end', function() {
2131
+ pending--;
2132
+ let tmp = this.$self;
2133
+ tmp.writer.end();
2134
+ tmp.writer = null;
2135
+ tmp.zlib = null;
2136
+ delete open[tmp.name];
2137
+ });
2138
+
2139
+ parser.next();
2140
+ };
2141
+
2142
+ parser.parse_dir = function() {
2143
+ index = data.indexOf(buffer_new);
2144
+ if (index !== -1) {
2145
+ data = data.slice(index + 1);
2146
+ type = 0;
2147
+ }
2148
+ parser.next();
2149
+ };
2150
+
2151
+ parser.parse_data = function() {
2152
+
2153
+ index = data.indexOf(buffer_new);
2154
+
2155
+ var skip = false;
2156
+
2157
+ if (index !== -1)
2158
+ type = 0;
2159
+
2160
+ if (type) {
2161
+ var remaining = data.length % 4;
2162
+ if (remaining) {
2163
+ open[item].zlib.write(Buffer.from(data.slice(0, data.length - remaining).toString('ascii'), 'base64'));
2164
+ data = data.slice(data.length - remaining);
2165
+ skip = true;
2166
+ } else {
2167
+ open[item].zlib.write(Buffer.from(data.toString('ascii'), 'base64'));
2168
+ data = null;
2169
+ }
2170
+ } else {
2171
+ open[item].zlib.end(Buffer.from(data.slice(0, index).toString('ascii'), 'base64'));
2172
+ data = data.slice(index + 1);
2173
+ }
2174
+
2175
+ !skip && data && data.length && parser.next();
2176
+ };
2177
+
2178
+ parser.next = function() {
2179
+ switch (type) {
2180
+ case 0:
2181
+ parser.parse_key();
2182
+ break;
2183
+ case 1:
2184
+ parser.parse_meta();
2185
+ break;
2186
+ case 2:
2187
+ parser.parse_data();
2188
+ break;
2189
+ case 3:
2190
+ parser.parse_dir();
2191
+ break;
2192
+ case 5:
2193
+ index = data.indexOf(buffer_new);
2194
+ if (index === -1)
2195
+ data = null;
2196
+ else {
2197
+ data = data.slice(index + 1);
2198
+ type = 0;
2199
+ parser.next();
2200
+ }
2201
+ break;
2202
+ }
2203
+
2204
+ end && !data.length && callback && callback(null, output);
2205
+ };
2206
+
2207
+ parser.end = function() {
2208
+ if (callback) {
2209
+ if (pending)
2210
+ setTimeout(parser.end, 100);
2211
+ else if (end && !data.length)
2212
+ callback(null, output);
2213
+ }
2214
+ };
2215
+
2216
+ stream.on('data', function(chunk) {
2217
+
2218
+ if (data) {
2219
+ concat[0] = data;
2220
+ concat[1] = chunk;
2221
+ data = Buffer.concat(concat);
2222
+ } else
2223
+ data = chunk;
2224
+
2225
+ parser.next();
2226
+ });
2227
+
2228
+ F.cleanup(stream, function() {
2229
+ end = true;
2230
+ parser.end();
2231
+ });
2232
+
2233
+ stream.resume();
2234
+
2235
+ };
2236
+
2237
+ F.backup = function(filename, files, callback, filter) {
2238
+
2239
+ if (!callback)
2240
+ return new Promise((resolve, reject) => F.backup(filename, files, (err, response) => err ? reject(err) : resolve(response), filter));
2241
+
2242
+ var padding = 100;
2243
+ var path = files instanceof Array ? F.path.root() : files;
2244
+
2245
+ if (!(files instanceof Array))
2246
+ files = [''];
2247
+
2248
+ var counter = 0;
2249
+ var totalsize = 0;
2250
+ var unlink = typeof(filename) === 'string' ? F.Fs.unlink : (filename, callback) => callback();
2251
+ var concat = [];
2252
+ var gzipoptions = { memLevel: 9 };
2253
+
2254
+ unlink(filename, function() {
2255
+
2256
+ files.sort(function(a, b) {
2257
+ let ac = a.split('/');
2258
+ let bc = b.split('/');
2259
+ if (ac.length < bc.length)
2260
+ return -1;
2261
+ else if (ac.length > bc.length)
2262
+ return 1;
2263
+ return a.localeCompare(b);
2264
+ });
2265
+
2266
+ var clean = function(path, files) {
2267
+ let index = 0;
2268
+ while (true) {
2269
+ let filename = files[index];
2270
+ if (!filename)
2271
+ break;
2272
+ if (filename.substring(0, path.length) === path)
2273
+ files.splice(index, 1);
2274
+ else
2275
+ index++;
2276
+ }
2277
+ };
2278
+
2279
+ var writer = typeof(filename) === 'string' ? F.Fs.createWriteStream(filename) : filename;
2280
+
2281
+ writer.on('finish', function() {
2282
+ callback && callback(null, { filename: filename, files: counter, size: totalsize });
2283
+ });
2284
+
2285
+ var lastchar = path[path.length - 1];
2286
+ var cleanpath = lastchar === '/' || lastchar === '\\' ? path.substring(0, path.length - 1) : path;
2287
+
2288
+ files.wait(function(item, next) {
2289
+
2290
+ var file = F.Path.join(path, item);
2291
+
2292
+ if (F.is)
2293
+ item = item.replace(/\\/g, '/');
2294
+
2295
+ if (item[0] !== '/')
2296
+ item = '/' + item;
2297
+
2298
+ F.Fs.stat(file, function(err, stats) {
2299
+
2300
+ if (err) {
2301
+ F.error(err, 'F.backup()', filename);
2302
+ next();
2303
+ return;
2304
+ }
2305
+
2306
+ if (stats.isSocket()) {
2307
+ next();
2308
+ return;
2309
+ }
2310
+
2311
+ if (stats.isDirectory()) {
2312
+
2313
+ var dir = item.replace(/\\/g, '/');
2314
+ if (dir[dir.length - 1] !== '/')
2315
+ dir += '/';
2316
+
2317
+ if (filter && !filter(dir, true))
2318
+ return next();
2319
+
2320
+ F.TUtils.ls(file, function(f, d) {
2321
+
2322
+ var length = path.length;
2323
+ if (path[path.length - 1] === '/')
2324
+ length--;
2325
+
2326
+ var processdir = function() {
2327
+
2328
+ var dir = d.shift();
2329
+ if (dir == null) {
2330
+ for (var i = 0; i < f.length; i++)
2331
+ files.push(f[i].substring(length));
2332
+ next();
2333
+ return;
2334
+ }
2335
+
2336
+ if (filter && !filter(dir.substring(length), true)) {
2337
+ clean(dir, f, true);
2338
+ clean(dir, d, true);
2339
+ } else {
2340
+ var tmp = Buffer.from(dir.substring(length).padRight(padding) + ': #\n', 'utf8');
2341
+ writer.write(tmp);
2342
+ totalsize += tmp.length;
2343
+ }
2344
+
2345
+ processdir();
2346
+ };
2347
+
2348
+ processdir();
2349
+
2350
+ });
2351
+ return;
2352
+ }
2353
+
2354
+ if (filter && !filter(file.substring(cleanpath.length), false)) {
2355
+ next();
2356
+ return;
2357
+ }
2358
+
2359
+ var data = Buffer.alloc(0);
2360
+ var tmp = Buffer.from(item.padRight(padding) + ': ');
2361
+
2362
+ totalsize += tmp.length;
2363
+ writer.write(tmp);
2364
+
2365
+ F.Fs.createReadStream(file).pipe(F.Zlib.createGzip(gzipoptions)).on('data', function(chunk) {
2366
+
2367
+ concat[0] = data;
2368
+ concat[1] = chunk;
2369
+ data = Buffer.concat(concat);
2370
+
2371
+ let remaining = data.length % 3;
2372
+ if (remaining) {
2373
+ let tmp = data.slice(0, data.length - remaining).toString('base64');
2374
+ writer.write(tmp, 'utf8');
2375
+ data = data.slice(data.length - remaining);
2376
+ totalsize += tmp.length;
2377
+ }
2378
+
2379
+ }).on('end', function() {
2380
+ let tmp = data.length ? data.toString('base64') : '';
2381
+ data.length && writer.write(tmp);
2382
+ writer.write('\n', 'utf8');
2383
+ totalsize += tmp.length + 1;
2384
+ counter++;
2385
+ setImmediate(next);
2386
+ }).on('error', function(err) {
2387
+ F.error(err, 'F.backup()', file);
2388
+ setImmediate(next);
2389
+ });
2390
+
2391
+ });
2392
+ }, () => writer.end());
2393
+ });
2394
+ };
2395
+
2396
+ F.restart = function() {
2397
+ process.send && process.send('total:restart');
2398
+ };
2399
+
2400
+ F.exit = function(signal = 15) {
2401
+
2402
+ if (F.isexited)
2403
+ return;
2404
+
2405
+ F.isexited = true;
2406
+
2407
+ for (let m in F.workers) {
2408
+ let worker = F.workers[m];
2409
+ try {
2410
+ worker && worker.kill && worker.kill(signal);
2411
+ } catch (e) {}
2412
+ }
2413
+
2414
+ let key = 'exit';
2415
+
2416
+ F.$events[key] && F.emit(key, signal);
2417
+
2418
+ if (!F.isWorker && process.send && process.connected) {
2419
+ try {
2420
+ process.send('total:stop');
2421
+ } catch (e) {}
2422
+ }
2423
+
2424
+ F.internal.interval && clearInterval(F.internal.interval);
2425
+ F.internal.interval = null;
2426
+
2427
+ if (F.server) {
2428
+ F.server.setTimeout(1);
2429
+ F.server.close();
2430
+ }
2431
+
2432
+ setTimeout(() => process.exit(1), 300);
2433
+ };
2434
+
2435
+ F.filestorage = function(name) {
2436
+ if (F.filestorages[name])
2437
+ return F.filestorages[name];
2438
+ var fs = F.TFileStorage.create(name);
2439
+ F.filestorages[name] = fs;
2440
+ return fs;
2441
+ };
2442
+
2443
+ F.encryptreq = function(ctrl, val, key, strict) {
2444
+ var obj = {};
2445
+ obj.ua = ctrl.ua;
2446
+ if (strict)
2447
+ obj.ip = ctrl.ip;
2448
+ obj.data = val;
2449
+ return F.encrypt(obj, key);
2450
+ };
2451
+
2452
+ F.decryptreq = function(ctrl, val, key) {
2453
+ if (!val)
2454
+ return;
2455
+ var obj = F.decrypt(val, key || '', true);
2456
+ if (!obj || (obj.ip && obj.ip !== ctrl.ip) || (obj.ua !== ctrl.ua))
2457
+ return;
2458
+ return obj.data;
2459
+ };
2460
+
2461
+ F.encrypt = function(value, key, unique) {
2462
+
2463
+ if (value == null)
2464
+ return '';
2465
+
2466
+ value = JSON.stringify(value);
2467
+
2468
+ if (F.config.$crypto) {
2469
+ if (!F.temporary.cryptokeys[key])
2470
+ F.temporary.cryptokeys[key] = Buffer.from(key);
2471
+ var cipher = F.Crypto.createCipheriv(F.config.$crypto, F.temporary.cryptokeys[key], F.config.$cryptoiv);
2472
+ CONCAT[0] = cipher.update(value);
2473
+ CONCAT[1] = cipher.final();
2474
+ return Buffer.concat(CONCAT).toString('hex');
2475
+ }
2476
+
2477
+ return value.encrypt(F.config.secret + '=' + key, unique);
2478
+ };
2479
+
2480
+ F.decrypt = function(value, key, tojson = true) {
2481
+
2482
+ var response;
2483
+
2484
+ if (F.config.$crypto) {
2485
+
2486
+ if (!F.temporary.cryptokeys[key])
2487
+ F.temporary.cryptokeys[key] = Buffer.from(key);
2488
+
2489
+ var decipher = F.Crypto.createDecipheriv(F.config.$crypto, F.temporary.cryptokeys[key], F.config.$cryptoiv);
2490
+ try {
2491
+ CONCAT[0] = decipher.update(Buffer.from(value || '', 'hex'));
2492
+ CONCAT[1] = decipher.final();
2493
+ response = Buffer.concat(CONCAT).toString('utf8');
2494
+ } catch (e) {
2495
+ response = null;
2496
+ }
2497
+ } else
2498
+ response = (value || '').decrypt(F.config.secret + '=' + key);
2499
+
2500
+ return response ? (tojson ? (response.isJSON() ? response.parseJSON(true) : null) : response) : null;
2501
+ };
2502
+
2503
+ F.dir = function(val) {
2504
+
2505
+ if (val)
2506
+ F.directory = val;
2507
+
2508
+ var dirs = ['public', 'tmp', 'logs', 'databases', 'controllers', 'resources', 'plugins', 'modules', 'views', 'definitions', 'schemas', 'models', 'flowstreams', 'bundles', 'actions', 'extensions', 'source', 'services', 'updates', 'templates', 'private'];
2509
+
2510
+ for (let dir of dirs) {
2511
+ let cfg = F.config['$dir' + dir];
2512
+ F.temporary.directories[dir] = cfg || F.Path.join(F.directory, dir);
2513
+ }
2514
+
2515
+ };
2516
+
2517
+ F.run = function(opt) {
2518
+ var type = opt.release ? 'release' : 'debug';
2519
+ require('./' + type)(opt);
2520
+ };
2521
+
2522
+ F.logmail = function(email, subject, body, callback) {
2523
+
2524
+ if (typeof(body) === 'function') {
2525
+ callback = body;
2526
+ body = subject;
2527
+ subject = null;
2528
+ } else if (body === undefined) {
2529
+ body = subject;
2530
+ subject = null;
2531
+ }
2532
+
2533
+ if (!subject)
2534
+ subject = F.config.name;
2535
+
2536
+ var body = '<!DOCTYPE html><html><head><title>' + subject + '</title><meta charset="utf-8" /></head><body><pre style="max-width:600px;font-size:13px;line-height:16px;white-space:pre-line">' + (typeof(body) === 'object' ? JSON.stringify(body).escape() : body) + '</pre></body></html>';
2537
+ return F.def.onMail(email, subject, body, callback);
2538
+ };
2539
+
2540
+ F.mail = function(email, subject, name, model, language, callback) {
2541
+
2542
+ if (typeof(language) === 'function') {
2543
+ let tmp = language;
2544
+ language = callback;
2545
+ callback = tmp;
2546
+ }
2547
+
2548
+ // Localization
2549
+ if (typeof(language) === 'string') {
2550
+ if (subject.includes('@('))
2551
+ subject = F.translate(language, subject);
2552
+ }
2553
+
2554
+ let body = F.view(name, model, view => view.language = language || '');
2555
+ return F.def.onMail(email, subject, body, callback);
2556
+ };
2557
+
2558
+ F.htmlmail = function(email, subject, body, language, callback) {
2559
+
2560
+ if (typeof(language) === 'function') {
2561
+ let tmp = language;
2562
+ language = callback;
2563
+ callback = tmp;
2564
+ }
2565
+
2566
+ // Localization
2567
+ if (typeof(language) === 'string') {
2568
+ if (subject.includes('@('))
2569
+ subject = F.translate(language, subject);
2570
+ if (body.includes('@('))
2571
+ body = F.translate(language, body);
2572
+ }
2573
+
2574
+ body = body.indexOf('<body>') === -1 ? ('<!DOCTYPE html><html><head><title>' + subject + '</title><meta charset="utf-8" /></head><body style="padding:0;margin:0;font-family:Arial;font-size:14px;font-weight:normal">' + body + '</body></html>') : body;
2575
+ return F.def.onMail(email, subject, body, callback);
2576
+ };
2577
+
2578
+ F.readfile = function(path, type = null) {
2579
+ return new Promise(resolve => F.Fs.readFile(path, type, (err, response) => err ? resolve(null) : resolve(response)));
2580
+ };
2581
+
2582
+ F.datauri = function(path) {
2583
+ return new Promise(resolve => F.Fs.readFile(path, 'base64', function(err, response) {
2584
+ if (err) {
2585
+ resolve(null);
2586
+ } else {
2587
+ var ext = F.TUtils.getExtension(path);
2588
+ resolve('data:' + F.TUtils.getContentType(ext) + ';base64,' + response);
2589
+ }
2590
+ }));
2591
+ };
2592
+
2593
+ F.loadstats = function() {
2594
+
2595
+ var main = {};
2596
+ var stats = F.consumption;
2597
+ var lastwarning = 0;
2598
+
2599
+ stats.id = F.clusterid;
2600
+ stats.version = {};
2601
+ stats.version.node = process.version;
2602
+ stats.version.total = F.version_header;
2603
+ stats.version.build = F.version;
2604
+ stats.version.app = F.config.version;
2605
+ stats.pid = process.pid;
2606
+ stats.thread = global.THREAD;
2607
+ stats.mode = DEBUG ? 'debug' : 'release';
2608
+ stats.overload = 0;
2609
+
2610
+ main.pid = process.pid;
2611
+ main.date = NOW;
2612
+ main.port = F.port;
2613
+ main.ip = F.ip;
2614
+ main.stats = [stats];
2615
+
2616
+ F.usage = function() {
2617
+
2618
+ var memory = process.memoryUsage();
2619
+ stats.date = NOW;
2620
+
2621
+ if (stats.id != F.clusterid)
2622
+ stats.id = F.clusterid;
2623
+
2624
+ stats.memory = (memory.heapUsed / 1024 / 1024).floor(2);
2625
+ stats.rm = F.temporary.service.request || 0; // request min
2626
+ stats.fm = F.temporary.service.file || 0; // files min
2627
+ stats.wm = F.temporary.service.message || 0; // websocket messages min
2628
+ stats.em = F.temporary.service.external || 0; // external requests min
2629
+ stats.mm = F.temporary.service.mail || 0; // mail min
2630
+ stats.om = F.temporary.service.open || 0; // open files min
2631
+ stats.dm = (F.temporary.service.download || 0).floor(3); // downloaded MB min
2632
+ stats.um = (F.temporary.service.upload || 0).floor(3); // uploaded MB min
2633
+ stats.pm = F.temporary.service.publish || 0; // publish messages min
2634
+ stats.sm = F.temporary.service.subscribe || 0; // subscribe messages min
2635
+ stats.cm = F.temporary.service.call || 0; // calls messages min
2636
+ stats.dbrm = F.temporary.service.dbrm || 0; // db read
2637
+ stats.dbwm = F.temporary.service.dbwm || 0; // db write
2638
+ stats.usage = F.temporary.service.usage.floor(2); // app usage in % min
2639
+ stats.requests = F.stats.request.request;
2640
+ stats.pending = F.stats.request.pending;
2641
+ stats.external = F.stats.request.external || 0;
2642
+ stats.errors = F.stats.error;
2643
+ stats.timeouts = F.stats.response.timeout;
2644
+ stats.online = F.stats.performance.online;
2645
+ stats.uptime = F.cache.count;
2646
+ stats.download = F.stats.request.size.floor(3);
2647
+ stats.upload = F.stats.response.size.floor(3);
2648
+
2649
+ var err = F.errors[F.errors.length - 1];
2650
+ var timeout = F.timeouts[F.timeouts.length - 1];
2651
+
2652
+ stats.lasterror = err ? (err.date.toJSON() + ' ' + (err.name ? (err.name + ' - ') : '') + err.error) : undefined;
2653
+ stats.lasttimeout = timeout;
2654
+
2655
+ if ((stats.usage > 80 || stats.memory > 600 || stats.pending > 1000) && lastwarning !== NOW.getHours()) {
2656
+ lastwarning = NOW.getHours();
2657
+ stats.overload++;
2658
+ }
2659
+
2660
+ if (F.isWorker) {
2661
+ if (process.connected) {
2662
+ CLUSTER_STATS.data = stats;
2663
+ process.send(CLUSTER_STATS);
2664
+ }
2665
+ } else if (F.config.$stats) {
2666
+ try {
2667
+ F.Fs.writeFile(process.mainModule.filename + '.json', JSON.stringify(main, null, '\t'), NOOP);
2668
+ } catch (e) {
2669
+ // readonly or something else
2670
+ F.usage = null;
2671
+ console.log(e);
2672
+ }
2673
+ }
2674
+
2675
+ F.$events.$stats && F.emit('$stats', stats);
2676
+
2677
+ };
2678
+
2679
+ };
2680
+
2681
+ function httptuningperformance(socket) {
2682
+ socket.setNoDelay(true);
2683
+ socket.setKeepAlive(true, 10);
2684
+ }
2685
+
2686
+ process.on('unhandledRejection', function(e) {
2687
+ F.error(e.stack, '');
2688
+ });
2689
+
2690
+ process.on('uncaughtException', function(e) {
2691
+ var err = e + '';
2692
+ if (err.indexOf('listen EADDRINUSE') !== -1) {
2693
+ console.log('\nThe IP address and the PORT is already in use.\nYou must change the PORT\'s number or IP address.\n');
2694
+ process.send && process.send('total:eaddrinuse');
2695
+ process.exit(1);
2696
+ return;
2697
+ } else if (F.config.$filtererrors && REG_SKIPERRORS.test(err))
2698
+ return;
2699
+ F.error(e.stack, '');
2700
+ });
2701
+
2702
+ function ping() {
2703
+ process.connected && process.send('total:ping');
2704
+ }
2705
+
2706
+ process.on('message', function(msg, h) {
2707
+
2708
+ let key;
2709
+
2710
+ if (msg === 'total:debug') {
2711
+ F.TUtils.wait(() => F.isLoaded, F.console, 10000, 500);
2712
+ } else if (msg === 'total:ping')
2713
+ setImmediate(ping);
2714
+ else if (msg === 'total:update') {
2715
+ key = '$update';
2716
+ F.$events[key] && F.emit(key);
2717
+ } else if (msg === 'stop' || msg === 'exit' || msg === 'kill')
2718
+ F.exit();
2719
+
2720
+ F.$events.$message && F.emit('$message', msg, h);
2721
+ });
2722
+
2723
+ (function(F) {
2724
+
2725
+ // Node.js modules
2726
+ F.Zlib = F.require('node:zlib');
2727
+ F.Fs = F.require('node:fs');
2728
+ F.Path = F.require('node:path');
2729
+ F.Http = F.require('node:http');
2730
+ F.Https = F.require('node:https');
2731
+ F.Worker = F.require('node:worker_threads');
2732
+ F.Crypto = F.require('node:crypto');
2733
+ F.Child = F.require('node:child_process');
2734
+ F.Os = F.require('node:os');
2735
+ F.Dns = F.require('node:dns');
2736
+ F.Net = F.require('node:net');
2737
+ F.Url = F.require('node:url');
2738
+ F.Tls = F.require('node:tls');
2739
+ F.Stream = F.require('node:stream');
2740
+ F.Cluster = require('node:cluster');
2741
+
2742
+ // Total.js modules
2743
+ F.TUtils = require('./utils');
2744
+ F.TRouting = require('./routing');
2745
+ F.TBuilders = require('./builders');
2746
+ F.TViewEngine = require('./viewengine');
2747
+ F.TMinificators = require('./minificators');
2748
+ F.TWebSocket = require('./websocket');
2749
+ F.TQueryBuilder = require('./querybuilder');
2750
+ F.THttp = require('./http');
2751
+ F.TJSONSchema = require('./jsonschema');
2752
+ F.TCron = require('./cron');
2753
+ F.TApi = require('./api');
2754
+ F.TBundles = require('./bundles');
2755
+ F.TFileStorage = require('./filestorage');
2756
+ F.TTemplates = require('./templates');
2757
+ F.TSourceMap = require('./sourcemap');
2758
+ F.TMail = require('./mail');
2759
+ F.TWorkers = require('./workers');
2760
+ F.TFlowStream = require('./flowstream');
2761
+ F.TCluster = require('./cluster');
2762
+
2763
+ // Settings
2764
+ // F.directory = F.TUtils.$normalize(require.main ? F.Path.dirname(require.main.filename) : process.cwd());
2765
+ F.directory = F.TUtils.$normalize(process.cwd());
2766
+
2767
+ F.is = F.Os.platform().substring(0, 3).toLowerCase() === 'win';
2768
+ F.isWorker = process.env.PASSENGER_APP_ENV ? false : F.Cluster.isWorker;
2769
+ F.syshash = (__dirname + '-' + F.Os.hostname() + '-' + F.Os.platform() + '-' + F.Os.arch() + '-' + F.Os.release() + '-' + F.Os.tmpdir() + JSON.stringify(process.versions)).md5();
2770
+ F.isLE = F.Os.endianness ? F.Os.endianness() === 'LE' : true;
2771
+ F.isWindows = F.Os.platform().substring(0, 3).toLowerCase() === 'win';
2772
+
2773
+ F.config.$total5 = F.Path.dirname(require.resolve('./index'));
2774
+
2775
+ F.cache = require('./cache');
2776
+ F.TImages = require('./images');
2777
+ F.path.fs = F.Fs;
2778
+ F.path.join = F.Path.join;
2779
+
2780
+ F.TUtils.EventEmitter2.extend(F);
2781
+
2782
+ F.on2 = F.on;
2783
+ F.on = function(name, fn) {
2784
+ if (name === 'ready' && F.isLoaded)
2785
+ fn();
2786
+ else
2787
+ F.on2(name, fn);
2788
+ };
2789
+
2790
+ // Configuration
2791
+ F.config.secret_uid = F.syshash.substring(10);
2792
+ F.config.$httpexpire = NOW.add('y', 1).toUTCString(); // must be refreshed every hour
2793
+ F.config.$cryptoiv = Buffer.from(F.syshash).slice(0, 16);
2794
+ F.config.$nodemodules = F.Path.join(F.directory, 'node_modules');
2795
+
2796
+ // Methods
2797
+ F.route = F.TRouting.route;
2798
+ F.newdb = F.TQueryBuilder.create;
2799
+ F.newflowstream = F.TFlowStream.create;
2800
+ F.internal.uidc = F.TUtils.random_text(1);
2801
+ F.ErrorBuilder = F.TBuilders.ErrorBuilder;
2802
+ F.newaction = F.TBuilders.newaction;
2803
+ F.action = F.TBuilders.action;
2804
+ F.api = F.TApi.exec;
2805
+ F.newapi = F.TApi.newapi;
2806
+ F.template = F.TTemplates.render;
2807
+ F.websocketclient = F.TWebSocket.createclient;
2808
+ F.image = F.TImages.load;
2809
+ F.sourcemap = F.TSourceMap.create;
2810
+ F.tmpdir = F.Os.tmpdir();
2811
+ F.proxy = F.TRouting.proxy;
2812
+
2813
+ // Needed "F"
2814
+ F.TFlow = require('./flow');
2815
+ F.TTMS = require('./tms');
2816
+ F.TCMS = require('./cms');
2817
+ F.TNoSQL = require('./nosql');
2818
+ F.TUIBuilder = require('./uibuilder');
2819
+
2820
+ })(F);
2821
+
2822
+ process.connected && setTimeout(() => process.send('total:init'), 100);
2823
+
2824
+ require('./global');
2825
+ require('./tangular');
2826
+ require('./markdown');
2827
+
2828
+ // Init directories
2829
+ F.dir();
2830
+
2831
+ // Init CORS
2832
+ F.on('$cors', function() {
2833
+
2834
+ var arr = (F.config.$cors || '').toLowerCase().split(',').trim();
2835
+ var wildcard = [];
2836
+ var strict = [];
2837
+
2838
+ for (let i = 0; i < arr.length; i++) {
2839
+ let val = arr[i];
2840
+ if (val !== '*') {
2841
+ if (val[0] === '*' && val.length > 1)
2842
+ wildcard.push(val.substring(1));
2843
+ else
2844
+ strict.push(val);
2845
+ }
2846
+ }
2847
+
2848
+ F.temporary.cors = F.config.$cors === '*' ? null : { wildcard: wildcard, strict: strict };
2849
+ });
2850
+
2851
+ module.exports = F;