1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | process.env.BLUEBIRD_W_FORGOTTEN_RETURN = '0';
|
9 |
|
10 | const http = require('http'),
|
11 | _ = require('lodash'),
|
12 | path = require('path'),
|
13 | staticConfig = require('./staticConfig'),
|
14 | Database = require('./Database'),
|
15 | Hooks = require('./Hooks'),
|
16 | PluginManager = require('./PluginManager'),
|
17 | Router = require('./Router'),
|
18 | Sanitizer = require('./Sanitizer'),
|
19 | EventEmiter = require('events'),
|
20 | { readFileSync, writeFileSync, writeFile } = require('fs');
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | function We (options) {
|
28 | if (!options) options = {};
|
29 |
|
30 | const we = this;
|
31 |
|
32 | this.packageJSON = require('../package.json');
|
33 |
|
34 | this.config = options;
|
35 |
|
36 | this.childProcesses = [];
|
37 |
|
38 | this.plugins = {};
|
39 | this.pluginPaths = [];
|
40 | this.pluginNames = [];
|
41 |
|
42 | this.controllers = {};
|
43 |
|
44 | this.projectPath = options.projectPath || process.cwd();
|
45 |
|
46 | this.projectPackageJSON = require(path.resolve(this.projectPath, 'package.json'));
|
47 |
|
48 | this.projectConfigFolder = options.projectConfigFolder || path.join(this.projectPath, 'config');
|
49 |
|
50 |
|
51 | this.config = staticConfig(this.projectPath, this);
|
52 |
|
53 | we.env = options.env || require('./getEnv.js')();
|
54 |
|
55 | we.log = require('./log')(we);
|
56 |
|
57 | we.hooks = new Hooks();
|
58 |
|
59 | we.events = new EventEmiter();
|
60 |
|
61 | we.events.setMaxListeners(70);
|
62 |
|
63 | we.sanitizer = new Sanitizer(this);
|
64 |
|
65 | we.router = new Router(this);
|
66 |
|
67 | we.class = {
|
68 | Controller: require('./class/Controller.js'),
|
69 | Theme: require('./class/Theme.js')(we),
|
70 | Plugin: require('./class/Plugin.js')(we)
|
71 | };
|
72 |
|
73 | we.db = new Database(this);
|
74 |
|
75 | we.db.defaultConnection = we.db.connect(we.env);
|
76 |
|
77 | we.db.sequelize = we.db.defaultConnection;
|
78 |
|
79 | we.pluginManager = new PluginManager(this);
|
80 |
|
81 | switch (we.config.bootstrapMode) {
|
82 | case 'install':
|
83 | case 'installation':
|
84 | case 'update':
|
85 | we.hooks.on('bootstrap', [
|
86 | we.bootstrapFunctions.checkDBConnection,
|
87 | we.bootstrapFunctions.loadCoreFeatures,
|
88 | we.bootstrapFunctions.loadPluginFeatures,
|
89 | we.bootstrapFunctions.initI18n,
|
90 | we.bootstrapFunctions.loadTemplateCache,
|
91 | we.bootstrapFunctions.instantiateModels,
|
92 | we.bootstrapFunctions.syncModels,
|
93 | we.bootstrapFunctions.loadControllers,
|
94 | we.bootstrapFunctions.installAndRegisterPlugins
|
95 | ]);
|
96 | break;
|
97 | case 'complete':
|
98 | case 'full':
|
99 | case 'test':
|
100 |
|
101 | we.hooks.on('bootstrap', [
|
102 | we.bootstrapFunctions.checkDBConnection,
|
103 | we.bootstrapFunctions.loadCoreFeatures,
|
104 | we.bootstrapFunctions.loadPluginFeatures,
|
105 | we.bootstrapFunctions.initI18n,
|
106 | we.bootstrapFunctions.loadTemplateCache,
|
107 | we.bootstrapFunctions.instantiateModels,
|
108 | we.bootstrapFunctions.syncModels,
|
109 | we.bootstrapFunctions.loadControllers,
|
110 | we.bootstrapFunctions.installAndRegisterPlugins,
|
111 | we.bootstrapFunctions.setExpressApp,
|
112 | we.bootstrapFunctions.passport,
|
113 | we.bootstrapFunctions.createDefaultFolders,
|
114 | we.bootstrapFunctions.registerAllViewTemplates,
|
115 | we.bootstrapFunctions.mergeRoutes,
|
116 | we.bootstrapFunctions.bindResources,
|
117 | we.bootstrapFunctions.bindRoutes
|
118 | ]);
|
119 | break;
|
120 | default:
|
121 |
|
122 | we.hooks.on('bootstrap', [
|
123 | we.bootstrapFunctions.checkDBConnection,
|
124 | we.bootstrapFunctions.loadCoreFeatures,
|
125 | we.bootstrapFunctions.loadPluginFeatures,
|
126 | we.bootstrapFunctions.initI18n,
|
127 | we.bootstrapFunctions.loadTemplateCache,
|
128 | we.bootstrapFunctions.instantiateModels,
|
129 | we.bootstrapFunctions.syncModels,
|
130 | we.bootstrapFunctions.loadControllers,
|
131 | we.bootstrapFunctions.installAndRegisterPlugins,
|
132 | we.bootstrapFunctions.setExpressApp,
|
133 | we.bootstrapFunctions.passport,
|
134 | we.bootstrapFunctions.createDefaultFolders,
|
135 | we.bootstrapFunctions.registerAllViewTemplates,
|
136 | we.bootstrapFunctions.mergeRoutes,
|
137 | we.bootstrapFunctions.bindResources,
|
138 | we.bootstrapFunctions.bindRoutes
|
139 | ]);
|
140 | }
|
141 | }
|
142 |
|
143 | We.prototype = {
|
144 | |
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 | setConfig(variable, value, cb) {
|
152 | if (!cb) cb = function(){};
|
153 |
|
154 | let cJSON,
|
155 | cFGpath = path.join(this.projectPath, '/config/configuration.json');
|
156 |
|
157 | try {
|
158 | cJSON = JSON.parse(readFileSync(cFGpath));
|
159 | } catch(e) {
|
160 | if (e.code == 'ENOENT') {
|
161 | writeFileSync(cFGpath, '{}');
|
162 | cJSON = {};
|
163 | } else {
|
164 | return cb(e);
|
165 | }
|
166 | }
|
167 |
|
168 | if (value == 'true') value = true;
|
169 | if (value == 'false') value = false;
|
170 |
|
171 | _.set(cJSON, variable, value);
|
172 |
|
173 | writeFile(cFGpath, JSON.stringify(cJSON, null, 2), cb);
|
174 | },
|
175 |
|
176 | |
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | unSetConfig(variable, cb) {
|
184 | let cJSON,
|
185 | cFGpath = path.join(this.projectPath, '/config/configuration.json');
|
186 |
|
187 | try {
|
188 | cJSON = JSON.parse(readFileSync(cFGpath));
|
189 | } catch(e) {
|
190 | if (e.code == 'ENOENT') {
|
191 | writeFileSync(cFGpath, '{}');
|
192 | cJSON = {};
|
193 | } else {
|
194 | return cb(e);
|
195 | }
|
196 | }
|
197 |
|
198 | _.unset(cJSON, variable);
|
199 |
|
200 | writeFile(cFGpath, JSON.stringify(cJSON, null, 2), cb);
|
201 | },
|
202 |
|
203 | bootstrapFunctions: require('./bootstrapFunctions'),
|
204 |
|
205 | bootstrapStarted: false,
|
206 |
|
207 | needsRestart: false,
|
208 |
|
209 | utils: require('./utils'),
|
210 |
|
211 | responses: require('./responses'),
|
212 |
|
213 | weCorePluginfile: path.resolve(__dirname, '../') + '/plugin.js',
|
214 |
|
215 | inspect() {
|
216 | return '\nWe.js ;)\n';
|
217 | },
|
218 | toString() {
|
219 | return this.inspect();
|
220 | },
|
221 |
|
222 | getAppBootstrapConfig: require('./staticConfig/getAppBootstrapConfig.js'),
|
223 |
|
224 | |
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 | bootstrap(configOnRun, cb) {
|
231 | const we = this;
|
232 |
|
233 | if (we.bootstrapStarted) throw new Error('We.js already did bootstrap');
|
234 |
|
235 | we.bootstrapStarted = true;
|
236 |
|
237 | if (!cb) {
|
238 | cb = configOnRun;
|
239 | configOnRun = null;
|
240 | }
|
241 |
|
242 | if (configOnRun) _.merge(we.config, configOnRun);
|
243 |
|
244 |
|
245 | we.hooks.trigger('bootstrap', we, function bootstrapDone (err) {
|
246 | if (err) {
|
247 | console.log('Error on bootstrap: ');
|
248 | throw err;
|
249 | }
|
250 |
|
251 | we.events.emit('we:bootstrap:done', we);
|
252 |
|
253 | we.log.debug('We.js bootstrap done');
|
254 |
|
255 | we.setPM2grShutdownFN(we);
|
256 |
|
257 | return cb(null, we);
|
258 | });
|
259 | },
|
260 |
|
261 | |
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 | startServer(cb) {
|
268 | if (!cb) cb = function(){};
|
269 |
|
270 | let we = this;
|
271 |
|
272 | we.hooks.trigger('we:server:before:start' ,we ,function afterRunBeforeServerStart (err) {
|
273 | if (err) return cb(err);
|
274 | |
275 |
|
276 |
|
277 | let port = normalizePort(we.config.port);
|
278 | we.express.set('port', port);
|
279 |
|
280 | |
281 |
|
282 |
|
283 | const server = http.createServer(function onCreateServer (req, res){
|
284 | req.we = we;
|
285 |
|
286 |
|
287 |
|
288 | if (req.headers && req.headers['we-widget-action'] && req.method == 'POST') {
|
289 | req.isWidgetAction = true;
|
290 | req.originalMethod = req.method;
|
291 | req.method = 'GET';
|
292 | }
|
293 |
|
294 |
|
295 | if (!we.router.isPublicFolder(req.url)) {
|
296 | req.extension = we.router.splitExtensionFromURL(req.url);
|
297 |
|
298 | if (req.extension) {
|
299 | let format = we.utils.mime.getType(req.extension);
|
300 |
|
301 | if (req.we.config.responseTypes.includes(format)) {
|
302 |
|
303 | req.headers.accept = format;
|
304 |
|
305 | req.url = req.url.replace('.'+req.extension, '');
|
306 | }
|
307 | }
|
308 | }
|
309 |
|
310 | if (we.plugins['we-plugin-url-alias'] && we.config.enableUrlAlias) {
|
311 | we.router.alias.httpHandler.bind(this)(req, res);
|
312 | } else {
|
313 | we.express.bind(this)(req, res);
|
314 | }
|
315 | });
|
316 |
|
317 | we.events.emit('we:server:after:create', { we: we, server: server });
|
318 |
|
319 | |
320 |
|
321 |
|
322 |
|
323 |
|
324 | we.express.use(function routeNotFound (req, res) {
|
325 | we.log.debug('Route not found:', {
|
326 | method: req.method,
|
327 | path: req.path
|
328 | });
|
329 |
|
330 |
|
331 | return res.notFound();
|
332 | });
|
333 |
|
334 | server.listen(port);
|
335 | server.on('error', onError);
|
336 | server.on('listening', onListening);
|
337 | |
338 |
|
339 |
|
340 | function normalizePort (val) {
|
341 | let port = parseInt(val, 10);
|
342 |
|
343 | if (isNaN(port)) {
|
344 |
|
345 | return val;
|
346 | }
|
347 |
|
348 | if (port >= 0) {
|
349 |
|
350 | return port;
|
351 | }
|
352 |
|
353 | return false;
|
354 | }
|
355 |
|
356 | |
357 |
|
358 |
|
359 | function onError (error) {
|
360 | if (error.syscall !== 'listen') {
|
361 | throw error;
|
362 | }
|
363 |
|
364 | let bind = typeof port === 'string'
|
365 | ? 'Pipe ' + port
|
366 | : 'Port ' + port;
|
367 |
|
368 |
|
369 | switch (error.code) {
|
370 | case 'EACCES':
|
371 | console.error(bind + ' requires elevated privileges');
|
372 | process.exit(1);
|
373 | break;
|
374 | case 'EADDRINUSE':
|
375 | console.error(bind + ' is already in use');
|
376 | process.exit(1);
|
377 | break;
|
378 | default:
|
379 | throw error;
|
380 | }
|
381 | }
|
382 | |
383 |
|
384 |
|
385 | function onListening () {
|
386 | let addr = server.address(),
|
387 | bind = typeof addr === 'string'
|
388 | ? 'pipe ' + addr
|
389 | : 'port ' + addr.port;
|
390 | we.log.info('Run in '+we.env+' enviroment and listening on ' + bind);
|
391 |
|
392 | if (process.send) {
|
393 | process.send('ready');
|
394 | }
|
395 | }
|
396 |
|
397 | we.http = server;
|
398 |
|
399 |
|
400 |
|
401 | we.express.use(function onExpressError (err, req, res, next) {
|
402 |
|
403 | if (err instanceof URIError) {
|
404 | we.log.warn('onExpressError:Error on:', req.path, err);
|
405 |
|
406 | res.addMessage('warning', {
|
407 | text: 'router.invalid.url'
|
408 | });
|
409 |
|
410 |
|
411 | return res.goTo('/');
|
412 | }
|
413 |
|
414 | we.log.error('onExpressError:Error on:', req.path, err);
|
415 |
|
416 | res.serverError(err);
|
417 | });
|
418 |
|
419 | we.hooks.trigger('we:server:after:start',we, function afterHookAfterStart (err) {
|
420 | cb(err, we);
|
421 | });
|
422 | });
|
423 | },
|
424 |
|
425 | |
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 | go(cfgs, cb) {
|
432 | if (!cb) {
|
433 | cb = cfgs;
|
434 | cfgs = {};
|
435 | }
|
436 |
|
437 | this.bootstrap(cfgs, function afterBootstrapOnWeGo (err, we) {
|
438 | if (err) throw err;
|
439 | we.startServer(cb);
|
440 | });
|
441 | },
|
442 |
|
443 | |
444 |
|
445 |
|
446 |
|
447 |
|
448 | exit(cb) {
|
449 | this.isExiting = true;
|
450 |
|
451 | if (this.db.defaultConnection) {
|
452 | this.db.defaultConnection.close();
|
453 | }
|
454 |
|
455 | this.log.closeAllLoggersAndDisconnect(this, cb);
|
456 | },
|
457 |
|
458 | |
459 |
|
460 |
|
461 | freeResponseMemory(req, res) {
|
462 | delete res.locals.req;
|
463 | delete res.locals.regions;
|
464 | delete res.locals.Model;
|
465 | delete res.locals.body;
|
466 | delete res.locals.layoutHtml;
|
467 | },
|
468 |
|
469 | |
470 |
|
471 |
|
472 |
|
473 |
|
474 | runCron(cb) {
|
475 | this.cron = require('./cron');
|
476 | this.cron.loadAndRunAllTasks(this, cb);
|
477 | },
|
478 |
|
479 | |
480 |
|
481 |
|
482 | setPM2grShutdownFN(we) {
|
483 |
|
484 | process.on('message', (msg)=> {
|
485 | if (msg === 'shutdown') {
|
486 |
|
487 | we.exit( (err)=> { process.exit(err ? 1 : 0); });
|
488 | }
|
489 | });
|
490 |
|
491 | process.on('SIGINT', ()=> {
|
492 | we.exit( (err)=> { process.exit(err ? 1 : 0); });
|
493 | });
|
494 | }
|
495 | };
|
496 |
|
497 | module.exports = We; |
\ | No newline at end of file |