alchemymvc 1.1.9 → 1.2.1
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/lib/app/conduit/socket_conduit.js +620 -620
- package/lib/app/datasource/mongo_datasource.js +75 -10
- package/lib/app/helper/backed_map.js +257 -0
- package/lib/app/helper/enum_values.js +125 -0
- package/lib/app/helper/router_helper.js +7 -1
- package/lib/app/helper/socket_helper.js +613 -613
- package/lib/app/helper_datasource/00-nosql_datasource.js +73 -19
- package/lib/app/helper_field/enum_field.js +9 -36
- package/lib/app/helper_field/schema_field.js +11 -21
- package/lib/app/helper_model/criteria.js +73 -18
- package/lib/app/helper_model/field_config.js +24 -5
- package/lib/app/helper_model/model.js +45 -7
- package/lib/app/model/alchemy_migration_model.js +33 -0
- package/lib/bootstrap.js +9 -0
- package/lib/class/datasource.js +2 -2
- package/lib/class/element.js +6 -1
- package/lib/class/field.js +7 -1
- package/lib/class/migration.js +138 -0
- package/lib/class/model.js +11 -19
- package/lib/class/schema.js +14 -12
- package/lib/core/client_alchemy.js +14 -0
- package/lib/core/socket.js +159 -159
- package/lib/init/alchemy.js +1793 -1779
- package/lib/init/functions.js +4 -1
- package/lib/init/load_functions.js +8 -2
- package/lib/init/requirements.js +101 -96
- package/package.json +13 -13
- package/CHANGELOG.md +0 -458
package/lib/init/alchemy.js
CHANGED
|
@@ -1,1780 +1,1794 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var shared_objects = {},
|
|
4
|
-
plugModules = null,
|
|
5
|
-
usedModules = {},
|
|
6
|
-
useErrors = {},
|
|
7
|
-
usePaths = {},
|
|
8
|
-
ac_entries = {},
|
|
9
|
-
parseArgs = require('minimist'),
|
|
10
|
-
libpath = require('path'),
|
|
11
|
-
colors = require('ansi-256-colors'),
|
|
12
|
-
fs = require('fs');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The Alchemy class
|
|
16
|
-
*
|
|
17
|
-
* @constructor
|
|
18
|
-
*
|
|
19
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
20
|
-
* @since 0.0.1
|
|
21
|
-
* @version 1.1.0
|
|
22
|
-
*/
|
|
23
|
-
global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
|
|
24
|
-
|
|
25
|
-
var that = this,
|
|
26
|
-
package_json;
|
|
27
|
-
|
|
28
|
-
// Only allow a single instance of the Alchemy class
|
|
29
|
-
if (global.alchemy) {
|
|
30
|
-
return global.alchemy;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Timestamp when alchemy started
|
|
34
|
-
this.start_time = Date.now();
|
|
35
|
-
|
|
36
|
-
// Current working directory
|
|
37
|
-
this.cwd = process.cwd();
|
|
38
|
-
|
|
39
|
-
// Parsed arguments
|
|
40
|
-
this.argv = parseArgs(process.argv.slice(2));
|
|
41
|
-
|
|
42
|
-
// The id of this server instance
|
|
43
|
-
this.discovery_id = Crypto.pseudoHex();
|
|
44
|
-
|
|
45
|
-
// Link to the colors module
|
|
46
|
-
this.colors = colors;
|
|
47
|
-
|
|
48
|
-
// The session count
|
|
49
|
-
this.session_count = 0;
|
|
50
|
-
|
|
51
|
-
// Plugins to be loaded will be stored in here, with their options
|
|
52
|
-
this.plugins = {};
|
|
53
|
-
|
|
54
|
-
// Certain required modules can be registered under a name
|
|
55
|
-
this.modules = {};
|
|
56
|
-
|
|
57
|
-
// Link to all used modules
|
|
58
|
-
this.modules_loaded = usedModules;
|
|
59
|
-
|
|
60
|
-
// Link to failed modules
|
|
61
|
-
this.modules_error = useErrors;
|
|
62
|
-
|
|
63
|
-
// Try getting the app package.json file
|
|
64
|
-
try {
|
|
65
|
-
package_json = require(libpath.resolve(PATH_ROOT, 'package.json'));
|
|
66
|
-
} catch (err) {
|
|
67
|
-
package_json = {};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// The app package.json as an object
|
|
71
|
-
this.package = package_json;
|
|
72
|
-
|
|
73
|
-
// Now get the alchemymvc package.json file
|
|
74
|
-
try {
|
|
75
|
-
package_json = require(libpath.resolve(PATH_CORE, '..', 'package.json'));
|
|
76
|
-
} catch (err) {
|
|
77
|
-
package_json = {};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Get the alchemy core version
|
|
81
|
-
this.version = package_json.version;
|
|
82
|
-
|
|
83
|
-
// Keep status
|
|
84
|
-
this.status = {};
|
|
85
|
-
|
|
86
|
-
// All caches
|
|
87
|
-
this.caches = {};
|
|
88
|
-
|
|
89
|
-
// Also store the version in the process versions object
|
|
90
|
-
process.versions.alchemy = this.version;
|
|
91
|
-
|
|
92
|
-
// Also store the version of the app
|
|
93
|
-
process.versions.alchemy_app = this.package.version;
|
|
94
|
-
|
|
95
|
-
// Load the settings
|
|
96
|
-
this.loadSettings();
|
|
97
|
-
|
|
98
|
-
// Listen to messages from parent processes
|
|
99
|
-
process.on('message', function gotMessage(message) {
|
|
100
|
-
if (typeof message == 'string') {
|
|
101
|
-
return that.emit(message);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (message && message.type) {
|
|
105
|
-
return that.emit(message.type, message.data);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Get Janeway
|
|
110
|
-
this.Janeway = this.use('janeway');
|
|
111
|
-
|
|
112
|
-
// Asign the Janeway levels
|
|
113
|
-
Object.assign(this, this.Janeway.LEVELS);
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
if (this.argv['stream-janeway']) {
|
|
117
|
-
this.startJaneway({stream: true});
|
|
118
|
-
} else if (this.allow_janeway) {
|
|
119
|
-
this.startJaneway();
|
|
120
|
-
}
|
|
121
|
-
} catch (err) {
|
|
122
|
-
log.warn('Failed to start Janeway:', err);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* See if running janeway is allowed
|
|
128
|
-
*
|
|
129
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
130
|
-
* @since 0.5.0
|
|
131
|
-
* @version 0.5.0
|
|
132
|
-
*
|
|
133
|
-
* @type {Boolean}
|
|
134
|
-
*/
|
|
135
|
-
Alchemy.prepareProperty(function allow_janeway() {
|
|
136
|
-
|
|
137
|
-
// Setting the --disable-janeway flag explicitly disabled ALL forms of janeway
|
|
138
|
-
if (this.argv['disable-janeway'] || process.env.DISABLE_JANEWAY) {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// You can also disable janeway in the settings
|
|
143
|
-
if (this.settings.janeway === false) {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (Blast.isNW || !process.stdout.isTTY) {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return true;
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Expirable object where sessions are stored
|
|
156
|
-
*
|
|
157
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
158
|
-
* @since 0.5.0
|
|
159
|
-
* @version 1.0.4
|
|
160
|
-
*
|
|
161
|
-
* @type {Develry.Cache}
|
|
162
|
-
*/
|
|
163
|
-
Alchemy.prepareProperty(function sessions() {
|
|
164
|
-
|
|
165
|
-
var cache = this.getCache('sessions', {
|
|
166
|
-
max_idle : alchemy.settings.session_length,
|
|
167
|
-
max_length : Infinity
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
cache.on('removed', function onRemoved(value, key) {
|
|
171
|
-
// @TODO: check if expired?
|
|
172
|
-
value.removed();
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
return cache;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Expirable object where sessions are temporarily stored
|
|
180
|
-
* based on the browser fingerprints
|
|
181
|
-
*
|
|
182
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
183
|
-
* @since 1.1.0
|
|
184
|
-
* @version 1.1.0
|
|
185
|
-
*
|
|
186
|
-
* @type {Develry.Cache}
|
|
187
|
-
*/
|
|
188
|
-
Alchemy.prepareProperty(function fingerprints() {
|
|
189
|
-
|
|
190
|
-
var cache = this.getCache('fingerprints', {
|
|
191
|
-
max_idle : '3 minutes',
|
|
192
|
-
max_length : 3000
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
return cache;
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Get or set the environment
|
|
200
|
-
*
|
|
201
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
202
|
-
* @since 0.4.0
|
|
203
|
-
* @version 0.4.0
|
|
204
|
-
*
|
|
205
|
-
* @type {String}
|
|
206
|
-
*/
|
|
207
|
-
Alchemy.setProperty(function environment() {
|
|
208
|
-
return alchemy.settings.environment;
|
|
209
|
-
}, function set_environment(value) {
|
|
210
|
-
alchemy.settings.environment = String(value);
|
|
211
|
-
return alchemy.settings.environment;
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Start janeway
|
|
216
|
-
*
|
|
217
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
218
|
-
* @since 0.5.0
|
|
219
|
-
* @version 1.1.0
|
|
220
|
-
*
|
|
221
|
-
* @param {Object} options
|
|
222
|
-
*/
|
|
223
|
-
Alchemy.setMethod(function startJaneway(options) {
|
|
224
|
-
|
|
225
|
-
if (this.Janeway.started) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (!options) {
|
|
230
|
-
options = {};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (options.stream) {
|
|
234
|
-
let that = this,
|
|
235
|
-
screen,
|
|
236
|
-
out;
|
|
237
|
-
|
|
238
|
-
out = new require('net').Socket({fd: 4, writable: true});
|
|
239
|
-
|
|
240
|
-
out.columns = 80;
|
|
241
|
-
out.rows = 24;
|
|
242
|
-
|
|
243
|
-
screen = this.Janeway.createScreen({
|
|
244
|
-
input : process.stdin,
|
|
245
|
-
terminal : 'xterm-256color',
|
|
246
|
-
output : out
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
options.screen = screen;
|
|
250
|
-
|
|
251
|
-
// Also output to stdout
|
|
252
|
-
options.output_to_stdout = true;
|
|
253
|
-
|
|
254
|
-
// Keep regular stdout color
|
|
255
|
-
options.keep_color = true;
|
|
256
|
-
|
|
257
|
-
// Don't mess with the indentation
|
|
258
|
-
options.change_indent = false;
|
|
259
|
-
|
|
260
|
-
this.on('janeway_propose_geometry', function onProposeGeometry(data) {
|
|
261
|
-
out.columns = data.cols || data.width;
|
|
262
|
-
out.rows = data.rows || data.height;
|
|
263
|
-
out.emit('resize');
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
screen.on('resize', function onResize(a, b) {
|
|
267
|
-
that.Janeway.redraw();
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
this.on('janeway_redraw', function onRedrawRequest() {
|
|
271
|
-
that.Janeway.redraw();
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
this.Janeway.started = true;
|
|
276
|
-
this.Janeway.start(options);
|
|
277
|
-
|
|
278
|
-
if (this.settings.title) {
|
|
279
|
-
let title = this.settings.title;
|
|
280
|
-
|
|
281
|
-
if (this.settings.titleized) {
|
|
282
|
-
title = 'Alchemy: ' + title;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
this.Janeway.setTitle(title);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (this.settings.session_menu) {
|
|
289
|
-
|
|
290
|
-
let session_menu = this.Janeway.addIndicator('⌨ ');
|
|
291
|
-
|
|
292
|
-
if (!session_menu.addItem) {
|
|
293
|
-
return session_menu.remove();
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
this.Janeway.session_menu = session_menu;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Log messages of level 5 (info)
|
|
303
|
-
*
|
|
304
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
305
|
-
* @since 0.0.1
|
|
306
|
-
* @version 0.4.0
|
|
307
|
-
*/
|
|
308
|
-
Alchemy.setMethod(function log(...args) {
|
|
309
|
-
return alchemy.printLog(5, args, {level: 3});
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Actually print a log message
|
|
314
|
-
*
|
|
315
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
316
|
-
* @since 0.4.0
|
|
317
|
-
* @version 1.1.0
|
|
318
|
-
*
|
|
319
|
-
* @param {Number} level
|
|
320
|
-
* @param {Array} args
|
|
321
|
-
* @param {Object} options
|
|
322
|
-
*/
|
|
323
|
-
Alchemy.setMethod(function printLog(level, args, options) {
|
|
324
|
-
|
|
325
|
-
var type,
|
|
326
|
-
line;
|
|
327
|
-
|
|
328
|
-
if (this.settings.silent) {
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (!Array.isArray(args)) {
|
|
333
|
-
args = [args];
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (typeof level == 'string') {
|
|
337
|
-
type = level;
|
|
338
|
-
} else {
|
|
339
|
-
if (level < 3) {
|
|
340
|
-
type = 'error';
|
|
341
|
-
} else if (level < 5) {
|
|
342
|
-
type = 'warn';
|
|
343
|
-
} else {
|
|
344
|
-
type = 'info';
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (this.Janeway != null) {
|
|
349
|
-
line = this.Janeway.print(type, args, options);
|
|
350
|
-
|
|
351
|
-
if (options && options.gutter && line) {
|
|
352
|
-
line.setGutter(options.gutter)
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return line;
|
|
356
|
-
} else {
|
|
357
|
-
console[type](...args);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Load the settings
|
|
363
|
-
*
|
|
364
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
365
|
-
* @since 0.4.0
|
|
366
|
-
* @version 1.1.6
|
|
367
|
-
*/
|
|
368
|
-
Alchemy.setMethod(function loadSettings() {
|
|
369
|
-
|
|
370
|
-
var default_path,
|
|
371
|
-
port_error,
|
|
372
|
-
local_path,
|
|
373
|
-
env_config,
|
|
374
|
-
env_path,
|
|
375
|
-
settings,
|
|
376
|
-
local,
|
|
377
|
-
env;
|
|
378
|
-
|
|
379
|
-
if (this.settings) {
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Create the settings object
|
|
384
|
-
this.settings = settings = {};
|
|
385
|
-
|
|
386
|
-
// Generate the path to the default settings file
|
|
387
|
-
default_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'default');
|
|
388
|
-
|
|
389
|
-
// Get default settings
|
|
390
|
-
try {
|
|
391
|
-
Object.assign(settings, require(default_path));
|
|
392
|
-
} catch (err) {
|
|
393
|
-
settings.no_default_file = default_path;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Generate the path to the local settings file
|
|
397
|
-
local_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'local');
|
|
398
|
-
|
|
399
|
-
// Get the local settings
|
|
400
|
-
try {
|
|
401
|
-
local = require(local_path);
|
|
402
|
-
} catch(err) {
|
|
403
|
-
local = {};
|
|
404
|
-
settings.no_local_file = local_path;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Default to the 'dev' environment
|
|
408
|
-
if (!local.environment) {
|
|
409
|
-
|
|
410
|
-
if (process.env.ENV) {
|
|
411
|
-
local.environment = process.env.ENV;
|
|
412
|
-
} else {
|
|
413
|
-
local.environment = 'dev';
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
env = this.argv.env || this.argv.environment;
|
|
418
|
-
|
|
419
|
-
if (env) {
|
|
420
|
-
local.environment = env;
|
|
421
|
-
this.printLog(this.INFO, ['Switching to environment', env]);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// Generate the path to the environment settings file
|
|
425
|
-
env_path = libpath.resolve(PATH_APP, 'config', local.environment, 'config');
|
|
426
|
-
|
|
427
|
-
// Get the config
|
|
428
|
-
try {
|
|
429
|
-
env_config = require(env_path);
|
|
430
|
-
} catch(err) {
|
|
431
|
-
env_config = {};
|
|
432
|
-
settings.no_env_file = env_path;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// Merge all the settings in order: default - environment - local
|
|
436
|
-
Object.merge(settings, env_config, local);
|
|
437
|
-
|
|
438
|
-
if (!settings.name) {
|
|
439
|
-
settings.name = this.package.name;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if (settings.title == null) {
|
|
443
|
-
if (this.package.title) {
|
|
444
|
-
// Allow users to set the title in their package file
|
|
445
|
-
settings.title = this.package.title;
|
|
446
|
-
} else if (settings.name) {
|
|
447
|
-
settings.title = settings.name.replace(/-/g, ' ').titleize();
|
|
448
|
-
settings.titleized = true;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (this.argv.port) {
|
|
453
|
-
let port = parseInt(this.argv.port);
|
|
454
|
-
|
|
455
|
-
if (port) {
|
|
456
|
-
this.printLog(this.INFO, ['Using port setting from argument:', port]);
|
|
457
|
-
settings.port = port;
|
|
458
|
-
} else {
|
|
459
|
-
this.argv.socket = this.argv.port;
|
|
460
|
-
this.argv.port = null;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (this.argv.socket) {
|
|
465
|
-
settings.port = false;
|
|
466
|
-
settings.socket = this.argv.socket;
|
|
467
|
-
|
|
468
|
-
let stat;
|
|
469
|
-
|
|
470
|
-
try {
|
|
471
|
-
stat = fs.statSync(settings.socket);
|
|
472
|
-
} catch (err) {
|
|
473
|
-
// Ignore if it doesn't exist yet
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
if (stat && stat.isDirectory()) {
|
|
477
|
-
settings.socket = libpath.resolve(settings.socket, settings.name + '.alchemy.sock');
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
this.printLog(this.INFO, ['Using socket setting from argument:', settings.socket]);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
if (!settings.port && settings.port !== false) {
|
|
484
|
-
settings.port = 3000;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
if (settings.port > 49151) {
|
|
488
|
-
port_error = 'Could not use port number ' + String(port).bold.red + ' because ';
|
|
489
|
-
|
|
490
|
-
// Make sure the port is valid
|
|
491
|
-
if (settings.port > 65535) {
|
|
492
|
-
this.printLog(this.FATAL, [port_error + 'there is no port higher than 65535. Please use ports below 49151.']);
|
|
493
|
-
} else {
|
|
494
|
-
this.printLog(this.FATAL, [port_error + 'it\'s an ephemeral port. Please use ports below 49151.']);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
process.exit();
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (this.argv.url) {
|
|
501
|
-
settings.url = this.argv.url;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (settings.url && settings.url.indexOf('{') > -1) {
|
|
505
|
-
settings.url = settings.url.assign(settings);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
if (this.argv.preload) {
|
|
509
|
-
settings.preload = this.argv.preload;
|
|
510
|
-
|
|
511
|
-
if (Array.isArray(settings.preload)) {
|
|
512
|
-
settings.preload = settings.preload.last();
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
if (settings.preload == 'false') {
|
|
517
|
-
settings.preload = false;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
let key,
|
|
521
|
-
val;
|
|
522
|
-
|
|
523
|
-
for (key in this.argv) {
|
|
524
|
-
|
|
525
|
-
if (!key.startsWith('override-')) {
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
val = this.argv[key];
|
|
530
|
-
key = key.after('override-');
|
|
531
|
-
|
|
532
|
-
if (!settings[key] || typeof settings[key] != 'object') {
|
|
533
|
-
settings[key] = val;
|
|
534
|
-
} else {
|
|
535
|
-
Object.merge(settings[key], val);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (settings.preload) {
|
|
540
|
-
this.doPreload();
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// Set the debug value
|
|
544
|
-
global.DEBUG = settings.debug;
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Set status
|
|
549
|
-
*
|
|
550
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
551
|
-
* @since 0.4.1
|
|
552
|
-
* @version 0.4.1
|
|
553
|
-
*/
|
|
554
|
-
Alchemy.setMethod(function setStatus(name, value) {
|
|
555
|
-
this.status[name] = value;
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
/**
|
|
559
|
-
* Execute the function when alchemy is ready
|
|
560
|
-
*
|
|
561
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
562
|
-
* @since 0.0.1
|
|
563
|
-
* @version 1.1.2
|
|
564
|
-
*
|
|
565
|
-
* @param {Function} callback The function to execute
|
|
566
|
-
*
|
|
567
|
-
* @return {Pledge}
|
|
568
|
-
*/
|
|
569
|
-
Alchemy.setMethod(function ready(callback) {
|
|
570
|
-
|
|
571
|
-
var that = this,
|
|
572
|
-
pledge = new Pledge();
|
|
573
|
-
|
|
574
|
-
pledge.done(callback);
|
|
575
|
-
|
|
576
|
-
if (!this.sputnik) {
|
|
577
|
-
Blast.loaded(function hasLoaded() {
|
|
578
|
-
pledge.resolve(that.ready());
|
|
579
|
-
});
|
|
580
|
-
} else {
|
|
581
|
-
this.sputnik.after(['start_server', 'datasources', 'listening'], function afterReady() {
|
|
582
|
-
pledge.resolve();
|
|
583
|
-
});
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
return pledge;
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* Preload the client-side stuff
|
|
591
|
-
*
|
|
592
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
593
|
-
* @since 1.1.2
|
|
594
|
-
* @version 1.1.2
|
|
595
|
-
*/
|
|
596
|
-
Alchemy.setMethod(async function doPreload() {
|
|
597
|
-
|
|
598
|
-
await this.ready();
|
|
599
|
-
|
|
600
|
-
let url;
|
|
601
|
-
|
|
602
|
-
if (this.settings.url) {
|
|
603
|
-
url = this.settings.url;
|
|
604
|
-
} else if (this.settings.port) {
|
|
605
|
-
url = 'http://localhost:' + this.settings.port;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (url) {
|
|
609
|
-
log.info('Preloading url', url);
|
|
610
|
-
Blast.fetch(url);
|
|
611
|
-
|
|
612
|
-
url += '/hawkejs/hawkejs-client.js';
|
|
613
|
-
|
|
614
|
-
log.info('Preloading client file via HTTP', url);
|
|
615
|
-
Blast.fetch(url);
|
|
616
|
-
} else {
|
|
617
|
-
log.info('Preloading client file');
|
|
618
|
-
|
|
619
|
-
Blast.getClientPath({
|
|
620
|
-
modify_prototypes : true,
|
|
621
|
-
create_source_map : alchemy.settings.debug,
|
|
622
|
-
enable_coverage : !!global.__coverage__
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Resolve the provided arguments to a useable path string.
|
|
629
|
-
* Only used strings, discards objects.
|
|
630
|
-
*
|
|
631
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
632
|
-
* @since 0.0.1
|
|
633
|
-
* @version 0.4.0
|
|
634
|
-
*
|
|
635
|
-
* @param {String} path_to_dirs The path containing the dirs to load
|
|
636
|
-
*/
|
|
637
|
-
Alchemy.setMethod(function pathResolve(...path_to_dirs) {
|
|
638
|
-
|
|
639
|
-
var path_arguments,
|
|
640
|
-
i;
|
|
641
|
-
|
|
642
|
-
if (path_to_dirs.length == 1) {
|
|
643
|
-
return path_to_dirs[0];
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
path_arguments = [];
|
|
647
|
-
|
|
648
|
-
for (i = 0; i < path_to_dirs.length; i++) {
|
|
649
|
-
if (typeof path_to_dirs[i] == 'string') {
|
|
650
|
-
path_arguments.push(path_to_dirs[i]);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
if (path_arguments.length > 1) {
|
|
655
|
-
return libpath.resolve(...path_arguments);
|
|
656
|
-
} else {
|
|
657
|
-
return path_arguments[0];
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* A wrapper function for requiring modules
|
|
663
|
-
*
|
|
664
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
665
|
-
* @since 0.0.1
|
|
666
|
-
* @version 1.0.0
|
|
667
|
-
*
|
|
668
|
-
* @param {String} module_name The name/path of the module to load
|
|
669
|
-
* @param {String} register_as Cache the module under this name
|
|
670
|
-
* @param {Object} options Extra options
|
|
671
|
-
* @param {Boolean} options.force Force a new requirement and do not cache
|
|
672
|
-
*
|
|
673
|
-
* @return {Object} The required module
|
|
674
|
-
*/
|
|
675
|
-
Alchemy.setMethod(function use(module_name, register_as, options) {
|
|
676
|
-
|
|
677
|
-
var module,
|
|
678
|
-
result;
|
|
679
|
-
|
|
680
|
-
if (typeof register_as == 'object') {
|
|
681
|
-
options = register_as;
|
|
682
|
-
register_as = false;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// Certain modules can be disabled by registering them as null
|
|
686
|
-
if (module_name == null && register_as) {
|
|
687
|
-
this.modules[register_as] = null;
|
|
688
|
-
return null;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// If the module has explicitly been set to null, return that
|
|
692
|
-
if (this.modules[module_name] === null) {
|
|
693
|
-
return null;
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
if (typeof options == 'undefined') options = {};
|
|
697
|
-
if (typeof options.force == 'undefined') options.force = false;
|
|
698
|
-
|
|
699
|
-
// If a module has already been registered under this name, return that
|
|
700
|
-
if (this.modules[module_name] && !options.force) {
|
|
701
|
-
return this.modules[module_name];
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
if (this.argv['debug-requirements']) {
|
|
705
|
-
this.printLog(this.DEBUG, ['Going to load module', module_name], {level: 2});
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
try {
|
|
709
|
-
result = this.findModule(module_name, options);
|
|
710
|
-
module = result.module;
|
|
711
|
-
} catch (err) {
|
|
712
|
-
|
|
713
|
-
if (!useErrors[module_name]) {
|
|
714
|
-
useErrors[module_name] = 0;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
useErrors[module_name]++;
|
|
718
|
-
|
|
719
|
-
if (!options.silent || this.argv['debug-requirements']) {
|
|
720
|
-
this.printLog(this.SEVERE, ['Failed to load module "' + module_name + '":', err.message], {level: 6, err: err});
|
|
721
|
-
}
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
if (!usedModules[module_name]) {
|
|
726
|
-
|
|
727
|
-
let entry = {
|
|
728
|
-
internal : result.internal,
|
|
729
|
-
loaded : 0
|
|
730
|
-
};
|
|
731
|
-
|
|
732
|
-
if (result.package) {
|
|
733
|
-
entry.version = result.package.version;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
usedModules[module_name] = result;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
usedModules[module_name].loaded++;
|
|
740
|
-
|
|
741
|
-
if (register_as) {
|
|
742
|
-
this.modules[register_as] = module;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
// If a new requirement needs to be forced, clear the cache
|
|
746
|
-
if (options.force) {
|
|
747
|
-
delete require.cache[result.module_path];
|
|
748
|
-
return require(result.module_path);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
return module;
|
|
752
|
-
});
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
* Look for a module by traversing the filesystem
|
|
757
|
-
*
|
|
758
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
759
|
-
* @since 0.0.1
|
|
760
|
-
* @version 0.4.0
|
|
761
|
-
*
|
|
762
|
-
* @param {String} startPath The path to originate the search from
|
|
763
|
-
* @param {String} moduleName
|
|
764
|
-
* @param {Number} recurse
|
|
765
|
-
*
|
|
766
|
-
* @return {String}
|
|
767
|
-
*/
|
|
768
|
-
Alchemy.setMethod(function searchModule(startPath, moduleName, recurse) {
|
|
769
|
-
|
|
770
|
-
var moduledirs,
|
|
771
|
-
module_path,
|
|
772
|
-
entries,
|
|
773
|
-
nmPath,
|
|
774
|
-
temp,
|
|
775
|
-
path,
|
|
776
|
-
key,
|
|
777
|
-
i;
|
|
778
|
-
|
|
779
|
-
// Don't do this search if it hasn't been enabled
|
|
780
|
-
// The new npm flat structure makes this an expensive thing to do
|
|
781
|
-
if (!this.settings.search_for_modules) {
|
|
782
|
-
|
|
783
|
-
// Set recurse to 3, so this is the first and last call
|
|
784
|
-
recurse = 3;
|
|
785
|
-
|
|
786
|
-
// Only add 2 folder to look through,
|
|
787
|
-
// the alchemymvc node_modules folder
|
|
788
|
-
// and the base node_modules folder
|
|
789
|
-
moduledirs = ['..', libpath.resolve(startPath, 'node_modules', 'alchemymvc')];
|
|
790
|
-
|
|
791
|
-
// Add plugin folders
|
|
792
|
-
if (!plugModules) {
|
|
793
|
-
path = libpath.resolve(PATH_ROOT, 'node_modules');
|
|
794
|
-
|
|
795
|
-
if (fs.existsSync(path)) {
|
|
796
|
-
|
|
797
|
-
// Get all the entries in the main modules folder
|
|
798
|
-
entries = fs.readdirSync(libpath.resolve(PATH_ROOT, 'node_modules'));
|
|
799
|
-
|
|
800
|
-
// Initiate the plugin modules variables
|
|
801
|
-
plugModules = [];
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
for (i = 0; i < entries.length; i++) {
|
|
805
|
-
temp = entries[i];
|
|
806
|
-
|
|
807
|
-
if (temp.startsWith('alchemy-')) {
|
|
808
|
-
plugModules.push(libpath.resolve(PATH_ROOT, 'node_modules', temp));
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
} else {
|
|
812
|
-
plugModules = [];
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
for (i = 0; i < plugModules.length; i++) {
|
|
817
|
-
moduledirs.push(plugModules[i]);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
} else if (!searchModule.have_warned) {
|
|
821
|
-
searchModule.have_warned = true;
|
|
822
|
-
log.warn('The "search_for_modules" config has been enabled!');
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
if (!recurse) {
|
|
826
|
-
recurse = 1;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
nmPath = libpath.resolve(startPath, 'node_modules');
|
|
830
|
-
|
|
831
|
-
if (!moduledirs) {
|
|
832
|
-
// Get all the entries inside the given path
|
|
833
|
-
try {
|
|
834
|
-
moduledirs = fs.readdirSync(nmPath);
|
|
835
|
-
} catch(err) {
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
// Look in the base node_modules directory first
|
|
841
|
-
if (recurse == 1) {
|
|
842
|
-
moduledirs.unshift('..');
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// Go over every directory in the main node_modules folder
|
|
846
|
-
for (i = 0; i < moduledirs.length; i++) {
|
|
847
|
-
|
|
848
|
-
key = moduledirs[i];
|
|
849
|
-
|
|
850
|
-
try {
|
|
851
|
-
// Let require find the specific file to get
|
|
852
|
-
module_path = require.resolve(libpath.resolve(nmPath, key, 'node_modules', moduleName));
|
|
853
|
-
|
|
854
|
-
// If no errors have popped up now, we can break the for loop
|
|
855
|
-
break;
|
|
856
|
-
|
|
857
|
-
} catch(e) {
|
|
858
|
-
// Do nothing
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
if (!module_path && recurse < 3) {
|
|
863
|
-
for (i = 0; i < moduledirs.length; i++) {
|
|
864
|
-
|
|
865
|
-
module_path = this.searchModule(libpath.resolve(nmPath, moduledirs[i]), moduleName, recurse+1);
|
|
866
|
-
|
|
867
|
-
if (module_path) {
|
|
868
|
-
break;
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
return module_path;
|
|
874
|
-
});
|
|
875
|
-
|
|
876
|
-
/**
|
|
877
|
-
* Find a module in our customized file structure
|
|
878
|
-
*
|
|
879
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
880
|
-
* @since 0.0.1
|
|
881
|
-
* @version 1.1.0
|
|
882
|
-
*
|
|
883
|
-
* @param {String} moduleName
|
|
884
|
-
* @param {Object} options
|
|
885
|
-
*
|
|
886
|
-
* @return {Object}
|
|
887
|
-
*/
|
|
888
|
-
Alchemy.setMethod(function findModule(moduleName, options) {
|
|
889
|
-
|
|
890
|
-
var package_json,
|
|
891
|
-
module_path,
|
|
892
|
-
internal,
|
|
893
|
-
module,
|
|
894
|
-
result,
|
|
895
|
-
time,
|
|
896
|
-
key,
|
|
897
|
-
i;
|
|
898
|
-
|
|
899
|
-
if (!options) {
|
|
900
|
-
options = {};
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
if (options.require == null) {
|
|
904
|
-
options.require = true;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// If we've required this once before, return it
|
|
908
|
-
if (result = usePaths[moduleName]) {
|
|
909
|
-
if (result.err) {
|
|
910
|
-
throw result.err;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
// Only return the cached module if it was required then,
|
|
914
|
-
// or if require is now false
|
|
915
|
-
if (result.module || !options.require) {
|
|
916
|
-
return result;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
result = {
|
|
921
|
-
err : null,
|
|
922
|
-
module : null,
|
|
923
|
-
module_dir : null,
|
|
924
|
-
module_path : null,
|
|
925
|
-
package : null,
|
|
926
|
-
internal : null,
|
|
927
|
-
search_time : null,
|
|
928
|
-
};
|
|
929
|
-
|
|
930
|
-
time = Date.now();
|
|
931
|
-
|
|
932
|
-
// Simply try to resolve the module by name
|
|
933
|
-
try {
|
|
934
|
-
module_path = require.resolve(moduleName);
|
|
935
|
-
} catch (err) {
|
|
936
|
-
result.err = err;
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// If that path wasn't found, look through the root node_modules
|
|
940
|
-
if (result.err) {
|
|
941
|
-
try {
|
|
942
|
-
module_path = this.searchModule(PATH_ROOT, moduleName);
|
|
943
|
-
} catch (err) {
|
|
944
|
-
console.log(err);
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// If the module_path was found, actually require the module
|
|
950
|
-
if (module_path) {
|
|
951
|
-
|
|
952
|
-
// Modules are required by default
|
|
953
|
-
if (options.require) {
|
|
954
|
-
module = require(module_path);
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// Get the package.json file
|
|
958
|
-
if (~module_path.indexOf(libpath.sep)) {
|
|
959
|
-
internal = false;
|
|
960
|
-
|
|
961
|
-
let module_dir = libpath.dirname(module_path);
|
|
962
|
-
result.module_dir = module_dir;
|
|
963
|
-
|
|
964
|
-
try {
|
|
965
|
-
package_json = require(libpath.resolve(module_dir, 'package.json'));
|
|
966
|
-
} catch (err) {
|
|
967
|
-
package_json = false;
|
|
968
|
-
}
|
|
969
|
-
} else {
|
|
970
|
-
internal = true;
|
|
971
|
-
package_json = {
|
|
972
|
-
version: process.versions.node
|
|
973
|
-
};
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
if (!options.require || module) {
|
|
978
|
-
result.err = null;
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
if (module) {
|
|
982
|
-
result.module = module;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
result.module_path = module_path;
|
|
986
|
-
result.package = package_json;
|
|
987
|
-
result.internal = internal;
|
|
988
|
-
|
|
989
|
-
// Save the result
|
|
990
|
-
usePaths[moduleName] = result;
|
|
991
|
-
|
|
992
|
-
// If there was an error, throw it now
|
|
993
|
-
if (result.err) {
|
|
994
|
-
throw result.err;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
result.search_time = Date.now() - time;
|
|
998
|
-
|
|
999
|
-
// Else return the result
|
|
1000
|
-
return result;
|
|
1001
|
-
});
|
|
1002
|
-
|
|
1003
|
-
/**
|
|
1004
|
-
* Create a shared object
|
|
1005
|
-
*
|
|
1006
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1007
|
-
* @since 0.0.1
|
|
1008
|
-
* @version 0.4.0
|
|
1009
|
-
*
|
|
1010
|
-
* @param {String} name The name of the object to get
|
|
1011
|
-
* @param {String} type The type to create (array or object)
|
|
1012
|
-
*
|
|
1013
|
-
* @return {Object|Array}
|
|
1014
|
-
*/
|
|
1015
|
-
Alchemy.setMethod(function shared(name, type, value) {
|
|
1016
|
-
|
|
1017
|
-
if (typeof type !== 'string') {
|
|
1018
|
-
value = type;
|
|
1019
|
-
type = 'object';
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
// Create it if it doesn't exist
|
|
1023
|
-
if (!shared_objects[name]) {
|
|
1024
|
-
if (type === 'array' || type === 'Array') {
|
|
1025
|
-
shared_objects[name] = value || [];
|
|
1026
|
-
} else {
|
|
1027
|
-
shared_objects[name] = value || {};
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
return shared_objects[name];
|
|
1032
|
-
});
|
|
1033
|
-
|
|
1034
|
-
/**
|
|
1035
|
-
* Get an object id,
|
|
1036
|
-
* return undefined if no valid data was given (instead of throwing an error)
|
|
1037
|
-
*
|
|
1038
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1039
|
-
* @since 0.0.1
|
|
1040
|
-
* @version 0.4.0
|
|
1041
|
-
*
|
|
1042
|
-
* @param {String|ObjectID} obj
|
|
1043
|
-
*
|
|
1044
|
-
* @return {ObjectID|undefined}
|
|
1045
|
-
*/
|
|
1046
|
-
Alchemy.setMethod(function castObjectId(obj) {
|
|
1047
|
-
|
|
1048
|
-
var type = typeof obj;
|
|
1049
|
-
|
|
1050
|
-
if (obj && type === 'object' && obj.constructor && obj.constructor.name === 'ObjectID') {
|
|
1051
|
-
return obj;
|
|
1052
|
-
} else if (type === 'string' && obj.isObjectId()) {
|
|
1053
|
-
return alchemy.ObjectId(obj);
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
return undefined;
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
/**
|
|
1060
|
-
* See if the given object is a stream
|
|
1061
|
-
*
|
|
1062
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1063
|
-
* @since 0.2.0
|
|
1064
|
-
* @version 1.0.5
|
|
1065
|
-
*
|
|
1066
|
-
* @return {Boolean}
|
|
1067
|
-
*/
|
|
1068
|
-
Alchemy.setMethod(function isStream(obj) {
|
|
1069
|
-
return obj && (typeof obj._read == 'function' || typeof obj._write == 'function') && typeof obj.on === 'function';
|
|
1070
|
-
});
|
|
1071
|
-
|
|
1072
|
-
/**
|
|
1073
|
-
* Get or create a new cache instance
|
|
1074
|
-
*
|
|
1075
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1076
|
-
* @since 1.0.0
|
|
1077
|
-
* @version 1.0.4
|
|
1078
|
-
*
|
|
1079
|
-
* @param {String} name
|
|
1080
|
-
* @param {Number|Object} options
|
|
1081
|
-
*
|
|
1082
|
-
* @return {Develry.Cache}
|
|
1083
|
-
*/
|
|
1084
|
-
Alchemy.setMethod(function getCache(name, options) {
|
|
1085
|
-
|
|
1086
|
-
var instance,
|
|
1087
|
-
duration,
|
|
1088
|
-
config,
|
|
1089
|
-
type;
|
|
1090
|
-
|
|
1091
|
-
if (this.caches[name]) {
|
|
1092
|
-
return this.caches[name];
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
if (!options) {
|
|
1096
|
-
options = {};
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
type = typeof options;
|
|
1100
|
-
|
|
1101
|
-
if (type == 'number' || type == 'string') {
|
|
1102
|
-
options = {
|
|
1103
|
-
max_age : options,
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
config = Object.assign({
|
|
1108
|
-
max_length : 5000,
|
|
1109
|
-
}, options);
|
|
1110
|
-
|
|
1111
|
-
// @TODO: Fixed in 0.6.1
|
|
1112
|
-
instance = new Blast.Classes.Develry.Cache();
|
|
1113
|
-
Object.assign(instance, config);
|
|
1114
|
-
|
|
1115
|
-
this.caches[name] = instance;
|
|
1116
|
-
|
|
1117
|
-
return instance;
|
|
1118
|
-
});
|
|
1119
|
-
|
|
1120
|
-
/**
|
|
1121
|
-
* Get a route
|
|
1122
|
-
*
|
|
1123
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1124
|
-
* @since 1.1.3
|
|
1125
|
-
* @version 1.1.3
|
|
1126
|
-
*
|
|
1127
|
-
* @param {String} href The href or route name
|
|
1128
|
-
* @param {Object} parameters Route parameters
|
|
1129
|
-
*
|
|
1130
|
-
* @return {String}
|
|
1131
|
-
*/
|
|
1132
|
-
Alchemy.setMethod(function routeUrl(href, parameters) {
|
|
1133
|
-
|
|
1134
|
-
let temp = Router.getUrl(href, parameters);
|
|
1135
|
-
|
|
1136
|
-
if (temp && temp.href) {
|
|
1137
|
-
temp = String(temp);
|
|
1138
|
-
|
|
1139
|
-
if (temp) {
|
|
1140
|
-
return temp;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
return href;
|
|
1145
|
-
});
|
|
1146
|
-
|
|
1147
|
-
/**
|
|
1148
|
-
* Get paths that should be cached by the client
|
|
1149
|
-
*
|
|
1150
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1151
|
-
* @since 1.0.7
|
|
1152
|
-
* @version 1.0.7
|
|
1153
|
-
*
|
|
1154
|
-
* @return {Pledge}
|
|
1155
|
-
*/
|
|
1156
|
-
Alchemy.decorateMethod(Blast.Decorators.memoize(), function getAppcachePaths() {
|
|
1157
|
-
|
|
1158
|
-
var paths = [];
|
|
1159
|
-
|
|
1160
|
-
return Function.parallel(function getHawkejsTemplates(next) {
|
|
1161
|
-
|
|
1162
|
-
var templates = [],
|
|
1163
|
-
directories = alchemy.hawkejs.directories.getSorted(),
|
|
1164
|
-
tasks = [],
|
|
1165
|
-
i;
|
|
1166
|
-
|
|
1167
|
-
function checkDirectory(dir_path, mount_path, next) {
|
|
1168
|
-
fs.readdir(dir_path, function gotDir(err, files) {
|
|
1169
|
-
|
|
1170
|
-
if (err) {
|
|
1171
|
-
|
|
1172
|
-
if (err.code == 'ENOENT') {
|
|
1173
|
-
return next();
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
return next(err);
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
let tasks = [],
|
|
1180
|
-
i;
|
|
1181
|
-
|
|
1182
|
-
for (i = 0; i < files.length; i++) {
|
|
1183
|
-
let file = files[i],
|
|
1184
|
-
full_path = libpath.resolve(dir_path, file),
|
|
1185
|
-
full_mount_path = mount_path + '/' + file;
|
|
1186
|
-
|
|
1187
|
-
tasks.push(function checkPath(next) {
|
|
1188
|
-
fs.stat(full_path, function gotStat(err, stat) {
|
|
1189
|
-
|
|
1190
|
-
if (err) {
|
|
1191
|
-
|
|
1192
|
-
if (err.code == 'ENOENT') {
|
|
1193
|
-
return next();
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
return next(err);
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
if (stat.isDirectory()) {
|
|
1200
|
-
return checkDirectory(full_path, full_mount_path, next);
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
if (stat.isFile()) {
|
|
1204
|
-
if (file.endsWith('.ejs') || file.endsWith('.hwk')) {
|
|
1205
|
-
|
|
1206
|
-
if (full_mount_path[0] == '/') {
|
|
1207
|
-
full_mount_path = full_mount_path.slice(1);
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
templates.push(full_mount_path);
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
next();
|
|
1215
|
-
});
|
|
1216
|
-
});
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
Function.parallel(tasks, next);
|
|
1220
|
-
});
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
for (i = 0; i < directories.length; i++) {
|
|
1224
|
-
let directory = directories[i];
|
|
1225
|
-
|
|
1226
|
-
tasks.push(function readDir(next) {
|
|
1227
|
-
checkDirectory(directory, '', next);
|
|
1228
|
-
});
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
return Function.parallel(tasks, function done(err) {
|
|
1232
|
-
|
|
1233
|
-
if (err) {
|
|
1234
|
-
return next(err);
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
let path,
|
|
1238
|
-
url,
|
|
1239
|
-
i;
|
|
1240
|
-
|
|
1241
|
-
for (i = 0; i < templates.length; i++) {
|
|
1242
|
-
path = templates[i];
|
|
1243
|
-
url = '/hawkejs/templates?name[0]=' + encodeURIComponent(path.beforeLast('.ejs')) + '&v=' + alchemy.package.version;
|
|
1244
|
-
paths.push(url);
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
next();
|
|
1248
|
-
});
|
|
1249
|
-
}, function done(err) {
|
|
1250
|
-
|
|
1251
|
-
if (err) {
|
|
1252
|
-
return;
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
return paths;
|
|
1256
|
-
});
|
|
1257
|
-
});
|
|
1258
|
-
|
|
1259
|
-
/**
|
|
1260
|
-
* Get the appcache manifest text
|
|
1261
|
-
*
|
|
1262
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1263
|
-
* @since 1.0.7
|
|
1264
|
-
* @version 1.0.7
|
|
1265
|
-
*
|
|
1266
|
-
* @return {Pledge}
|
|
1267
|
-
*/
|
|
1268
|
-
Alchemy.decorateMethod(Blast.Decorators.memoize(), function getAppcacheManifest() {
|
|
1269
|
-
|
|
1270
|
-
return Function.series(function gotPaths(next) {
|
|
1271
|
-
alchemy.getAppcachePaths().done(next);
|
|
1272
|
-
}, function createText(err, result) {
|
|
1273
|
-
|
|
1274
|
-
if (err) {
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
let manifest = 'CACHE MANIFEST\n\n',
|
|
1279
|
-
entry,
|
|
1280
|
-
url,
|
|
1281
|
-
key,
|
|
1282
|
-
i;
|
|
1283
|
-
|
|
1284
|
-
manifest += 'CACHE:\n';
|
|
1285
|
-
|
|
1286
|
-
// Allways add the client script
|
|
1287
|
-
manifest += '/hawkejs/hawkejs-client.js?v=' + alchemy.package.version + '\n';
|
|
1288
|
-
|
|
1289
|
-
if (ac_entries.cache && ac_entries.cache.length) {
|
|
1290
|
-
for (key in ac_entries.cache) {
|
|
1291
|
-
manifest += ac_entries.cache[key].url + '\n';
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
for (i = 0; i < result[0].length; i++) {
|
|
1296
|
-
url = result[0][i];
|
|
1297
|
-
|
|
1298
|
-
manifest += url + '\n';
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
manifest += '\n';
|
|
1302
|
-
manifest += 'NETWORK:\n*\n\n';
|
|
1303
|
-
|
|
1304
|
-
// This will cause a cache update each time the server is reset
|
|
1305
|
-
manifest += '#' + alchemy.package.version + '-' + alchemy.discovery_id;
|
|
1306
|
-
|
|
1307
|
-
return manifest;
|
|
1308
|
-
});
|
|
1309
|
-
});
|
|
1310
|
-
|
|
1311
|
-
/**
|
|
1312
|
-
* Add an appcache entry
|
|
1313
|
-
*
|
|
1314
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1315
|
-
* @since 1.0.7
|
|
1316
|
-
* @version 1.0.7
|
|
1317
|
-
*
|
|
1318
|
-
* @param {String|Object}
|
|
1319
|
-
*/
|
|
1320
|
-
Alchemy.setMethod(function addAppcacheEntry(entry) {
|
|
1321
|
-
|
|
1322
|
-
if (typeof entry == 'string') {
|
|
1323
|
-
entry = {
|
|
1324
|
-
url : entry
|
|
1325
|
-
};
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
if (!entry.type) {
|
|
1329
|
-
entry.type = 'cache';
|
|
1330
|
-
} else {
|
|
1331
|
-
entry.type = entry.type.toLowerCase();
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
if (!ac_entries[entry.type]) {
|
|
1335
|
-
ac_entries[entry.type] = [];
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
ac_entries[entry.type].push(entry);
|
|
1339
|
-
});
|
|
1340
|
-
|
|
1341
|
-
/**
|
|
1342
|
-
* Get the body of an IncomingMessage
|
|
1343
|
-
*
|
|
1344
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1345
|
-
* @since 1.1.0
|
|
1346
|
-
* @version 1.1.0
|
|
1347
|
-
*
|
|
1348
|
-
* @param {IncomingMessage} req
|
|
1349
|
-
* @param {OutgoingMessage} res Optional
|
|
1350
|
-
* @param {Function} callback
|
|
1351
|
-
*/
|
|
1352
|
-
Alchemy.setMethod(function parseRequestBody(req, res, callback) {
|
|
1353
|
-
|
|
1354
|
-
const conduit = req.conduit;
|
|
1355
|
-
|
|
1356
|
-
if (typeof res == 'function') {
|
|
1357
|
-
callback = res;
|
|
1358
|
-
res = null;
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
if (req.original) {
|
|
1362
|
-
req = req.original;
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
if (req.body != null) {
|
|
1366
|
-
return callback(null, req.body);
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
// Multipart data is handled by "formidable"
|
|
1370
|
-
if (req.headers['content-type'] && req.headers['content-type'].startsWith('multipart/form-data')) {
|
|
1371
|
-
|
|
1372
|
-
let form = new formidable.IncomingForm();
|
|
1373
|
-
|
|
1374
|
-
// md5 hash by default
|
|
1375
|
-
form.hash = 'md5';
|
|
1376
|
-
|
|
1377
|
-
form.parse(req, function parsedMultipart(err, form_fields, form_files) {
|
|
1378
|
-
|
|
1379
|
-
var fields = {},
|
|
1380
|
-
files = {},
|
|
1381
|
-
key;
|
|
1382
|
-
|
|
1383
|
-
if (err && req.conduit && req.conduit.aborted) {
|
|
1384
|
-
return callback(null);
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
// Fix the field names
|
|
1388
|
-
for (key in form_fields) {
|
|
1389
|
-
Object.setFormPath(fields, key, form_fields[key]);
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
// Fix the file names
|
|
1393
|
-
for (key in form_files) {
|
|
1394
|
-
Object.setFormPath(files, key, form_files[key]);
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
if (err) {
|
|
1398
|
-
log.error('Error parsing multipart POST', {err: err});
|
|
1399
|
-
req.body = {};
|
|
1400
|
-
req.files = {};
|
|
1401
|
-
} else {
|
|
1402
|
-
req.body = fields;
|
|
1403
|
-
req.files = files;
|
|
1404
|
-
|
|
1405
|
-
if (conduit) {
|
|
1406
|
-
conduit.setRequestBody(fields);
|
|
1407
|
-
conduit.setRequestFiles(files);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
callback(null, fields);
|
|
1412
|
-
});
|
|
1413
|
-
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
// Regular form-encoded data
|
|
1418
|
-
if (req.headers['content-type'] && req.headers['content-type'].indexOf('form-urlencoded') > -1) {
|
|
1419
|
-
|
|
1420
|
-
urlFormBody(req, res, function parsedBody(err) {
|
|
1421
|
-
|
|
1422
|
-
if (err && req.conduit && req.conduit.aborted) {
|
|
1423
|
-
return callback(null);
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
// You can't send files using a regular post
|
|
1427
|
-
req.files = {};
|
|
1428
|
-
|
|
1429
|
-
if (err) {
|
|
1430
|
-
log.error('Error parsing x-www-form-urlencoded body data', {err: err});
|
|
1431
|
-
req.body = {};
|
|
1432
|
-
} else {
|
|
1433
|
-
req.body = req.body;
|
|
1434
|
-
|
|
1435
|
-
if (conduit) {
|
|
1436
|
-
conduit.setRequestBody(req.body);
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
callback(null, req.body);
|
|
1441
|
-
});
|
|
1442
|
-
|
|
1443
|
-
return;
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
// Any other encoded data (like JSON)
|
|
1447
|
-
anyBody(req, function parsedBody(err, body) {
|
|
1448
|
-
|
|
1449
|
-
if (err && req.conduit && req.conduit.aborted) {
|
|
1450
|
-
return callback(null);
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
// You can't send files using a regular post
|
|
1454
|
-
req.files = {};
|
|
1455
|
-
|
|
1456
|
-
if (err) {
|
|
1457
|
-
log.error('Error parsing body data', {err: err});
|
|
1458
|
-
req.body = {};
|
|
1459
|
-
} else {
|
|
1460
|
-
req.body = body;
|
|
1461
|
-
|
|
1462
|
-
if (conduit) {
|
|
1463
|
-
conduit.setRequestBody(body);
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
callback(null, req.body);
|
|
1468
|
-
});
|
|
1469
|
-
});
|
|
1470
|
-
|
|
1471
|
-
/**
|
|
1472
|
-
* Export all data
|
|
1473
|
-
*
|
|
1474
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1475
|
-
* @since 1.0.5
|
|
1476
|
-
* @version 1.0.5
|
|
1477
|
-
*
|
|
1478
|
-
* @return {Stream}
|
|
1479
|
-
*/
|
|
1480
|
-
Alchemy.setMethod(function createExportStream(options) {
|
|
1481
|
-
|
|
1482
|
-
var stream = new require('stream').PassThrough();
|
|
1483
|
-
|
|
1484
|
-
this.exportToStream(stream, options);
|
|
1485
|
-
|
|
1486
|
-
return stream;
|
|
1487
|
-
});
|
|
1488
|
-
|
|
1489
|
-
/**
|
|
1490
|
-
* Export all data to stream
|
|
1491
|
-
*
|
|
1492
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1493
|
-
* @since 1.0.5
|
|
1494
|
-
* @version 1.0.5
|
|
1495
|
-
*
|
|
1496
|
-
* @param {Stream} output
|
|
1497
|
-
* @param {Object} options
|
|
1498
|
-
*
|
|
1499
|
-
* @return {Pledge}
|
|
1500
|
-
*/
|
|
1501
|
-
Alchemy.setMethod(function exportToStream(output, options) {
|
|
1502
|
-
|
|
1503
|
-
if (!alchemy.isStream(output)) {
|
|
1504
|
-
if (!options) {
|
|
1505
|
-
options = output;
|
|
1506
|
-
output = null;
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
output = options.output;
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
if (!output) {
|
|
1513
|
-
return Pledge.reject(new Error('No target output stream has been given'));
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
if (!options) {
|
|
1517
|
-
options = {};
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
let tasks = [],
|
|
1521
|
-
i;
|
|
1522
|
-
|
|
1523
|
-
for (i = 0; i < Model.children.length; i++) {
|
|
1524
|
-
let model = Model.children[i];
|
|
1525
|
-
|
|
1526
|
-
tasks.push(async function exportModel(next) {
|
|
1527
|
-
await (new model).exportToStream(output);
|
|
1528
|
-
next();
|
|
1529
|
-
});
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
return Function.series(tasks, function done(err) {
|
|
1533
|
-
|
|
1534
|
-
if (err) {
|
|
1535
|
-
return output.emit('error', err);
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
output.end();
|
|
1539
|
-
});
|
|
1540
|
-
});
|
|
1541
|
-
|
|
1542
|
-
/**
|
|
1543
|
-
* Import from a stream
|
|
1544
|
-
*
|
|
1545
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1546
|
-
* @since 1.0.5
|
|
1547
|
-
* @version 1.0.5
|
|
1548
|
-
*
|
|
1549
|
-
* @param {Stream} input
|
|
1550
|
-
* @param {Object} options
|
|
1551
|
-
*
|
|
1552
|
-
* @return {Pledge}
|
|
1553
|
-
*/
|
|
1554
|
-
Alchemy.setMethod(function importFromStream(input, options) {
|
|
1555
|
-
|
|
1556
|
-
if (!alchemy.isStream(input)) {
|
|
1557
|
-
if (!options) {
|
|
1558
|
-
options = input;
|
|
1559
|
-
input = null;
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
input = options.input;
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
if (!input) {
|
|
1566
|
-
return Pledge.reject(new Error('No source input stream has been given'));
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
if (!options) {
|
|
1570
|
-
options = {};
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
let that = this,
|
|
1574
|
-
current_type = null,
|
|
1575
|
-
extra_stream,
|
|
1576
|
-
pledge = new Pledge(),
|
|
1577
|
-
stopped,
|
|
1578
|
-
paused,
|
|
1579
|
-
buffer,
|
|
1580
|
-
model,
|
|
1581
|
-
value,
|
|
1582
|
-
seen = 0,
|
|
1583
|
-
left,
|
|
1584
|
-
size,
|
|
1585
|
-
doc;
|
|
1586
|
-
|
|
1587
|
-
input.on('data', function onData(data) {
|
|
1588
|
-
|
|
1589
|
-
if (stopped) {
|
|
1590
|
-
return;
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
if (buffer) {
|
|
1594
|
-
buffer = Buffer.concat([buffer, data]);
|
|
1595
|
-
} else {
|
|
1596
|
-
buffer = data;
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
handleBuffer();
|
|
1600
|
-
});
|
|
1601
|
-
|
|
1602
|
-
function handleBuffer() {
|
|
1603
|
-
|
|
1604
|
-
if (paused) {
|
|
1605
|
-
return;
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
if (!current_type && buffer.length < 2) {
|
|
1609
|
-
return;
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
if (!current_type) {
|
|
1613
|
-
current_type = buffer.readUInt8(0);
|
|
1614
|
-
|
|
1615
|
-
if (current_type == 0x01) {
|
|
1616
|
-
size = buffer.readUInt8(1);
|
|
1617
|
-
buffer = buffer.slice(2);
|
|
1618
|
-
} else if (current_type == 0x02 && buffer.length >= 5) {
|
|
1619
|
-
size = buffer.readUInt32BE(1);
|
|
1620
|
-
buffer = buffer.slice(5);
|
|
1621
|
-
} else if (current_type == 0xFF) {
|
|
1622
|
-
size = buffer.readUInt32BE(1);
|
|
1623
|
-
buffer = buffer.slice(5);
|
|
1624
|
-
seen = 0;
|
|
1625
|
-
|
|
1626
|
-
if (!doc) {
|
|
1627
|
-
stopped = true;
|
|
1628
|
-
pledge.reject(new Error('Found extra import data, but no active document'));
|
|
1629
|
-
} else {
|
|
1630
|
-
extra_stream = new require('stream').PassThrough();
|
|
1631
|
-
doc.extraImportFromStream(extra_stream);
|
|
1632
|
-
}
|
|
1633
|
-
} else {
|
|
1634
|
-
// Not enough data? Wait
|
|
1635
|
-
current_type = null;
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
handleRest();
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
function handleRest() {
|
|
1644
|
-
|
|
1645
|
-
if (current_type == 0xFF) {
|
|
1646
|
-
left = size - seen;
|
|
1647
|
-
value = buffer.slice(0, left);
|
|
1648
|
-
|
|
1649
|
-
seen += value.length;
|
|
1650
|
-
|
|
1651
|
-
if (value.length == buffer.length) {
|
|
1652
|
-
buffer = null;
|
|
1653
|
-
} else if (value.length < buffer.length) {
|
|
1654
|
-
buffer = buffer.slice(left);
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
extra_stream.write(value);
|
|
1658
|
-
|
|
1659
|
-
if (value.length == left) {
|
|
1660
|
-
extra_stream.end();
|
|
1661
|
-
current_type = null;
|
|
1662
|
-
|
|
1663
|
-
if (buffer) {
|
|
1664
|
-
handleBuffer();
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
return;
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
if (buffer.length >= size) {
|
|
1672
|
-
value = buffer.slice(0, size);
|
|
1673
|
-
buffer = buffer.slice(size);
|
|
1674
|
-
} else {
|
|
1675
|
-
// Wait for next call
|
|
1676
|
-
return;
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
if (current_type == 0x01) {
|
|
1680
|
-
value = value.toString();
|
|
1681
|
-
|
|
1682
|
-
if (!model || model.model_name != value) {
|
|
1683
|
-
model = Model.get(value);
|
|
1684
|
-
doc = null;
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
if (!model) {
|
|
1688
|
-
stopped = true;
|
|
1689
|
-
return pledge.reject(new Error('Could not find Model "' + value + '"'));
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
current_type = null;
|
|
1693
|
-
size = 0;
|
|
1694
|
-
} else if (current_type == 0x02) {
|
|
1695
|
-
doc = model.createDocument();
|
|
1696
|
-
input.pause();
|
|
1697
|
-
paused = true;
|
|
1698
|
-
|
|
1699
|
-
doc.importFromBuffer(value).done(function done(err, result) {
|
|
1700
|
-
|
|
1701
|
-
if (err) {
|
|
1702
|
-
stopped = true;
|
|
1703
|
-
return pledge.reject(err);
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
|
-
current_type = null;
|
|
1707
|
-
paused = false;
|
|
1708
|
-
input.resume();
|
|
1709
|
-
|
|
1710
|
-
handleBuffer();
|
|
1711
|
-
});
|
|
1712
|
-
|
|
1713
|
-
return;
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
if (buffer && buffer.length) {
|
|
1717
|
-
handleBuffer();
|
|
1718
|
-
}
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
return pledge;
|
|
1722
|
-
});
|
|
1723
|
-
|
|
1724
|
-
/**
|
|
1725
|
-
*
|
|
1726
|
-
*
|
|
1727
|
-
* @author Jelle De Loecker <jelle@
|
|
1728
|
-
* @since
|
|
1729
|
-
* @version
|
|
1730
|
-
*
|
|
1731
|
-
* @
|
|
1732
|
-
*/
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
*
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
* @
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var shared_objects = {},
|
|
4
|
+
plugModules = null,
|
|
5
|
+
usedModules = {},
|
|
6
|
+
useErrors = {},
|
|
7
|
+
usePaths = {},
|
|
8
|
+
ac_entries = {},
|
|
9
|
+
parseArgs = require('minimist'),
|
|
10
|
+
libpath = require('path'),
|
|
11
|
+
colors = require('ansi-256-colors'),
|
|
12
|
+
fs = require('fs');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The Alchemy class
|
|
16
|
+
*
|
|
17
|
+
* @constructor
|
|
18
|
+
*
|
|
19
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
20
|
+
* @since 0.0.1
|
|
21
|
+
* @version 1.1.0
|
|
22
|
+
*/
|
|
23
|
+
global.Alchemy = Function.inherits('Informer', 'Alchemy', function Alchemy() {
|
|
24
|
+
|
|
25
|
+
var that = this,
|
|
26
|
+
package_json;
|
|
27
|
+
|
|
28
|
+
// Only allow a single instance of the Alchemy class
|
|
29
|
+
if (global.alchemy) {
|
|
30
|
+
return global.alchemy;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Timestamp when alchemy started
|
|
34
|
+
this.start_time = Date.now();
|
|
35
|
+
|
|
36
|
+
// Current working directory
|
|
37
|
+
this.cwd = process.cwd();
|
|
38
|
+
|
|
39
|
+
// Parsed arguments
|
|
40
|
+
this.argv = parseArgs(process.argv.slice(2));
|
|
41
|
+
|
|
42
|
+
// The id of this server instance
|
|
43
|
+
this.discovery_id = Crypto.pseudoHex();
|
|
44
|
+
|
|
45
|
+
// Link to the colors module
|
|
46
|
+
this.colors = colors;
|
|
47
|
+
|
|
48
|
+
// The session count
|
|
49
|
+
this.session_count = 0;
|
|
50
|
+
|
|
51
|
+
// Plugins to be loaded will be stored in here, with their options
|
|
52
|
+
this.plugins = {};
|
|
53
|
+
|
|
54
|
+
// Certain required modules can be registered under a name
|
|
55
|
+
this.modules = {};
|
|
56
|
+
|
|
57
|
+
// Link to all used modules
|
|
58
|
+
this.modules_loaded = usedModules;
|
|
59
|
+
|
|
60
|
+
// Link to failed modules
|
|
61
|
+
this.modules_error = useErrors;
|
|
62
|
+
|
|
63
|
+
// Try getting the app package.json file
|
|
64
|
+
try {
|
|
65
|
+
package_json = require(libpath.resolve(PATH_ROOT, 'package.json'));
|
|
66
|
+
} catch (err) {
|
|
67
|
+
package_json = {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The app package.json as an object
|
|
71
|
+
this.package = package_json;
|
|
72
|
+
|
|
73
|
+
// Now get the alchemymvc package.json file
|
|
74
|
+
try {
|
|
75
|
+
package_json = require(libpath.resolve(PATH_CORE, '..', 'package.json'));
|
|
76
|
+
} catch (err) {
|
|
77
|
+
package_json = {};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Get the alchemy core version
|
|
81
|
+
this.version = package_json.version;
|
|
82
|
+
|
|
83
|
+
// Keep status
|
|
84
|
+
this.status = {};
|
|
85
|
+
|
|
86
|
+
// All caches
|
|
87
|
+
this.caches = {};
|
|
88
|
+
|
|
89
|
+
// Also store the version in the process versions object
|
|
90
|
+
process.versions.alchemy = this.version;
|
|
91
|
+
|
|
92
|
+
// Also store the version of the app
|
|
93
|
+
process.versions.alchemy_app = this.package.version;
|
|
94
|
+
|
|
95
|
+
// Load the settings
|
|
96
|
+
this.loadSettings();
|
|
97
|
+
|
|
98
|
+
// Listen to messages from parent processes
|
|
99
|
+
process.on('message', function gotMessage(message) {
|
|
100
|
+
if (typeof message == 'string') {
|
|
101
|
+
return that.emit(message);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (message && message.type) {
|
|
105
|
+
return that.emit(message.type, message.data);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Get Janeway
|
|
110
|
+
this.Janeway = this.use('janeway');
|
|
111
|
+
|
|
112
|
+
// Asign the Janeway levels
|
|
113
|
+
Object.assign(this, this.Janeway.LEVELS);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
if (this.argv['stream-janeway']) {
|
|
117
|
+
this.startJaneway({stream: true});
|
|
118
|
+
} else if (this.allow_janeway) {
|
|
119
|
+
this.startJaneway();
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
log.warn('Failed to start Janeway:', err);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* See if running janeway is allowed
|
|
128
|
+
*
|
|
129
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
130
|
+
* @since 0.5.0
|
|
131
|
+
* @version 0.5.0
|
|
132
|
+
*
|
|
133
|
+
* @type {Boolean}
|
|
134
|
+
*/
|
|
135
|
+
Alchemy.prepareProperty(function allow_janeway() {
|
|
136
|
+
|
|
137
|
+
// Setting the --disable-janeway flag explicitly disabled ALL forms of janeway
|
|
138
|
+
if (this.argv['disable-janeway'] || process.env.DISABLE_JANEWAY) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// You can also disable janeway in the settings
|
|
143
|
+
if (this.settings.janeway === false) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (Blast.isNW || !process.stdout.isTTY) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return true;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Expirable object where sessions are stored
|
|
156
|
+
*
|
|
157
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
158
|
+
* @since 0.5.0
|
|
159
|
+
* @version 1.0.4
|
|
160
|
+
*
|
|
161
|
+
* @type {Develry.Cache}
|
|
162
|
+
*/
|
|
163
|
+
Alchemy.prepareProperty(function sessions() {
|
|
164
|
+
|
|
165
|
+
var cache = this.getCache('sessions', {
|
|
166
|
+
max_idle : alchemy.settings.session_length,
|
|
167
|
+
max_length : Infinity
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
cache.on('removed', function onRemoved(value, key) {
|
|
171
|
+
// @TODO: check if expired?
|
|
172
|
+
value.removed();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
return cache;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Expirable object where sessions are temporarily stored
|
|
180
|
+
* based on the browser fingerprints
|
|
181
|
+
*
|
|
182
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
183
|
+
* @since 1.1.0
|
|
184
|
+
* @version 1.1.0
|
|
185
|
+
*
|
|
186
|
+
* @type {Develry.Cache}
|
|
187
|
+
*/
|
|
188
|
+
Alchemy.prepareProperty(function fingerprints() {
|
|
189
|
+
|
|
190
|
+
var cache = this.getCache('fingerprints', {
|
|
191
|
+
max_idle : '3 minutes',
|
|
192
|
+
max_length : 3000
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return cache;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get or set the environment
|
|
200
|
+
*
|
|
201
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
202
|
+
* @since 0.4.0
|
|
203
|
+
* @version 0.4.0
|
|
204
|
+
*
|
|
205
|
+
* @type {String}
|
|
206
|
+
*/
|
|
207
|
+
Alchemy.setProperty(function environment() {
|
|
208
|
+
return alchemy.settings.environment;
|
|
209
|
+
}, function set_environment(value) {
|
|
210
|
+
alchemy.settings.environment = String(value);
|
|
211
|
+
return alchemy.settings.environment;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Start janeway
|
|
216
|
+
*
|
|
217
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
218
|
+
* @since 0.5.0
|
|
219
|
+
* @version 1.1.0
|
|
220
|
+
*
|
|
221
|
+
* @param {Object} options
|
|
222
|
+
*/
|
|
223
|
+
Alchemy.setMethod(function startJaneway(options) {
|
|
224
|
+
|
|
225
|
+
if (this.Janeway.started) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!options) {
|
|
230
|
+
options = {};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (options.stream) {
|
|
234
|
+
let that = this,
|
|
235
|
+
screen,
|
|
236
|
+
out;
|
|
237
|
+
|
|
238
|
+
out = new require('net').Socket({fd: 4, writable: true});
|
|
239
|
+
|
|
240
|
+
out.columns = 80;
|
|
241
|
+
out.rows = 24;
|
|
242
|
+
|
|
243
|
+
screen = this.Janeway.createScreen({
|
|
244
|
+
input : process.stdin,
|
|
245
|
+
terminal : 'xterm-256color',
|
|
246
|
+
output : out
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
options.screen = screen;
|
|
250
|
+
|
|
251
|
+
// Also output to stdout
|
|
252
|
+
options.output_to_stdout = true;
|
|
253
|
+
|
|
254
|
+
// Keep regular stdout color
|
|
255
|
+
options.keep_color = true;
|
|
256
|
+
|
|
257
|
+
// Don't mess with the indentation
|
|
258
|
+
options.change_indent = false;
|
|
259
|
+
|
|
260
|
+
this.on('janeway_propose_geometry', function onProposeGeometry(data) {
|
|
261
|
+
out.columns = data.cols || data.width;
|
|
262
|
+
out.rows = data.rows || data.height;
|
|
263
|
+
out.emit('resize');
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
screen.on('resize', function onResize(a, b) {
|
|
267
|
+
that.Janeway.redraw();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
this.on('janeway_redraw', function onRedrawRequest() {
|
|
271
|
+
that.Janeway.redraw();
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
this.Janeway.started = true;
|
|
276
|
+
this.Janeway.start(options);
|
|
277
|
+
|
|
278
|
+
if (this.settings.title) {
|
|
279
|
+
let title = this.settings.title;
|
|
280
|
+
|
|
281
|
+
if (this.settings.titleized) {
|
|
282
|
+
title = 'Alchemy: ' + title;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this.Janeway.setTitle(title);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (this.settings.session_menu) {
|
|
289
|
+
|
|
290
|
+
let session_menu = this.Janeway.addIndicator('⌨ ');
|
|
291
|
+
|
|
292
|
+
if (!session_menu.addItem) {
|
|
293
|
+
return session_menu.remove();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
this.Janeway.session_menu = session_menu;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Log messages of level 5 (info)
|
|
303
|
+
*
|
|
304
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
305
|
+
* @since 0.0.1
|
|
306
|
+
* @version 0.4.0
|
|
307
|
+
*/
|
|
308
|
+
Alchemy.setMethod(function log(...args) {
|
|
309
|
+
return alchemy.printLog(5, args, {level: 3});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Actually print a log message
|
|
314
|
+
*
|
|
315
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
316
|
+
* @since 0.4.0
|
|
317
|
+
* @version 1.1.0
|
|
318
|
+
*
|
|
319
|
+
* @param {Number} level
|
|
320
|
+
* @param {Array} args
|
|
321
|
+
* @param {Object} options
|
|
322
|
+
*/
|
|
323
|
+
Alchemy.setMethod(function printLog(level, args, options) {
|
|
324
|
+
|
|
325
|
+
var type,
|
|
326
|
+
line;
|
|
327
|
+
|
|
328
|
+
if (this.settings.silent) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (!Array.isArray(args)) {
|
|
333
|
+
args = [args];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (typeof level == 'string') {
|
|
337
|
+
type = level;
|
|
338
|
+
} else {
|
|
339
|
+
if (level < 3) {
|
|
340
|
+
type = 'error';
|
|
341
|
+
} else if (level < 5) {
|
|
342
|
+
type = 'warn';
|
|
343
|
+
} else {
|
|
344
|
+
type = 'info';
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (this.Janeway != null) {
|
|
349
|
+
line = this.Janeway.print(type, args, options);
|
|
350
|
+
|
|
351
|
+
if (options && options.gutter && line) {
|
|
352
|
+
line.setGutter(options.gutter)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return line;
|
|
356
|
+
} else {
|
|
357
|
+
console[type](...args);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Load the settings
|
|
363
|
+
*
|
|
364
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
365
|
+
* @since 0.4.0
|
|
366
|
+
* @version 1.1.6
|
|
367
|
+
*/
|
|
368
|
+
Alchemy.setMethod(function loadSettings() {
|
|
369
|
+
|
|
370
|
+
var default_path,
|
|
371
|
+
port_error,
|
|
372
|
+
local_path,
|
|
373
|
+
env_config,
|
|
374
|
+
env_path,
|
|
375
|
+
settings,
|
|
376
|
+
local,
|
|
377
|
+
env;
|
|
378
|
+
|
|
379
|
+
if (this.settings) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Create the settings object
|
|
384
|
+
this.settings = settings = {};
|
|
385
|
+
|
|
386
|
+
// Generate the path to the default settings file
|
|
387
|
+
default_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'default');
|
|
388
|
+
|
|
389
|
+
// Get default settings
|
|
390
|
+
try {
|
|
391
|
+
Object.assign(settings, require(default_path));
|
|
392
|
+
} catch (err) {
|
|
393
|
+
settings.no_default_file = default_path;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Generate the path to the local settings file
|
|
397
|
+
local_path = libpath.resolve(PATH_ROOT, 'app', 'config', 'local');
|
|
398
|
+
|
|
399
|
+
// Get the local settings
|
|
400
|
+
try {
|
|
401
|
+
local = require(local_path);
|
|
402
|
+
} catch(err) {
|
|
403
|
+
local = {};
|
|
404
|
+
settings.no_local_file = local_path;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Default to the 'dev' environment
|
|
408
|
+
if (!local.environment) {
|
|
409
|
+
|
|
410
|
+
if (process.env.ENV) {
|
|
411
|
+
local.environment = process.env.ENV;
|
|
412
|
+
} else {
|
|
413
|
+
local.environment = 'dev';
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
env = this.argv.env || this.argv.environment;
|
|
418
|
+
|
|
419
|
+
if (env) {
|
|
420
|
+
local.environment = env;
|
|
421
|
+
this.printLog(this.INFO, ['Switching to environment', env]);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Generate the path to the environment settings file
|
|
425
|
+
env_path = libpath.resolve(PATH_APP, 'config', local.environment, 'config');
|
|
426
|
+
|
|
427
|
+
// Get the config
|
|
428
|
+
try {
|
|
429
|
+
env_config = require(env_path);
|
|
430
|
+
} catch(err) {
|
|
431
|
+
env_config = {};
|
|
432
|
+
settings.no_env_file = env_path;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Merge all the settings in order: default - environment - local
|
|
436
|
+
Object.merge(settings, env_config, local);
|
|
437
|
+
|
|
438
|
+
if (!settings.name) {
|
|
439
|
+
settings.name = this.package.name;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (settings.title == null) {
|
|
443
|
+
if (this.package.title) {
|
|
444
|
+
// Allow users to set the title in their package file
|
|
445
|
+
settings.title = this.package.title;
|
|
446
|
+
} else if (settings.name) {
|
|
447
|
+
settings.title = settings.name.replace(/-/g, ' ').titleize();
|
|
448
|
+
settings.titleized = true;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (this.argv.port) {
|
|
453
|
+
let port = parseInt(this.argv.port);
|
|
454
|
+
|
|
455
|
+
if (port) {
|
|
456
|
+
this.printLog(this.INFO, ['Using port setting from argument:', port]);
|
|
457
|
+
settings.port = port;
|
|
458
|
+
} else {
|
|
459
|
+
this.argv.socket = this.argv.port;
|
|
460
|
+
this.argv.port = null;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (this.argv.socket) {
|
|
465
|
+
settings.port = false;
|
|
466
|
+
settings.socket = this.argv.socket;
|
|
467
|
+
|
|
468
|
+
let stat;
|
|
469
|
+
|
|
470
|
+
try {
|
|
471
|
+
stat = fs.statSync(settings.socket);
|
|
472
|
+
} catch (err) {
|
|
473
|
+
// Ignore if it doesn't exist yet
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (stat && stat.isDirectory()) {
|
|
477
|
+
settings.socket = libpath.resolve(settings.socket, settings.name + '.alchemy.sock');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
this.printLog(this.INFO, ['Using socket setting from argument:', settings.socket]);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (!settings.port && settings.port !== false) {
|
|
484
|
+
settings.port = 3000;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (settings.port > 49151) {
|
|
488
|
+
port_error = 'Could not use port number ' + String(port).bold.red + ' because ';
|
|
489
|
+
|
|
490
|
+
// Make sure the port is valid
|
|
491
|
+
if (settings.port > 65535) {
|
|
492
|
+
this.printLog(this.FATAL, [port_error + 'there is no port higher than 65535. Please use ports below 49151.']);
|
|
493
|
+
} else {
|
|
494
|
+
this.printLog(this.FATAL, [port_error + 'it\'s an ephemeral port. Please use ports below 49151.']);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
process.exit();
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (this.argv.url) {
|
|
501
|
+
settings.url = this.argv.url;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (settings.url && settings.url.indexOf('{') > -1) {
|
|
505
|
+
settings.url = settings.url.assign(settings);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (this.argv.preload) {
|
|
509
|
+
settings.preload = this.argv.preload;
|
|
510
|
+
|
|
511
|
+
if (Array.isArray(settings.preload)) {
|
|
512
|
+
settings.preload = settings.preload.last();
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (settings.preload == 'false') {
|
|
517
|
+
settings.preload = false;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
let key,
|
|
521
|
+
val;
|
|
522
|
+
|
|
523
|
+
for (key in this.argv) {
|
|
524
|
+
|
|
525
|
+
if (!key.startsWith('override-')) {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
val = this.argv[key];
|
|
530
|
+
key = key.after('override-');
|
|
531
|
+
|
|
532
|
+
if (!settings[key] || typeof settings[key] != 'object') {
|
|
533
|
+
settings[key] = val;
|
|
534
|
+
} else {
|
|
535
|
+
Object.merge(settings[key], val);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (settings.preload) {
|
|
540
|
+
this.doPreload();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Set the debug value
|
|
544
|
+
global.DEBUG = settings.debug;
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Set status
|
|
549
|
+
*
|
|
550
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
551
|
+
* @since 0.4.1
|
|
552
|
+
* @version 0.4.1
|
|
553
|
+
*/
|
|
554
|
+
Alchemy.setMethod(function setStatus(name, value) {
|
|
555
|
+
this.status[name] = value;
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Execute the function when alchemy is ready
|
|
560
|
+
*
|
|
561
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
562
|
+
* @since 0.0.1
|
|
563
|
+
* @version 1.1.2
|
|
564
|
+
*
|
|
565
|
+
* @param {Function} callback The function to execute
|
|
566
|
+
*
|
|
567
|
+
* @return {Pledge}
|
|
568
|
+
*/
|
|
569
|
+
Alchemy.setMethod(function ready(callback) {
|
|
570
|
+
|
|
571
|
+
var that = this,
|
|
572
|
+
pledge = new Pledge();
|
|
573
|
+
|
|
574
|
+
pledge.done(callback);
|
|
575
|
+
|
|
576
|
+
if (!this.sputnik) {
|
|
577
|
+
Blast.loaded(function hasLoaded() {
|
|
578
|
+
pledge.resolve(that.ready());
|
|
579
|
+
});
|
|
580
|
+
} else {
|
|
581
|
+
this.sputnik.after(['start_server', 'datasources', 'listening'], function afterReady() {
|
|
582
|
+
pledge.resolve();
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return pledge;
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Preload the client-side stuff
|
|
591
|
+
*
|
|
592
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
593
|
+
* @since 1.1.2
|
|
594
|
+
* @version 1.1.2
|
|
595
|
+
*/
|
|
596
|
+
Alchemy.setMethod(async function doPreload() {
|
|
597
|
+
|
|
598
|
+
await this.ready();
|
|
599
|
+
|
|
600
|
+
let url;
|
|
601
|
+
|
|
602
|
+
if (this.settings.url) {
|
|
603
|
+
url = this.settings.url;
|
|
604
|
+
} else if (this.settings.port) {
|
|
605
|
+
url = 'http://localhost:' + this.settings.port;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (url) {
|
|
609
|
+
log.info('Preloading url', url);
|
|
610
|
+
Blast.fetch(url);
|
|
611
|
+
|
|
612
|
+
url += '/hawkejs/hawkejs-client.js';
|
|
613
|
+
|
|
614
|
+
log.info('Preloading client file via HTTP', url);
|
|
615
|
+
Blast.fetch(url);
|
|
616
|
+
} else {
|
|
617
|
+
log.info('Preloading client file');
|
|
618
|
+
|
|
619
|
+
Blast.getClientPath({
|
|
620
|
+
modify_prototypes : true,
|
|
621
|
+
create_source_map : alchemy.settings.debug,
|
|
622
|
+
enable_coverage : !!global.__coverage__
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Resolve the provided arguments to a useable path string.
|
|
629
|
+
* Only used strings, discards objects.
|
|
630
|
+
*
|
|
631
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
632
|
+
* @since 0.0.1
|
|
633
|
+
* @version 0.4.0
|
|
634
|
+
*
|
|
635
|
+
* @param {String} path_to_dirs The path containing the dirs to load
|
|
636
|
+
*/
|
|
637
|
+
Alchemy.setMethod(function pathResolve(...path_to_dirs) {
|
|
638
|
+
|
|
639
|
+
var path_arguments,
|
|
640
|
+
i;
|
|
641
|
+
|
|
642
|
+
if (path_to_dirs.length == 1) {
|
|
643
|
+
return path_to_dirs[0];
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
path_arguments = [];
|
|
647
|
+
|
|
648
|
+
for (i = 0; i < path_to_dirs.length; i++) {
|
|
649
|
+
if (typeof path_to_dirs[i] == 'string') {
|
|
650
|
+
path_arguments.push(path_to_dirs[i]);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (path_arguments.length > 1) {
|
|
655
|
+
return libpath.resolve(...path_arguments);
|
|
656
|
+
} else {
|
|
657
|
+
return path_arguments[0];
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* A wrapper function for requiring modules
|
|
663
|
+
*
|
|
664
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
665
|
+
* @since 0.0.1
|
|
666
|
+
* @version 1.0.0
|
|
667
|
+
*
|
|
668
|
+
* @param {String} module_name The name/path of the module to load
|
|
669
|
+
* @param {String} register_as Cache the module under this name
|
|
670
|
+
* @param {Object} options Extra options
|
|
671
|
+
* @param {Boolean} options.force Force a new requirement and do not cache
|
|
672
|
+
*
|
|
673
|
+
* @return {Object} The required module
|
|
674
|
+
*/
|
|
675
|
+
Alchemy.setMethod(function use(module_name, register_as, options) {
|
|
676
|
+
|
|
677
|
+
var module,
|
|
678
|
+
result;
|
|
679
|
+
|
|
680
|
+
if (typeof register_as == 'object') {
|
|
681
|
+
options = register_as;
|
|
682
|
+
register_as = false;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Certain modules can be disabled by registering them as null
|
|
686
|
+
if (module_name == null && register_as) {
|
|
687
|
+
this.modules[register_as] = null;
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// If the module has explicitly been set to null, return that
|
|
692
|
+
if (this.modules[module_name] === null) {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (typeof options == 'undefined') options = {};
|
|
697
|
+
if (typeof options.force == 'undefined') options.force = false;
|
|
698
|
+
|
|
699
|
+
// If a module has already been registered under this name, return that
|
|
700
|
+
if (this.modules[module_name] && !options.force) {
|
|
701
|
+
return this.modules[module_name];
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (this.argv['debug-requirements']) {
|
|
705
|
+
this.printLog(this.DEBUG, ['Going to load module', module_name], {level: 2});
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
try {
|
|
709
|
+
result = this.findModule(module_name, options);
|
|
710
|
+
module = result.module;
|
|
711
|
+
} catch (err) {
|
|
712
|
+
|
|
713
|
+
if (!useErrors[module_name]) {
|
|
714
|
+
useErrors[module_name] = 0;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
useErrors[module_name]++;
|
|
718
|
+
|
|
719
|
+
if (!options.silent || this.argv['debug-requirements']) {
|
|
720
|
+
this.printLog(this.SEVERE, ['Failed to load module "' + module_name + '":', err.message], {level: 6, err: err});
|
|
721
|
+
}
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (!usedModules[module_name]) {
|
|
726
|
+
|
|
727
|
+
let entry = {
|
|
728
|
+
internal : result.internal,
|
|
729
|
+
loaded : 0
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
if (result.package) {
|
|
733
|
+
entry.version = result.package.version;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
usedModules[module_name] = result;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
usedModules[module_name].loaded++;
|
|
740
|
+
|
|
741
|
+
if (register_as) {
|
|
742
|
+
this.modules[register_as] = module;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// If a new requirement needs to be forced, clear the cache
|
|
746
|
+
if (options.force) {
|
|
747
|
+
delete require.cache[result.module_path];
|
|
748
|
+
return require(result.module_path);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return module;
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Look for a module by traversing the filesystem
|
|
757
|
+
*
|
|
758
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
759
|
+
* @since 0.0.1
|
|
760
|
+
* @version 0.4.0
|
|
761
|
+
*
|
|
762
|
+
* @param {String} startPath The path to originate the search from
|
|
763
|
+
* @param {String} moduleName
|
|
764
|
+
* @param {Number} recurse
|
|
765
|
+
*
|
|
766
|
+
* @return {String}
|
|
767
|
+
*/
|
|
768
|
+
Alchemy.setMethod(function searchModule(startPath, moduleName, recurse) {
|
|
769
|
+
|
|
770
|
+
var moduledirs,
|
|
771
|
+
module_path,
|
|
772
|
+
entries,
|
|
773
|
+
nmPath,
|
|
774
|
+
temp,
|
|
775
|
+
path,
|
|
776
|
+
key,
|
|
777
|
+
i;
|
|
778
|
+
|
|
779
|
+
// Don't do this search if it hasn't been enabled
|
|
780
|
+
// The new npm flat structure makes this an expensive thing to do
|
|
781
|
+
if (!this.settings.search_for_modules) {
|
|
782
|
+
|
|
783
|
+
// Set recurse to 3, so this is the first and last call
|
|
784
|
+
recurse = 3;
|
|
785
|
+
|
|
786
|
+
// Only add 2 folder to look through,
|
|
787
|
+
// the alchemymvc node_modules folder
|
|
788
|
+
// and the base node_modules folder
|
|
789
|
+
moduledirs = ['..', libpath.resolve(startPath, 'node_modules', 'alchemymvc')];
|
|
790
|
+
|
|
791
|
+
// Add plugin folders
|
|
792
|
+
if (!plugModules) {
|
|
793
|
+
path = libpath.resolve(PATH_ROOT, 'node_modules');
|
|
794
|
+
|
|
795
|
+
if (fs.existsSync(path)) {
|
|
796
|
+
|
|
797
|
+
// Get all the entries in the main modules folder
|
|
798
|
+
entries = fs.readdirSync(libpath.resolve(PATH_ROOT, 'node_modules'));
|
|
799
|
+
|
|
800
|
+
// Initiate the plugin modules variables
|
|
801
|
+
plugModules = [];
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
for (i = 0; i < entries.length; i++) {
|
|
805
|
+
temp = entries[i];
|
|
806
|
+
|
|
807
|
+
if (temp.startsWith('alchemy-')) {
|
|
808
|
+
plugModules.push(libpath.resolve(PATH_ROOT, 'node_modules', temp));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
} else {
|
|
812
|
+
plugModules = [];
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
for (i = 0; i < plugModules.length; i++) {
|
|
817
|
+
moduledirs.push(plugModules[i]);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
} else if (!searchModule.have_warned) {
|
|
821
|
+
searchModule.have_warned = true;
|
|
822
|
+
log.warn('The "search_for_modules" config has been enabled!');
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (!recurse) {
|
|
826
|
+
recurse = 1;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
nmPath = libpath.resolve(startPath, 'node_modules');
|
|
830
|
+
|
|
831
|
+
if (!moduledirs) {
|
|
832
|
+
// Get all the entries inside the given path
|
|
833
|
+
try {
|
|
834
|
+
moduledirs = fs.readdirSync(nmPath);
|
|
835
|
+
} catch(err) {
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Look in the base node_modules directory first
|
|
841
|
+
if (recurse == 1) {
|
|
842
|
+
moduledirs.unshift('..');
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Go over every directory in the main node_modules folder
|
|
846
|
+
for (i = 0; i < moduledirs.length; i++) {
|
|
847
|
+
|
|
848
|
+
key = moduledirs[i];
|
|
849
|
+
|
|
850
|
+
try {
|
|
851
|
+
// Let require find the specific file to get
|
|
852
|
+
module_path = require.resolve(libpath.resolve(nmPath, key, 'node_modules', moduleName));
|
|
853
|
+
|
|
854
|
+
// If no errors have popped up now, we can break the for loop
|
|
855
|
+
break;
|
|
856
|
+
|
|
857
|
+
} catch(e) {
|
|
858
|
+
// Do nothing
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (!module_path && recurse < 3) {
|
|
863
|
+
for (i = 0; i < moduledirs.length; i++) {
|
|
864
|
+
|
|
865
|
+
module_path = this.searchModule(libpath.resolve(nmPath, moduledirs[i]), moduleName, recurse+1);
|
|
866
|
+
|
|
867
|
+
if (module_path) {
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
return module_path;
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Find a module in our customized file structure
|
|
878
|
+
*
|
|
879
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
880
|
+
* @since 0.0.1
|
|
881
|
+
* @version 1.1.0
|
|
882
|
+
*
|
|
883
|
+
* @param {String} moduleName
|
|
884
|
+
* @param {Object} options
|
|
885
|
+
*
|
|
886
|
+
* @return {Object}
|
|
887
|
+
*/
|
|
888
|
+
Alchemy.setMethod(function findModule(moduleName, options) {
|
|
889
|
+
|
|
890
|
+
var package_json,
|
|
891
|
+
module_path,
|
|
892
|
+
internal,
|
|
893
|
+
module,
|
|
894
|
+
result,
|
|
895
|
+
time,
|
|
896
|
+
key,
|
|
897
|
+
i;
|
|
898
|
+
|
|
899
|
+
if (!options) {
|
|
900
|
+
options = {};
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
if (options.require == null) {
|
|
904
|
+
options.require = true;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// If we've required this once before, return it
|
|
908
|
+
if (result = usePaths[moduleName]) {
|
|
909
|
+
if (result.err) {
|
|
910
|
+
throw result.err;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// Only return the cached module if it was required then,
|
|
914
|
+
// or if require is now false
|
|
915
|
+
if (result.module || !options.require) {
|
|
916
|
+
return result;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
result = {
|
|
921
|
+
err : null,
|
|
922
|
+
module : null,
|
|
923
|
+
module_dir : null,
|
|
924
|
+
module_path : null,
|
|
925
|
+
package : null,
|
|
926
|
+
internal : null,
|
|
927
|
+
search_time : null,
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
time = Date.now();
|
|
931
|
+
|
|
932
|
+
// Simply try to resolve the module by name
|
|
933
|
+
try {
|
|
934
|
+
module_path = require.resolve(moduleName);
|
|
935
|
+
} catch (err) {
|
|
936
|
+
result.err = err;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// If that path wasn't found, look through the root node_modules
|
|
940
|
+
if (result.err) {
|
|
941
|
+
try {
|
|
942
|
+
module_path = this.searchModule(PATH_ROOT, moduleName);
|
|
943
|
+
} catch (err) {
|
|
944
|
+
console.log(err);
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// If the module_path was found, actually require the module
|
|
950
|
+
if (module_path) {
|
|
951
|
+
|
|
952
|
+
// Modules are required by default
|
|
953
|
+
if (options.require) {
|
|
954
|
+
module = require(module_path);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Get the package.json file
|
|
958
|
+
if (~module_path.indexOf(libpath.sep)) {
|
|
959
|
+
internal = false;
|
|
960
|
+
|
|
961
|
+
let module_dir = libpath.dirname(module_path);
|
|
962
|
+
result.module_dir = module_dir;
|
|
963
|
+
|
|
964
|
+
try {
|
|
965
|
+
package_json = require(libpath.resolve(module_dir, 'package.json'));
|
|
966
|
+
} catch (err) {
|
|
967
|
+
package_json = false;
|
|
968
|
+
}
|
|
969
|
+
} else {
|
|
970
|
+
internal = true;
|
|
971
|
+
package_json = {
|
|
972
|
+
version: process.versions.node
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
if (!options.require || module) {
|
|
978
|
+
result.err = null;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
if (module) {
|
|
982
|
+
result.module = module;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
result.module_path = module_path;
|
|
986
|
+
result.package = package_json;
|
|
987
|
+
result.internal = internal;
|
|
988
|
+
|
|
989
|
+
// Save the result
|
|
990
|
+
usePaths[moduleName] = result;
|
|
991
|
+
|
|
992
|
+
// If there was an error, throw it now
|
|
993
|
+
if (result.err) {
|
|
994
|
+
throw result.err;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
result.search_time = Date.now() - time;
|
|
998
|
+
|
|
999
|
+
// Else return the result
|
|
1000
|
+
return result;
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Create a shared object
|
|
1005
|
+
*
|
|
1006
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1007
|
+
* @since 0.0.1
|
|
1008
|
+
* @version 0.4.0
|
|
1009
|
+
*
|
|
1010
|
+
* @param {String} name The name of the object to get
|
|
1011
|
+
* @param {String} type The type to create (array or object)
|
|
1012
|
+
*
|
|
1013
|
+
* @return {Object|Array}
|
|
1014
|
+
*/
|
|
1015
|
+
Alchemy.setMethod(function shared(name, type, value) {
|
|
1016
|
+
|
|
1017
|
+
if (typeof type !== 'string') {
|
|
1018
|
+
value = type;
|
|
1019
|
+
type = 'object';
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Create it if it doesn't exist
|
|
1023
|
+
if (!shared_objects[name]) {
|
|
1024
|
+
if (type === 'array' || type === 'Array') {
|
|
1025
|
+
shared_objects[name] = value || [];
|
|
1026
|
+
} else {
|
|
1027
|
+
shared_objects[name] = value || {};
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
return shared_objects[name];
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Get an object id,
|
|
1036
|
+
* return undefined if no valid data was given (instead of throwing an error)
|
|
1037
|
+
*
|
|
1038
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1039
|
+
* @since 0.0.1
|
|
1040
|
+
* @version 0.4.0
|
|
1041
|
+
*
|
|
1042
|
+
* @param {String|ObjectID} obj
|
|
1043
|
+
*
|
|
1044
|
+
* @return {ObjectID|undefined}
|
|
1045
|
+
*/
|
|
1046
|
+
Alchemy.setMethod(function castObjectId(obj) {
|
|
1047
|
+
|
|
1048
|
+
var type = typeof obj;
|
|
1049
|
+
|
|
1050
|
+
if (obj && type === 'object' && obj.constructor && obj.constructor.name === 'ObjectID') {
|
|
1051
|
+
return obj;
|
|
1052
|
+
} else if (type === 'string' && obj.isObjectId()) {
|
|
1053
|
+
return alchemy.ObjectId(obj);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
return undefined;
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* See if the given object is a stream
|
|
1061
|
+
*
|
|
1062
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1063
|
+
* @since 0.2.0
|
|
1064
|
+
* @version 1.0.5
|
|
1065
|
+
*
|
|
1066
|
+
* @return {Boolean}
|
|
1067
|
+
*/
|
|
1068
|
+
Alchemy.setMethod(function isStream(obj) {
|
|
1069
|
+
return obj && (typeof obj._read == 'function' || typeof obj._write == 'function') && typeof obj.on === 'function';
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* Get or create a new cache instance
|
|
1074
|
+
*
|
|
1075
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1076
|
+
* @since 1.0.0
|
|
1077
|
+
* @version 1.0.4
|
|
1078
|
+
*
|
|
1079
|
+
* @param {String} name
|
|
1080
|
+
* @param {Number|Object} options
|
|
1081
|
+
*
|
|
1082
|
+
* @return {Develry.Cache}
|
|
1083
|
+
*/
|
|
1084
|
+
Alchemy.setMethod(function getCache(name, options) {
|
|
1085
|
+
|
|
1086
|
+
var instance,
|
|
1087
|
+
duration,
|
|
1088
|
+
config,
|
|
1089
|
+
type;
|
|
1090
|
+
|
|
1091
|
+
if (this.caches[name]) {
|
|
1092
|
+
return this.caches[name];
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
if (!options) {
|
|
1096
|
+
options = {};
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
type = typeof options;
|
|
1100
|
+
|
|
1101
|
+
if (type == 'number' || type == 'string') {
|
|
1102
|
+
options = {
|
|
1103
|
+
max_age : options,
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
config = Object.assign({
|
|
1108
|
+
max_length : 5000,
|
|
1109
|
+
}, options);
|
|
1110
|
+
|
|
1111
|
+
// @TODO: Fixed in 0.6.1
|
|
1112
|
+
instance = new Blast.Classes.Develry.Cache();
|
|
1113
|
+
Object.assign(instance, config);
|
|
1114
|
+
|
|
1115
|
+
this.caches[name] = instance;
|
|
1116
|
+
|
|
1117
|
+
return instance;
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Get a route
|
|
1122
|
+
*
|
|
1123
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1124
|
+
* @since 1.1.3
|
|
1125
|
+
* @version 1.1.3
|
|
1126
|
+
*
|
|
1127
|
+
* @param {String} href The href or route name
|
|
1128
|
+
* @param {Object} parameters Route parameters
|
|
1129
|
+
*
|
|
1130
|
+
* @return {String}
|
|
1131
|
+
*/
|
|
1132
|
+
Alchemy.setMethod(function routeUrl(href, parameters) {
|
|
1133
|
+
|
|
1134
|
+
let temp = Router.getUrl(href, parameters);
|
|
1135
|
+
|
|
1136
|
+
if (temp && temp.href) {
|
|
1137
|
+
temp = String(temp);
|
|
1138
|
+
|
|
1139
|
+
if (temp) {
|
|
1140
|
+
return temp;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
return href;
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Get paths that should be cached by the client
|
|
1149
|
+
*
|
|
1150
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1151
|
+
* @since 1.0.7
|
|
1152
|
+
* @version 1.0.7
|
|
1153
|
+
*
|
|
1154
|
+
* @return {Pledge}
|
|
1155
|
+
*/
|
|
1156
|
+
Alchemy.decorateMethod(Blast.Decorators.memoize(), function getAppcachePaths() {
|
|
1157
|
+
|
|
1158
|
+
var paths = [];
|
|
1159
|
+
|
|
1160
|
+
return Function.parallel(function getHawkejsTemplates(next) {
|
|
1161
|
+
|
|
1162
|
+
var templates = [],
|
|
1163
|
+
directories = alchemy.hawkejs.directories.getSorted(),
|
|
1164
|
+
tasks = [],
|
|
1165
|
+
i;
|
|
1166
|
+
|
|
1167
|
+
function checkDirectory(dir_path, mount_path, next) {
|
|
1168
|
+
fs.readdir(dir_path, function gotDir(err, files) {
|
|
1169
|
+
|
|
1170
|
+
if (err) {
|
|
1171
|
+
|
|
1172
|
+
if (err.code == 'ENOENT') {
|
|
1173
|
+
return next();
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
return next(err);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
let tasks = [],
|
|
1180
|
+
i;
|
|
1181
|
+
|
|
1182
|
+
for (i = 0; i < files.length; i++) {
|
|
1183
|
+
let file = files[i],
|
|
1184
|
+
full_path = libpath.resolve(dir_path, file),
|
|
1185
|
+
full_mount_path = mount_path + '/' + file;
|
|
1186
|
+
|
|
1187
|
+
tasks.push(function checkPath(next) {
|
|
1188
|
+
fs.stat(full_path, function gotStat(err, stat) {
|
|
1189
|
+
|
|
1190
|
+
if (err) {
|
|
1191
|
+
|
|
1192
|
+
if (err.code == 'ENOENT') {
|
|
1193
|
+
return next();
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
return next(err);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
if (stat.isDirectory()) {
|
|
1200
|
+
return checkDirectory(full_path, full_mount_path, next);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
if (stat.isFile()) {
|
|
1204
|
+
if (file.endsWith('.ejs') || file.endsWith('.hwk')) {
|
|
1205
|
+
|
|
1206
|
+
if (full_mount_path[0] == '/') {
|
|
1207
|
+
full_mount_path = full_mount_path.slice(1);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
templates.push(full_mount_path);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
next();
|
|
1215
|
+
});
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
Function.parallel(tasks, next);
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
for (i = 0; i < directories.length; i++) {
|
|
1224
|
+
let directory = directories[i];
|
|
1225
|
+
|
|
1226
|
+
tasks.push(function readDir(next) {
|
|
1227
|
+
checkDirectory(directory, '', next);
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
return Function.parallel(tasks, function done(err) {
|
|
1232
|
+
|
|
1233
|
+
if (err) {
|
|
1234
|
+
return next(err);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
let path,
|
|
1238
|
+
url,
|
|
1239
|
+
i;
|
|
1240
|
+
|
|
1241
|
+
for (i = 0; i < templates.length; i++) {
|
|
1242
|
+
path = templates[i];
|
|
1243
|
+
url = '/hawkejs/templates?name[0]=' + encodeURIComponent(path.beforeLast('.ejs')) + '&v=' + alchemy.package.version;
|
|
1244
|
+
paths.push(url);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
next();
|
|
1248
|
+
});
|
|
1249
|
+
}, function done(err) {
|
|
1250
|
+
|
|
1251
|
+
if (err) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
return paths;
|
|
1256
|
+
});
|
|
1257
|
+
});
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Get the appcache manifest text
|
|
1261
|
+
*
|
|
1262
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1263
|
+
* @since 1.0.7
|
|
1264
|
+
* @version 1.0.7
|
|
1265
|
+
*
|
|
1266
|
+
* @return {Pledge}
|
|
1267
|
+
*/
|
|
1268
|
+
Alchemy.decorateMethod(Blast.Decorators.memoize(), function getAppcacheManifest() {
|
|
1269
|
+
|
|
1270
|
+
return Function.series(function gotPaths(next) {
|
|
1271
|
+
alchemy.getAppcachePaths().done(next);
|
|
1272
|
+
}, function createText(err, result) {
|
|
1273
|
+
|
|
1274
|
+
if (err) {
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
let manifest = 'CACHE MANIFEST\n\n',
|
|
1279
|
+
entry,
|
|
1280
|
+
url,
|
|
1281
|
+
key,
|
|
1282
|
+
i;
|
|
1283
|
+
|
|
1284
|
+
manifest += 'CACHE:\n';
|
|
1285
|
+
|
|
1286
|
+
// Allways add the client script
|
|
1287
|
+
manifest += '/hawkejs/hawkejs-client.js?v=' + alchemy.package.version + '\n';
|
|
1288
|
+
|
|
1289
|
+
if (ac_entries.cache && ac_entries.cache.length) {
|
|
1290
|
+
for (key in ac_entries.cache) {
|
|
1291
|
+
manifest += ac_entries.cache[key].url + '\n';
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
for (i = 0; i < result[0].length; i++) {
|
|
1296
|
+
url = result[0][i];
|
|
1297
|
+
|
|
1298
|
+
manifest += url + '\n';
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
manifest += '\n';
|
|
1302
|
+
manifest += 'NETWORK:\n*\n\n';
|
|
1303
|
+
|
|
1304
|
+
// This will cause a cache update each time the server is reset
|
|
1305
|
+
manifest += '#' + alchemy.package.version + '-' + alchemy.discovery_id;
|
|
1306
|
+
|
|
1307
|
+
return manifest;
|
|
1308
|
+
});
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* Add an appcache entry
|
|
1313
|
+
*
|
|
1314
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1315
|
+
* @since 1.0.7
|
|
1316
|
+
* @version 1.0.7
|
|
1317
|
+
*
|
|
1318
|
+
* @param {String|Object}
|
|
1319
|
+
*/
|
|
1320
|
+
Alchemy.setMethod(function addAppcacheEntry(entry) {
|
|
1321
|
+
|
|
1322
|
+
if (typeof entry == 'string') {
|
|
1323
|
+
entry = {
|
|
1324
|
+
url : entry
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
if (!entry.type) {
|
|
1329
|
+
entry.type = 'cache';
|
|
1330
|
+
} else {
|
|
1331
|
+
entry.type = entry.type.toLowerCase();
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
if (!ac_entries[entry.type]) {
|
|
1335
|
+
ac_entries[entry.type] = [];
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
ac_entries[entry.type].push(entry);
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Get the body of an IncomingMessage
|
|
1343
|
+
*
|
|
1344
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1345
|
+
* @since 1.1.0
|
|
1346
|
+
* @version 1.1.0
|
|
1347
|
+
*
|
|
1348
|
+
* @param {IncomingMessage} req
|
|
1349
|
+
* @param {OutgoingMessage} res Optional
|
|
1350
|
+
* @param {Function} callback
|
|
1351
|
+
*/
|
|
1352
|
+
Alchemy.setMethod(function parseRequestBody(req, res, callback) {
|
|
1353
|
+
|
|
1354
|
+
const conduit = req.conduit;
|
|
1355
|
+
|
|
1356
|
+
if (typeof res == 'function') {
|
|
1357
|
+
callback = res;
|
|
1358
|
+
res = null;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
if (req.original) {
|
|
1362
|
+
req = req.original;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
if (req.body != null) {
|
|
1366
|
+
return callback(null, req.body);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// Multipart data is handled by "formidable"
|
|
1370
|
+
if (req.headers['content-type'] && req.headers['content-type'].startsWith('multipart/form-data')) {
|
|
1371
|
+
|
|
1372
|
+
let form = new formidable.IncomingForm();
|
|
1373
|
+
|
|
1374
|
+
// md5 hash by default
|
|
1375
|
+
form.hash = 'md5';
|
|
1376
|
+
|
|
1377
|
+
form.parse(req, function parsedMultipart(err, form_fields, form_files) {
|
|
1378
|
+
|
|
1379
|
+
var fields = {},
|
|
1380
|
+
files = {},
|
|
1381
|
+
key;
|
|
1382
|
+
|
|
1383
|
+
if (err && req.conduit && req.conduit.aborted) {
|
|
1384
|
+
return callback(null);
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// Fix the field names
|
|
1388
|
+
for (key in form_fields) {
|
|
1389
|
+
Object.setFormPath(fields, key, form_fields[key]);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// Fix the file names
|
|
1393
|
+
for (key in form_files) {
|
|
1394
|
+
Object.setFormPath(files, key, form_files[key]);
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
if (err) {
|
|
1398
|
+
log.error('Error parsing multipart POST', {err: err});
|
|
1399
|
+
req.body = {};
|
|
1400
|
+
req.files = {};
|
|
1401
|
+
} else {
|
|
1402
|
+
req.body = fields;
|
|
1403
|
+
req.files = files;
|
|
1404
|
+
|
|
1405
|
+
if (conduit) {
|
|
1406
|
+
conduit.setRequestBody(fields);
|
|
1407
|
+
conduit.setRequestFiles(files);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
callback(null, fields);
|
|
1412
|
+
});
|
|
1413
|
+
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
// Regular form-encoded data
|
|
1418
|
+
if (req.headers['content-type'] && req.headers['content-type'].indexOf('form-urlencoded') > -1) {
|
|
1419
|
+
|
|
1420
|
+
urlFormBody(req, res, function parsedBody(err) {
|
|
1421
|
+
|
|
1422
|
+
if (err && req.conduit && req.conduit.aborted) {
|
|
1423
|
+
return callback(null);
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
// You can't send files using a regular post
|
|
1427
|
+
req.files = {};
|
|
1428
|
+
|
|
1429
|
+
if (err) {
|
|
1430
|
+
log.error('Error parsing x-www-form-urlencoded body data', {err: err});
|
|
1431
|
+
req.body = {};
|
|
1432
|
+
} else {
|
|
1433
|
+
req.body = req.body;
|
|
1434
|
+
|
|
1435
|
+
if (conduit) {
|
|
1436
|
+
conduit.setRequestBody(req.body);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
callback(null, req.body);
|
|
1441
|
+
});
|
|
1442
|
+
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// Any other encoded data (like JSON)
|
|
1447
|
+
anyBody(req, function parsedBody(err, body) {
|
|
1448
|
+
|
|
1449
|
+
if (err && req.conduit && req.conduit.aborted) {
|
|
1450
|
+
return callback(null);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
// You can't send files using a regular post
|
|
1454
|
+
req.files = {};
|
|
1455
|
+
|
|
1456
|
+
if (err) {
|
|
1457
|
+
log.error('Error parsing body data', {err: err});
|
|
1458
|
+
req.body = {};
|
|
1459
|
+
} else {
|
|
1460
|
+
req.body = body;
|
|
1461
|
+
|
|
1462
|
+
if (conduit) {
|
|
1463
|
+
conduit.setRequestBody(body);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
callback(null, req.body);
|
|
1468
|
+
});
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
/**
|
|
1472
|
+
* Export all data
|
|
1473
|
+
*
|
|
1474
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1475
|
+
* @since 1.0.5
|
|
1476
|
+
* @version 1.0.5
|
|
1477
|
+
*
|
|
1478
|
+
* @return {Stream}
|
|
1479
|
+
*/
|
|
1480
|
+
Alchemy.setMethod(function createExportStream(options) {
|
|
1481
|
+
|
|
1482
|
+
var stream = new require('stream').PassThrough();
|
|
1483
|
+
|
|
1484
|
+
this.exportToStream(stream, options);
|
|
1485
|
+
|
|
1486
|
+
return stream;
|
|
1487
|
+
});
|
|
1488
|
+
|
|
1489
|
+
/**
|
|
1490
|
+
* Export all data to stream
|
|
1491
|
+
*
|
|
1492
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1493
|
+
* @since 1.0.5
|
|
1494
|
+
* @version 1.0.5
|
|
1495
|
+
*
|
|
1496
|
+
* @param {Stream} output
|
|
1497
|
+
* @param {Object} options
|
|
1498
|
+
*
|
|
1499
|
+
* @return {Pledge}
|
|
1500
|
+
*/
|
|
1501
|
+
Alchemy.setMethod(function exportToStream(output, options) {
|
|
1502
|
+
|
|
1503
|
+
if (!alchemy.isStream(output)) {
|
|
1504
|
+
if (!options) {
|
|
1505
|
+
options = output;
|
|
1506
|
+
output = null;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
output = options.output;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
if (!output) {
|
|
1513
|
+
return Pledge.reject(new Error('No target output stream has been given'));
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
if (!options) {
|
|
1517
|
+
options = {};
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
let tasks = [],
|
|
1521
|
+
i;
|
|
1522
|
+
|
|
1523
|
+
for (i = 0; i < Model.children.length; i++) {
|
|
1524
|
+
let model = Model.children[i];
|
|
1525
|
+
|
|
1526
|
+
tasks.push(async function exportModel(next) {
|
|
1527
|
+
await (new model).exportToStream(output);
|
|
1528
|
+
next();
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
return Function.series(tasks, function done(err) {
|
|
1533
|
+
|
|
1534
|
+
if (err) {
|
|
1535
|
+
return output.emit('error', err);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
output.end();
|
|
1539
|
+
});
|
|
1540
|
+
});
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Import from a stream
|
|
1544
|
+
*
|
|
1545
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1546
|
+
* @since 1.0.5
|
|
1547
|
+
* @version 1.0.5
|
|
1548
|
+
*
|
|
1549
|
+
* @param {Stream} input
|
|
1550
|
+
* @param {Object} options
|
|
1551
|
+
*
|
|
1552
|
+
* @return {Pledge}
|
|
1553
|
+
*/
|
|
1554
|
+
Alchemy.setMethod(function importFromStream(input, options) {
|
|
1555
|
+
|
|
1556
|
+
if (!alchemy.isStream(input)) {
|
|
1557
|
+
if (!options) {
|
|
1558
|
+
options = input;
|
|
1559
|
+
input = null;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
input = options.input;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
if (!input) {
|
|
1566
|
+
return Pledge.reject(new Error('No source input stream has been given'));
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
if (!options) {
|
|
1570
|
+
options = {};
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
let that = this,
|
|
1574
|
+
current_type = null,
|
|
1575
|
+
extra_stream,
|
|
1576
|
+
pledge = new Pledge(),
|
|
1577
|
+
stopped,
|
|
1578
|
+
paused,
|
|
1579
|
+
buffer,
|
|
1580
|
+
model,
|
|
1581
|
+
value,
|
|
1582
|
+
seen = 0,
|
|
1583
|
+
left,
|
|
1584
|
+
size,
|
|
1585
|
+
doc;
|
|
1586
|
+
|
|
1587
|
+
input.on('data', function onData(data) {
|
|
1588
|
+
|
|
1589
|
+
if (stopped) {
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
if (buffer) {
|
|
1594
|
+
buffer = Buffer.concat([buffer, data]);
|
|
1595
|
+
} else {
|
|
1596
|
+
buffer = data;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
handleBuffer();
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1602
|
+
function handleBuffer() {
|
|
1603
|
+
|
|
1604
|
+
if (paused) {
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
if (!current_type && buffer.length < 2) {
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
if (!current_type) {
|
|
1613
|
+
current_type = buffer.readUInt8(0);
|
|
1614
|
+
|
|
1615
|
+
if (current_type == 0x01) {
|
|
1616
|
+
size = buffer.readUInt8(1);
|
|
1617
|
+
buffer = buffer.slice(2);
|
|
1618
|
+
} else if (current_type == 0x02 && buffer.length >= 5) {
|
|
1619
|
+
size = buffer.readUInt32BE(1);
|
|
1620
|
+
buffer = buffer.slice(5);
|
|
1621
|
+
} else if (current_type == 0xFF) {
|
|
1622
|
+
size = buffer.readUInt32BE(1);
|
|
1623
|
+
buffer = buffer.slice(5);
|
|
1624
|
+
seen = 0;
|
|
1625
|
+
|
|
1626
|
+
if (!doc) {
|
|
1627
|
+
stopped = true;
|
|
1628
|
+
pledge.reject(new Error('Found extra import data, but no active document'));
|
|
1629
|
+
} else {
|
|
1630
|
+
extra_stream = new require('stream').PassThrough();
|
|
1631
|
+
doc.extraImportFromStream(extra_stream);
|
|
1632
|
+
}
|
|
1633
|
+
} else {
|
|
1634
|
+
// Not enough data? Wait
|
|
1635
|
+
current_type = null;
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
handleRest();
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
function handleRest() {
|
|
1644
|
+
|
|
1645
|
+
if (current_type == 0xFF) {
|
|
1646
|
+
left = size - seen;
|
|
1647
|
+
value = buffer.slice(0, left);
|
|
1648
|
+
|
|
1649
|
+
seen += value.length;
|
|
1650
|
+
|
|
1651
|
+
if (value.length == buffer.length) {
|
|
1652
|
+
buffer = null;
|
|
1653
|
+
} else if (value.length < buffer.length) {
|
|
1654
|
+
buffer = buffer.slice(left);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
extra_stream.write(value);
|
|
1658
|
+
|
|
1659
|
+
if (value.length == left) {
|
|
1660
|
+
extra_stream.end();
|
|
1661
|
+
current_type = null;
|
|
1662
|
+
|
|
1663
|
+
if (buffer) {
|
|
1664
|
+
handleBuffer();
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
if (buffer.length >= size) {
|
|
1672
|
+
value = buffer.slice(0, size);
|
|
1673
|
+
buffer = buffer.slice(size);
|
|
1674
|
+
} else {
|
|
1675
|
+
// Wait for next call
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
if (current_type == 0x01) {
|
|
1680
|
+
value = value.toString();
|
|
1681
|
+
|
|
1682
|
+
if (!model || model.model_name != value) {
|
|
1683
|
+
model = Model.get(value);
|
|
1684
|
+
doc = null;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
if (!model) {
|
|
1688
|
+
stopped = true;
|
|
1689
|
+
return pledge.reject(new Error('Could not find Model "' + value + '"'));
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
current_type = null;
|
|
1693
|
+
size = 0;
|
|
1694
|
+
} else if (current_type == 0x02) {
|
|
1695
|
+
doc = model.createDocument();
|
|
1696
|
+
input.pause();
|
|
1697
|
+
paused = true;
|
|
1698
|
+
|
|
1699
|
+
doc.importFromBuffer(value).done(function done(err, result) {
|
|
1700
|
+
|
|
1701
|
+
if (err) {
|
|
1702
|
+
stopped = true;
|
|
1703
|
+
return pledge.reject(err);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
current_type = null;
|
|
1707
|
+
paused = false;
|
|
1708
|
+
input.resume();
|
|
1709
|
+
|
|
1710
|
+
handleBuffer();
|
|
1711
|
+
});
|
|
1712
|
+
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
if (buffer && buffer.length) {
|
|
1717
|
+
handleBuffer();
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
return pledge;
|
|
1722
|
+
});
|
|
1723
|
+
|
|
1724
|
+
/**
|
|
1725
|
+
* Create a new schema
|
|
1726
|
+
*
|
|
1727
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1728
|
+
* @since 1.2.1
|
|
1729
|
+
* @version 1.2.1
|
|
1730
|
+
*
|
|
1731
|
+
* @param {*} parent
|
|
1732
|
+
*/
|
|
1733
|
+
Alchemy.setMethod(function createSchema(parent) {
|
|
1734
|
+
let schema = new Classes.Alchemy.Schema(parent);
|
|
1735
|
+
return schema;
|
|
1736
|
+
});
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* The alchemy global, where everything will be stored
|
|
1740
|
+
*
|
|
1741
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1742
|
+
* @since 0.0.1
|
|
1743
|
+
* @version 0.4.0
|
|
1744
|
+
*
|
|
1745
|
+
* @type {Alchemy}
|
|
1746
|
+
*/
|
|
1747
|
+
DEFINE('alchemy', new Alchemy());
|
|
1748
|
+
|
|
1749
|
+
/**
|
|
1750
|
+
* Define the log function
|
|
1751
|
+
*
|
|
1752
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1753
|
+
* @since 0.0.1
|
|
1754
|
+
* @version 0.4.0
|
|
1755
|
+
*
|
|
1756
|
+
* @type {Function}
|
|
1757
|
+
*/
|
|
1758
|
+
DEFINE('log', alchemy.log);
|
|
1759
|
+
|
|
1760
|
+
for (let key in alchemy.Janeway.LEVELS) {
|
|
1761
|
+
let name = key.toLowerCase();
|
|
1762
|
+
let val = alchemy.Janeway.LEVELS[key];
|
|
1763
|
+
|
|
1764
|
+
log[name] = function(...args) {
|
|
1765
|
+
return alchemy.printLog(val, args, {level: 2});
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
log.warn = log.warning;
|
|
1770
|
+
|
|
1771
|
+
/**
|
|
1772
|
+
* Define the todo log function
|
|
1773
|
+
*
|
|
1774
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1775
|
+
* @since 0.2.0
|
|
1776
|
+
* @version 0.4.0
|
|
1777
|
+
*
|
|
1778
|
+
* @type {Function}
|
|
1779
|
+
*/
|
|
1780
|
+
log.todo = function todo(...args) {
|
|
1781
|
+
|
|
1782
|
+
var options = {
|
|
1783
|
+
gutter: alchemy.Janeway.esc(91) + '\u2620 Todo:' + alchemy.Janeway.esc(39),
|
|
1784
|
+
level: 2
|
|
1785
|
+
};
|
|
1786
|
+
|
|
1787
|
+
return alchemy.printLog(alchemy.TODO, args, options);
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1790
|
+
const anyBody = alchemy.use('body/any'),
|
|
1791
|
+
formBody = alchemy.use('body/form'),
|
|
1792
|
+
formidable = alchemy.use('formidable'),
|
|
1793
|
+
bodyParser = alchemy.use('body-parser'),
|
|
1780
1794
|
urlFormBody = bodyParser.urlencoded({extended: true});
|