UNPKG

126 kBJavaScriptView Raw
1/*!
2 * node-mu
3 * node.js minimalistic microservices framework on top of Express.js
4 *
5 * Copyright(c) 2018 IT Resources s.r.l.
6 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in all
16 * copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 * See node-mu license text even in LICENSE file.
27 *
28 * lib/index.js
29 */
30
31'use strict';
32
33// yeah, I know... it's a global! ... go on :)!
34Promise = require('bluebird');
35
36const inversify = require('inversify');
37require('reflect-metadata');
38const ioc = require('./node-mu/ioc');
39const Application = require('./node-mu/application');
40
41const {LoggerWrapper} = require('./node-mu/logger');
42const logger = new LoggerWrapper('build');
43
44
45/**
46 * Register the application Service class into the inversify IoC Container and returns the managed instance.
47 *
48 * @param applicationClass - the actual service class
49 * @returns {*}
50 */
51const build = (applicationClass) => {
52 logger.info('starting service', true);
53
54 const application = ioc.container.get(applicationClass.prototype.ioc.id);
55 logger.info(`service Application instance [${application.id}] builded`, true);
56 return application;
57};
58
59/* main export */
60exports = module.exports = (applicationClass) => {
61 return build(applicationClass);
62};
63
64
65/**
66 * Main lib exports
67 * @module node-mu
68 * @public
69 */
70exports.ioc = ioc;
71exports.Application = Application;
72exports.Providers = require('./node-mu/providers');
73exports.Controllers = require('./node-mu/components').Controllers;
74exports.Route = require('./node-mu/components').Route;
75exports.Component = require('./node-mu/components').Component;
76exports.Repository = require('./node-mu/components').Repository;
77exports.Service = require('./node-mu/components').Service;
78exports.LoggerWrapper = LoggerWrapper;
79exports.Utils = require('./node-mu/utils');/*!
80 * node-mu
81 * node.js minimalistic microservices framework on top of Express.js
82 *
83 * Copyright(c) 2018 IT Resources s.r.l.
84 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
85 *
86 * Permission is hereby granted, free of charge, to any person obtaining a copy
87 * of this software and associated documentation files (the "Software"), to deal
88 * in the Software without restriction, including without limitation the rights
89 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
90 * copies of the Software, and to permit persons to whom the Software is
91 * furnished to do so, subject to the following conditions:
92 *
93 * The above copyright notice and this permission notice shall be included in all
94 * copies or substantial portions of the Software.
95 *
96 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
97 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
98 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
99 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
100 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
101 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
102 * SOFTWARE.
103 *
104 * See node-mu license text even in LICENSE file.
105 *
106 * lib/node-mu/application.js
107 */
108
109'use strict';
110
111require('reflect-metadata');
112
113const {container, Injectable, Inject} = require('./ioc');
114const config = require('config');
115const {Component} = require('./components');
116const RoutesRegister = require('./providers/api/routes-register');
117const ProvidersRegister = require('./providers/health/providers-register');
118
119/**
120 * The main Service class from which derive our service.
121 *
122 * @public
123 */
124class Application extends Component {
125 constructor() {
126 super();
127 }
128
129 /**
130 * Runs the service.
131 * @returns {Promise<void>}
132 */
133 async run() {
134 try {
135 await this.$bootstrap();
136 await this._start();
137 } catch (err) {
138 throw err;
139 }
140 }
141
142 /**
143 * To be implemented in the derived service class to initialize anything useful.
144 * Normally used to register injectable components.
145 * @returns {Promise<void>}
146 */
147 async $bootstrap() {
148 console.log('$bootstrap() not yet implemented');
149 }
150
151 /**
152 * Try and start the injected provider (if it has been injected ... != null).
153 *
154 * @param provider
155 * @param after
156 * @returns {Promise<void>}
157 */
158 async _startProvider(provider) {
159 if (provider) {
160 try {
161 this._logger.debug(`[*] starting injected ${provider.constructor.name} provider`);
162 await provider.$start();
163 } catch (err) {
164 throw err;
165 }
166 }
167 }
168
169 // TODO: make a better providers loading procedure (configuring, rules, etc...)
170 async _startInjectedProviders() {
171 return new Promise(async (resolve, reject) => {
172 try {
173
174 // TOTALLY ASYNC PROVIDERS INITIALIZATION
175 /*
176 const startProviderPromises = Object.keys(this)
177 .filter(k => {
178 let obj = Object(this)[k];
179 if (/(provider)/i.test(obj.ctype) || /router/i.test(obj.ctype)) {
180 return k;
181 }
182 })
183 .map(async (k) => {
184 return new Promise(async (resolve, reject) => {
185 try {
186 let obj = Object(this)[k];
187 await this._startInjectedProvider(obj);
188
189 // setup routes for each Api provider
190 if (/router/i.test(obj.ctype)) {
191 await this._setupRoutes(obj);
192 }
193
194 resolve()
195 } catch (err) {
196 reject(err);
197 }
198 });
199 });
200
201 Promise.all(startProviderPromises)
202 .then(() => {
203 this._logger.info('[*] all Providers started');
204 resolve();
205 });
206 */
207
208 // SEQUENTIAL PROVIDERS INITIALIZATION
209 for (let k of Object.keys(this)) {
210 let obj = Object(this)[k];
211 if (/(provider)/i.test(obj.ctype)) {
212 await this._startProvider(obj);
213 this._logger.info(`[*] ${obj.constructor.name} provider started`, true);
214 ProvidersRegister.register(obj.constructor.name);
215
216 // setup routes for each Api provider
217 if (/router/i.test(obj.ctype)) {
218 await this._setupRoutes(obj);
219 }
220 }
221 }
222 resolve();
223 } catch (err) {
224 reject(err);
225 }
226 });
227 }
228
229 /**
230 * Start the service registering providers
231 * @returns {Promise<void>}
232 * @private
233 */
234 async _start() {
235 try {
236 this._logger.info('starting providers');
237 await this._startInjectedProviders();
238
239 try {
240 const mgmtConfig = config.get('management');
241 if (mgmtConfig.health) {
242 this._health = container.get('Health');
243 await this._startProvider(this._health);
244 } else {
245 this._logger.warn('No Health provider configured. Could be difficult to integrate with a Service Registry.', true);
246 }
247 this._management = container.get('Management');
248 await this._startProvider(this._management);
249 } catch (err) {
250 console.log(err);
251 this._logger.warn('No Management provider configuration found. The service will not have a Management endpoint.');
252 }
253
254 this._logger.info('registering service shutdown hook');
255 const shudownHook = async () => {
256 try {
257 console.log('\n');
258 this._logger.info('\uD83D\uDCA3 [shutdownHook] BORN TO KILL SERVICES!');
259 await this.stop();
260 process.exit(0);
261 } catch (err) {
262 this._logger.error(`error killing service process: ${err}`);
263 process.exit(1);
264 }
265 };
266
267 process.on('SIGTERM', shudownHook);
268 process.on('SIGINT', shudownHook);
269
270 this._logger.info(`service started [pid: ${process.pid}]`, true);
271 } catch (err) {
272 throw err;
273 }
274 }
275
276 /** Stops the service */
277 async stop() {
278 return new Promise(async (resolve, reject) => {
279 try {
280 this._logger.info('gracefully shutting down the service');
281
282 for (let k of Object.keys(this)) {
283 let obj = Object(this)[k];
284 if (/(provider)/i.test(obj.ctype)) {
285 obj.$stop && await obj.$stop();
286 this._logger.info(`${obj.name} provider stoppped`);
287 }
288 }
289
290 this._logger.info('service shutted down. Bye!');
291 resolve(true);
292 } catch (err) {
293 reject(err);
294 }
295 });
296 }
297
298 /**
299 * Set up the API routes.
300 * @private
301 */
302 async _setupRoutes(api) {
303 return new Promise((resolve, reject) => {
304 try {
305 this._logger.info(`setting up routes for ${this.constructor.name}`);
306 RoutesRegister.ids.forEach(iocId => {
307 const route = container.get(iocId);
308 this.addRoute(api, route);
309 });
310 //this.$setupRoutes();
311 resolve();
312 } catch (err) {
313 reject(err);
314 }
315 });
316
317 }
318
319 async _setHealthRoute() {
320 return new Promise((resolve, reject) => {
321 try {
322 const healthRoute = container.get('HealthRoute');
323 this.addRoute(healthRoute);
324 resolve();
325 } catch (err) {
326 reject(err);
327 }
328 });
329 }
330
331 /**
332 * Set up the API routes. To be implemented in the actual service class.
333 * @abstract
334 */
335 //$setupRoutes() {
336 //}
337
338
339 /**
340 * Add a route to the API router.
341 * @param {*} route - The route to add.
342 */
343 addRoute(api, route) {
344 route.$setupValidationRules();
345 route.$setupRoutes();
346 api.addRoute(route.basePath, route.router);
347 }
348
349 /**
350 * Called from derived service class to set injected instances (usually the injected providers instances)
351 * @param n - the instance to set
352 */
353 set ['name'](n) {
354 this['name'] = n;
355 }
356
357}
358
359module.exports = Application;/*!
360 * node-mu
361 * node.js minimalistic microservices framework on top of Express.js
362 *
363 * Copyright(c) 2018 IT Resources s.r.l.
364 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
365 *
366 * Permission is hereby granted, free of charge, to any person obtaining a copy
367 * of this software and associated documentation files (the "Software"), to deal
368 * in the Software without restriction, including without limitation the rights
369 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
370 * copies of the Software, and to permit persons to whom the Software is
371 * furnished to do so, subject to the following conditions:
372 *
373 * The above copyright notice and this permission notice shall be included in all
374 * copies or substantial portions of the Software.
375 *
376 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
377 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
378 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
379 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
380 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
381 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
382 * SOFTWARE.
383 *
384 * See node-mu license text even in LICENSE file.
385 *
386 * lib/node-mu/components/component.js
387 */
388
389'use strict';
390
391const uuidv1 = require('uuid/v1');
392const {LoggerWrapper} = require('../logger');
393
394/**
395 * A component class which generates and maintain an instance id.
396 * Actually used only by the AmqpProducer instance classes.
397 */
398class Component {
399
400 /**
401 * Initialize the component generating an uuid v1 code and grabbing the only the first part,
402 * and storing the class instance full name into an internal const.
403 */
404 constructor(ctype = 'component') {
405 this._id = uuidv1().split('-')[0];
406 this._name = this.constructor.name + '-' + this._id;
407 this._ctype = ctype;
408 this._logger = new LoggerWrapper(this.constructor.name, this._id);
409 }
410
411 /**
412 * Returns the instance id
413 * @return {number} _id - The instance id number.
414 */
415 get id() {
416 return this._id;
417 }
418
419 /**
420 * Returns the full class instance name.
421 * @return {string} _name - The instance class name.
422 */
423 get name() {
424 return this._name;
425 }
426
427 get ctype() {
428 return this._ctype;
429 }
430}
431
432module.exports = Component;
433/*!
434 * node-mu
435 * node.js minimalistic microservices framework on top of Express.js
436 *
437 * Copyright(c) 2018 IT Resources s.r.l.
438 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
439 *
440 * Permission is hereby granted, free of charge, to any person obtaining a copy
441 * of this software and associated documentation files (the "Software"), to deal
442 * in the Software without restriction, including without limitation the rights
443 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
444 * copies of the Software, and to permit persons to whom the Software is
445 * furnished to do so, subject to the following conditions:
446 *
447 * The above copyright notice and this permission notice shall be included in all
448 * copies or substantial portions of the Software.
449 *
450 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
451 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
452 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
453 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
454 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
455 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
456 * SOFTWARE.
457 *
458 * See node-mu license text even in LICENSE file.
459 *
460 * lib/node-mu/components/controllers/events-emitter.controller.js
461 */
462
463'use strict';
464
465const EventsEmitterController = require('./events-emitter.controller');
466
467/**
468 * A base class to derive a controller which can emit events on the default 'api-events' event-channel.
469 * The 'api-events' channel is the default node-mu channel to which publish events to be published on AMQP.
470 */
471class ApiEventsEmitterController extends EventsEmitterController {
472 constructor() {
473 super('api-events');
474 }
475}
476
477module.exports = ApiEventsEmitterController;
478/*!
479 * node-mu
480 * node.js minimalistic microservices framework on top of Express.js
481 *
482 * Copyright(c) 2018 IT Resources s.r.l.
483 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
484 *
485 * Permission is hereby granted, free of charge, to any person obtaining a copy
486 * of this software and associated documentation files (the "Software"), to deal
487 * in the Software without restriction, including without limitation the rights
488 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
489 * copies of the Software, and to permit persons to whom the Software is
490 * furnished to do so, subject to the following conditions:
491 *
492 * The above copyright notice and this permission notice shall be included in all
493 * copies or substantial portions of the Software.
494 *
495 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
496 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
497 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
498 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
499 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
500 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
501 * SOFTWARE.
502 *
503 * See node-mu license text even in LICENSE file.
504 *
505 * lib/node-mu/components/controllers/controller.js
506 */
507
508'use strict';
509
510const { injectable } = require('../../ioc');
511const Component = require('../component');
512const autoBind = require('auto-bind');
513
514class Controller extends Component {
515 /** Initialize the controller logger and binds its methods. */
516 constructor() {
517 super();
518 this._logger.info('auto-binding all methods');
519 autoBind(this);
520 }
521
522 /** used to return a converted view of a model (call it a dto!) */
523 _wrapResponse(model, converter, res, next) {
524 if (!model || model.length == 0) {
525 res.status(404);
526 return next();
527 } else {
528 return res.json(converter != null ? converter(model) : model);
529 }
530 }
531
532}
533
534module.exports = Controller;
535/*!
536 * node-mu
537 * node.js minimalistic microservices framework on top of Express.js
538 *
539 * Copyright(c) 2018 IT Resources s.r.l.
540 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
541 *
542 * Permission is hereby granted, free of charge, to any person obtaining a copy
543 * of this software and associated documentation files (the "Software"), to deal
544 * in the Software without restriction, including without limitation the rights
545 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
546 * copies of the Software, and to permit persons to whom the Software is
547 * furnished to do so, subject to the following conditions:
548 *
549 * The above copyright notice and this permission notice shall be included in all
550 * copies or substantial portions of the Software.
551 *
552 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
553 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
554 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
555 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
556 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
557 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
558 * SOFTWARE.
559 *
560 * See node-mu license text even in LICENSE file.
561 *
562 * lib/node-mu/components/controllers/events-emitter.controller.js
563 */
564
565'use strict';
566
567const Controller = require('./controller');
568const Hertzy = require('hertzy');
569
570/**
571 * A base class to derive a controller which can emit events on an Hertzy events-channel.
572 * Hertzy channels follows the Mediator desing pattern.
573 * Using this base class the actual derived controller can emit events to the channel
574 * and publish on an AMQP server staying decoupled from the AMQP Publisher.
575 */
576class EventsEmitterController extends Controller {
577
578 /**
579 * Initialize the controller with the events-channel.
580 * @param {string} eventChannelName - The events-channel name.
581 */
582 constructor(eventChannelName = undefined) {
583 super();
584
585 this._eventChannelName = eventChannelName;
586 if (this._eventChannelName) this._eventsChannel = Hertzy.tune(eventChannelName);
587 this._logger.info('Hertzy API events channel initialized as "api-events"');
588 }
589
590 set eventChannelName(name) {
591 this._eventChannelName = name;
592 this.startEventChannel();
593 }
594
595 get eventChannelName() {
596 return this._eventChannelName;
597 }
598
599 startEventChannel() {
600 this._eventsChannel = Hertzy.tune(eventChannelName);
601 }
602
603 /**
604 * Emit an event on the Event Channel. The event will be triggered by the service Events Emitter
605 * which in turn will publish it on the configured AMQP Server (on exchange).
606 *
607 * @param {*} evt - The event name
608 * @param {*} data - The event payload to be published into the AMQP server
609 */
610 emit(evt, data) {
611 this._eventsChannel.emit(evt, data);
612 }
613}
614
615module.exports = EventsEmitterController;
616/*!
617 * node-mu
618 * node.js minimalistic microservices framework on top of Express.js
619 *
620 * Copyright(c) 2018 IT Resources s.r.l.
621 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
622 *
623 * Permission is hereby granted, free of charge, to any person obtaining a copy
624 * of this software and associated documentation files (the "Software"), to deal
625 * in the Software without restriction, including without limitation the rights
626 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
627 * copies of the Software, and to permit persons to whom the Software is
628 * furnished to do so, subject to the following conditions:
629 *
630 * The above copyright notice and this permission notice shall be included in all
631 * copies or substantial portions of the Software.
632 *
633 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
634 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
635 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
636 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
637 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
638 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
639 * SOFTWARE.
640 *
641 * See node-mu license text even in LICENSE file.
642 *
643 * lib/node-mu/components/controllers/index.js
644 */
645
646'use strict';
647
648/** @module node-mu/controllers */
649module.exports = {
650 Controller: require('./controller'),
651 EventsEmitterController: require('./events-emitter.controller'),
652 ApiEventsEmitterController:require('./api-events-emitter.controller')
653};
654/*!
655 * node-mu
656 * node.js minimalistic microservices framework on top of Express.js
657 *
658 * Copyright(c) 2018 IT Resources s.r.l.
659 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
660 *
661 * Permission is hereby granted, free of charge, to any person obtaining a copy
662 * of this software and associated documentation files (the "Software"), to deal
663 * in the Software without restriction, including without limitation the rights
664 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
665 * copies of the Software, and to permit persons to whom the Software is
666 * furnished to do so, subject to the following conditions:
667 *
668 * The above copyright notice and this permission notice shall be included in all
669 * copies or substantial portions of the Software.
670 *
671 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
672 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
673 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
674 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
675 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
676 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
677 * SOFTWARE.
678 *
679 * See node-mu license text even in LICENSE file.
680 *
681 * lib/node-mu/components/index.js
682 */
683
684'use strict';
685
686module.exports = {
687 Component: require('./component'),
688 Controllers: require('./controllers'),
689 Route: require('./route'),
690 Service: require('./service'),
691 Repository: require('./repository')
692};/*!
693 * node-mu
694 * node.js minimalistic microservices framework on top of Express.js
695 *
696 * Copyright(c) 2018 IT Resources s.r.l.
697 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
698 *
699 * Permission is hereby granted, free of charge, to any person obtaining a copy
700 * of this software and associated documentation files (the "Software"), to deal
701 * in the Software without restriction, including without limitation the rights
702 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
703 * copies of the Software, and to permit persons to whom the Software is
704 * furnished to do so, subject to the following conditions:
705 *
706 * The above copyright notice and this permission notice shall be included in all
707 * copies or substantial portions of the Software.
708 *
709 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
710 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
711 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
712 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
713 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
714 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
715 * SOFTWARE.
716 *
717 * See node-mu license text even in LICENSE file.
718 *
719 * lib/node-mu/components/repository/index.js
720 */
721
722'use strict';
723
724/** @module node-mu/repository */
725module.exports = require('./repository');
726/*!
727 * node-mu
728 * node.js minimalistic microservices framework on top of Express.js
729 *
730 * Copyright(c) 2018 IT Resources s.r.l.
731 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
732 *
733 * Permission is hereby granted, free of charge, to any person obtaining a copy
734 * of this software and associated documentation files (the "Software"), to deal
735 * in the Software without restriction, including without limitation the rights
736 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
737 * copies of the Software, and to permit persons to whom the Software is
738 * furnished to do so, subject to the following conditions:
739 *
740 * The above copyright notice and this permission notice shall be included in all
741 * copies or substantial portions of the Software.
742 *
743 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
744 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
745 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
746 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
747 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
748 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
749 * SOFTWARE.
750 *
751 * See node-mu license text even in LICENSE file.
752 *
753 * lib/node-mu/components/repository/repository.js
754 */
755
756'use strict';
757
758const {EntityRepository} = require('objection-repositories');
759const {container} = require('../../ioc');
760
761class Repository extends EntityRepository {
762 constructor(Model) {
763 super((container.get('DbConnectionManager')).knex, Model);
764 }
765}
766
767module.exports = Repository;
768/*!
769 * node-mu
770 * node.js minimalistic microservices framework on top of Express.js
771 *
772 * Copyright(c) 2018 IT Resources s.r.l.
773 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
774 *
775 * Permission is hereby granted, free of charge, to any person obtaining a copy
776 * of this software and associated documentation files (the "Software"), to deal
777 * in the Software without restriction, including without limitation the rights
778 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
779 * copies of the Software, and to permit persons to whom the Software is
780 * furnished to do so, subject to the following conditions:
781 *
782 * The above copyright notice and this permission notice shall be included in all
783 * copies or substantial portions of the Software.
784 *
785 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
786 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
787 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
788 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
789 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
790 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
791 * SOFTWARE.
792 *
793 * See node-mu license text even in LICENSE file.
794 *
795 * lib/node-mu/components/route/index.js
796 */
797
798'use strict';
799
800/** @module node-mu/route */
801module.exports = require('./route');
802/*!
803 * node-mu
804 * node.js minimalistic microservices framework on top of Express.js
805 *
806 * Copyright(c) 2018 IT Resources s.r.l.
807 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
808 *
809 * Permission is hereby granted, free of charge, to any person obtaining a copy
810 * of this software and associated documentation files (the "Software"), to deal
811 * in the Software without restriction, including without limitation the rights
812 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
813 * copies of the Software, and to permit persons to whom the Software is
814 * furnished to do so, subject to the following conditions:
815 *
816 * The above copyright notice and this permission notice shall be included in all
817 * copies or substantial portions of the Software.
818 *
819 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
820 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
821 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
822 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
823 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
824 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
825 * SOFTWARE.
826 *
827 * See node-mu license text even in LICENSE file.
828 *
829 * lib/node-mu/components/route/route.js
830 */
831
832'use strict';
833
834const Component = require('../component');
835const express = require('express');
836const validate = require('express-validation');
837
838class Route extends Component {
839 constructor(basePath = '/') {
840 super();
841 this._basePath = basePath;
842 this._router = express.Router();
843 if (this._basePath) this._logger.debug('Route base path: ' + this._basePath);
844 }
845
846 route(basePath = '/', validationRules = []) {
847 this._basePath = basePath;
848 this._logger.debug('Route base path: ' + this._basePath);
849 this._validationRules = validationRules;
850 return this;
851 }
852
853 /**
854 * Returns this route Express Router.
855 * @return {express.Router} _router - This route Express Router.
856 */
857 get router() {
858 return this._router;
859 }
860
861 /**
862 * Returns thi route base path.
863 * @return {string} _basePath - The base path for this route.
864 */
865 get basePath() {
866 return this._basePath;
867 }
868
869 /**
870 * Adds a route.
871 * @param {string} method - HTTP method.
872 * @param {string} path - The route path.
873 * @param {[function]} handlers - The route handlers (middlewares... handler).
874 */
875 addRoute(method, path, ...handlers) {
876 this._logger.debug(`addRoute() - method: '${method}', path: '${path}'`);
877 const _validationRule = this.getValidationRule(path);
878 let validationOnRoute = false;
879 if (_validationRule && this._checkValidationRuleMethod(_validationRule.method, method)) {
880 this._logger.debug(`adding validation rule for method '${method}' on paht '${path}'`);
881 handlers.splice(0, 0, validate(_validationRule));
882 validationOnRoute = true;
883 }
884
885 this._router.route(path)[method](handlers);
886 this._logger.info(`[${method.toUpperCase()} ${this._basePath}${path}] route configured ${validationOnRoute ? ' (with validation rule)' : ''}`);
887 return this;
888 }
889
890 _checkValidationRuleMethod(ruleMethods, method) {
891 if(typeof array != "undefined" && array != null && array.length != null && array.length > 0){
892 for (let m of ruleMethods) {
893 if ((new RegExp(m, 'i')).test(method)) {
894 return true;
895 }
896 }
897 return false;
898 }
899 return true;
900 }
901
902 /**
903 * Adds a GET route.
904 * @param {string} path - The route path.
905 * @param {[function]} handlers - The route handlers (middlewares... handler).
906 */
907 get(path, ...handlers) {
908 return this.addRoute('get', path, handlers);
909 }
910
911 /**
912 * Adds a POST route.
913 * @param {string} path - The route path.
914 * @param {[function]} handlers - The route handlers (middlewares... handler).
915 */
916 post(path, ...handlers) {
917 return this.addRoute('post', path, handlers);
918 }
919
920 /**
921 * Adds a PUT route.
922 * @param {string} path - The route path.
923 * @param {[function]} handlers - The route handlers (middlewares... handler).
924 */
925 put(path, ...handlers) {
926 return this.addRoute('put', path, handlers);
927 }
928
929 /**
930 * Adds a DELETE route.
931 * @param {string} path - The route path.
932 * @param {[function]} handlers - The route handlers (middlewares... handler).
933 */
934 delete(path, ...handlers) {
935 return this.addRoute('delete', path, handlers);
936 }
937
938 /**
939 * Adds a PATCH route.
940 * @param {string} path - The route path.
941 * @param {[function]} handlers - The route handlers (middlewares... handler).
942 */
943 patch(path, ...handlers) {
944 return this.addRoute('patch', path, handlers);
945 }
946
947 /**
948 * Adds an OPTIONS route.
949 * @param {string} path - The route path.
950 * @param {[function]} handlers - The route handlers (middlewares... handler).
951 */
952 options(path, ...handlers) {
953 return this.addRoute('options', path, handlers);
954 }
955
956 /**
957 * Adds a HEAD route.
958 * @param {string} path - The route path.
959 * @param {[function]} handlers - The route handlers (middlewares... handler).
960 */
961 head(path, ...handlers) {
962 return this.addRoute('head', path, handlers);
963 }
964
965 setValidationRules(rules) {
966 this._validationRules = rules;
967 return this;
968 }
969
970 getValidationRule(path) {
971 if (this._validationRules) {
972 return this._validationRules[path];
973 }
974
975 return undefined;
976 }
977
978 /**
979 * Helper function called by the Service during initialization.
980 * Implement it in the derived Route class
981 */
982 $setupRoutes() {
983 }
984
985 /**
986 * Helper function called by the Service during initialization.
987 * Implement it in the derived Route class
988 */
989 $setupValidationRules() {
990 }
991
992
993}
994
995module.exports = Route;
996/*!
997 * node-mu
998 * node.js minimalistic microservices framework on top of Express.js
999 *
1000 * Copyright(c) 2018 IT Resources s.r.l.
1001 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1002 *
1003 * Permission is hereby granted, free of charge, to any person obtaining a copy
1004 * of this software and associated documentation files (the "Software"), to deal
1005 * in the Software without restriction, including without limitation the rights
1006 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1007 * copies of the Software, and to permit persons to whom the Software is
1008 * furnished to do so, subject to the following conditions:
1009 *
1010 * The above copyright notice and this permission notice shall be included in all
1011 * copies or substantial portions of the Software.
1012 *
1013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1014 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1015 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1016 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1017 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1018 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1019 * SOFTWARE.
1020 *
1021 * See node-mu license text even in LICENSE file.
1022 *
1023 * lib/node-mu/components/service/index.js
1024 */
1025
1026'use strict';
1027
1028/** @module node-mu/service */
1029module.exports = require('./service');
1030/*!
1031 * node-mu
1032 * node.js minimalistic microservices framework on top of Express.js
1033 *
1034 * Copyright(c) 2018 IT Resources s.r.l.
1035 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1036 *
1037 * Permission is hereby granted, free of charge, to any person obtaining a copy
1038 * of this software and associated documentation files (the "Software"), to deal
1039 * in the Software without restriction, including without limitation the rights
1040 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1041 * copies of the Software, and to permit persons to whom the Software is
1042 * furnished to do so, subject to the following conditions:
1043 *
1044 * The above copyright notice and this permission notice shall be included in all
1045 * copies or substantial portions of the Software.
1046 *
1047 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1048 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1049 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1050 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1051 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1052 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1053 * SOFTWARE.
1054 *
1055 * See node-mu license text even in LICENSE file.
1056 *
1057 * lib/node-mu/components/service/service.js
1058 */
1059
1060'use strict';
1061
1062const Component = require('../component');
1063
1064class Service extends Component {
1065 constructor(knex, entity) {
1066 super(knex, entity);
1067 }
1068}
1069
1070module.exports = Service;
1071/*!
1072 * node-mu
1073 * node.js minimalistic microservices framework on top of Express.js
1074 *
1075 * Copyright(c) 2018 IT Resources s.r.l.
1076 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1077 *
1078 * Permission is hereby granted, free of charge, to any person obtaining a copy
1079 * of this software and associated documentation files (the "Software"), to deal
1080 * in the Software without restriction, including without limitation the rights
1081 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1082 * copies of the Software, and to permit persons to whom the Software is
1083 * furnished to do so, subject to the following conditions:
1084 *
1085 * The above copyright notice and this permission notice shall be included in all
1086 * copies or substantial portions of the Software.
1087 *
1088 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1089 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1090 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1091 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1092 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1093 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1094 * SOFTWARE.
1095 *
1096 * See node-mu license text even in LICENSE file.
1097 *
1098 * lib/node-mu/ioc/index.js
1099 */
1100
1101'use strict';
1102
1103const inversify = require('inversify');
1104require('reflect-metadata');
1105const IocContainer = new (require('./ioc-container'))();
1106const container = IocContainer.container;
1107const logger = IocContainer.logger;
1108//const ProvidersRegister = require('../providers/health/providers-register');
1109const RoutesRegister = require('../providers/api/routes-register');
1110
1111const injectable = (target, singleton = false) => {
1112 logger.debug(`registering ${target.name} type as injectable`);
1113 target.prototype.ioc = {id: target.name};
1114 inversify.decorate(inversify.injectable(), target);
1115 logger.debug(`binding '${target.prototype.ioc.id}' to ${target.name} into the IoC Container`);
1116 const _bindContext = container.bind(target.name).to(target);
1117 if (singleton) {
1118 _bindContext.inSingletonScope();
1119 logger.debug(`${target.name} binded as Singleton`);
1120 }
1121 return target;
1122};
1123
1124const component = (target) => {
1125 return injectable(target);
1126};
1127
1128const provider = (target, singleton = true) => {
1129 const injectableProvider = injectable(target, singleton);
1130 //ProvidersRegister.register(injectableProvider.prototype.ioc.id);
1131 logger.debug(`provider ${injectableProvider.prototype.ioc.id} registered into the Providers Register`);
1132 return injectableProvider;
1133};
1134
1135const factoryFunction = (target) => {
1136 logger.debug(`registering factory ${target.name} type as injectable`);
1137 target.prototype.ioc = {id: target.name};
1138 logger.debug(`binding '${target.prototype.ioc.id}' to ${target.name} into the IoC Container`);
1139 container.bind(target.name).toFunction(target);
1140 return target;
1141};
1142
1143const controller = (target) => {
1144 return injectable(target);
1145};
1146
1147const route = (target) => {
1148 const injectableRoute = injectable(target);
1149 RoutesRegister.register(injectableRoute.prototype.ioc.id);
1150 logger.debug(`route ${injectableRoute.prototype.ioc.id} registered into the Routes Register`);
1151 return injectableRoute;
1152};
1153
1154const service = (target) => {
1155 return injectable(target);
1156};
1157
1158const repository = (target) => {
1159 return injectable(target);
1160};
1161
1162const application = (target) => {
1163 let appTarget = injectable(target, true);
1164 global.APPLICATION_TYPE = appTarget.prototype.ioc.id;
1165 return appTarget;
1166};
1167
1168const isInjectable = (target) => {
1169 return target.prototype.ioc && target.prototype.ioc.id;
1170};
1171
1172const inject = (injectables, target) => {
1173 for (let order = 0; order < injectables.length; order++) {
1174 const injectable = injectables[order];
1175 logger.debug(`injecting ${injectable.name} into ${target.name}`);
1176 if (!isInjectable(injectable)) {
1177 throw Error(`${injectable.name} is not registered as injectable in the IoC Container.`);
1178 } else if (!container.isBound(injectable.prototype.ioc.id)) {
1179 throw Error(`${injectable.name} is unbound in the IoC Container.`);
1180 }
1181
1182 logger.debug(`making ${injectable.prototype.ioc.id} injectable into ${target.name}`);
1183 inversify.decorate(inversify.inject(injectable.prototype.ioc.id), target, order);
1184 }
1185
1186 return target;
1187};
1188
1189
1190module.exports = {
1191 container,
1192 injectable,
1193 component,
1194 provider,
1195 factoryFunction,
1196 route,
1197 controller,
1198 service,
1199 repository,
1200 application,
1201 inject
1202};
1203/*!
1204 * node-mu
1205 * node.js minimalistic microservices framework on top of Express.js
1206 *
1207 * Copyright(c) 2018 IT Resources s.r.l.
1208 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1209 *
1210 * Permission is hereby granted, free of charge, to any person obtaining a copy
1211 * of this software and associated documentation files (the "Software"), to deal
1212 * in the Software without restriction, including without limitation the rights
1213 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1214 * copies of the Software, and to permit persons to whom the Software is
1215 * furnished to do so, subject to the following conditions:
1216 *
1217 * The above copyright notice and this permission notice shall be included in all
1218 * copies or substantial portions of the Software.
1219 *
1220 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1221 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1222 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1223 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1224 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1225 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1226 * SOFTWARE.
1227 *
1228 * See node-mu license text even in LICENSE file.
1229 *
1230 * lib/node-mu/ioc/ioc-container.js
1231 */
1232
1233'use strict';
1234
1235const inversify = require('inversify');
1236require('reflect-metadata');
1237const {LoggerWrapper} = require('../logger');
1238
1239let _instance = null;
1240
1241class IocContainer {
1242 constructor() {
1243 if (!_instance) {
1244 this._container = new inversify.Container({skipBaseClassChecks: true});
1245 _instance = this;
1246 this._logger = new LoggerWrapper(this.constructor.name);
1247 }
1248
1249 return _instance;
1250 }
1251
1252 get container() {
1253 return this._container;
1254 }
1255
1256 get logger() {
1257 return this._logger;
1258 }
1259}
1260
1261module.exports = IocContainer;
1262/*!
1263 * node-mu
1264 * node.js minimalistic microservices framework on top of Express.js
1265 *
1266 * Copyright(c) 2018 IT Resources s.r.l.
1267 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1268 *
1269 * Permission is hereby granted, free of charge, to any person obtaining a copy
1270 * of this software and associated documentation files (the "Software"), to deal
1271 * in the Software without restriction, including without limitation the rights
1272 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1273 * copies of the Software, and to permit persons to whom the Software is
1274 * furnished to do so, subject to the following conditions:
1275 *
1276 * The above copyright notice and this permission notice shall be included in all
1277 * copies or substantial portions of the Software.
1278 *
1279 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1280 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1281 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1282 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1283 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1284 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1285 * SOFTWARE.
1286 *
1287 * See node-mu license text even in LICENSE file.
1288 *
1289 * lib/node-mu/logger/index.js
1290 */
1291
1292'use strict';
1293
1294/** @module node-mu/logger */
1295module.exports = {
1296 Logger: require('./logger'),
1297 LoggerWrapper: require('./logger-wrapper')
1298}/*!
1299 * node-mu
1300 * node.js minimalistic microservices framework on top of Express.js
1301 *
1302 * Copyright(c) 2018 IT Resources s.r.l.
1303 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1304 *
1305 * Permission is hereby granted, free of charge, to any person obtaining a copy
1306 * of this software and associated documentation files (the "Software"), to deal
1307 * in the Software without restriction, including without limitation the rights
1308 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1309 * copies of the Software, and to permit persons to whom the Software is
1310 * furnished to do so, subject to the following conditions:
1311 *
1312 * The above copyright notice and this permission notice shall be included in all
1313 * copies or substantial portions of the Software.
1314 *
1315 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1316 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1317 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1318 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1319 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1320 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1321 * SOFTWARE.
1322 *
1323 * See node-mu license text even in LICENSE file.
1324 *
1325 * lib/node-mu/logger/logger-wrapper.js
1326 */
1327
1328'use strict';
1329
1330const Logger = require('./logger');
1331
1332/** Helper wrapper for the logger. */
1333class LoggerWrapper {
1334 constructor(cname, id = undefined) {
1335 this._logger = (new Logger()).logger;
1336 this._cname = cname;
1337 this._id = id;
1338 }
1339
1340 /** Logs out in INFO level. */
1341 info(msg, evidence = false) {
1342 evidence && this._logger.info(` ${this._msg('-'.repeat(msg.length))}`);
1343 this._logger.info(` ${this._msg(msg)}`);
1344 evidence && this._logger.info(` ${this._msg('-'.repeat(msg.length))}`);
1345 }
1346
1347 /** Logs out in DEBUG level. */
1348 debug(msg) {
1349 this._logger.debug(this._msg(msg));
1350 }
1351
1352 /** Logs out in ERROR level. */
1353 error(msg) {
1354 this._logger.error(this._msg(msg));
1355 }
1356
1357 /** Logs out in WARN level */
1358 warn(msg, evidence = false) {
1359 evidence && this._logger.warn(` ${this._msg('-'.repeat(msg.length))}`);
1360 this._logger.warn(` ${this._msg(msg)}`);
1361 evidence && this._logger.warn(` ${this._msg('-'.repeat(msg.length))}`);
1362 }
1363
1364 _msg(msg) {
1365 return `[${this._cname.padEnd(29)}]${this._id ? ' - [' + this._id + '] - ' : '-'} ${msg}`;
1366 }
1367
1368}
1369
1370module.exports = LoggerWrapper;/*!
1371 * node-mu
1372 * node.js minimalistic microservices framework on top of Express.js
1373 *
1374 * Copyright(c) 2018 IT Resources s.r.l.
1375 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1376 *
1377 * Permission is hereby granted, free of charge, to any person obtaining a copy
1378 * of this software and associated documentation files (the "Software"), to deal
1379 * in the Software without restriction, including without limitation the rights
1380 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1381 * copies of the Software, and to permit persons to whom the Software is
1382 * furnished to do so, subject to the following conditions:
1383 *
1384 * The above copyright notice and this permission notice shall be included in all
1385 * copies or substantial portions of the Software.
1386 *
1387 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1388 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1389 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1390 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1391 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1392 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1393 * SOFTWARE.
1394 *
1395 * See node-mu license text even in LICENSE file.
1396 *
1397 * lib/node-mu/logger/logger.js
1398 */
1399
1400'use strict';
1401
1402const path = require('path');
1403const config = require('config');
1404const winston = require('winston');
1405require('winston-daily-rotate-file');
1406const fs = require('fs');
1407const { serviceInfo } = require('../utils');
1408
1409let _instance = null;
1410
1411/** Singleton for the main logger class. */
1412class Logger {
1413 constructor() {
1414 if (!_instance) {
1415 this._configuration = config.get('log');
1416 this._initialize();
1417 _instance = this;
1418 } else {
1419 return _instance;
1420 }
1421 }
1422
1423 /**
1424 * Initialize the logger Winston transport.
1425 * @private
1426 */
1427 _initialize() {
1428 const fullPath = path.join(process.cwd(), this._configuration.path);
1429 if (!fs.existsSync(fullPath)) {
1430 fs.mkdirSync(fullPath);
1431 }
1432
1433 const fullname = path.join(fullPath, serviceInfo.name);
1434
1435 const fileTransport = new (winston.transports.DailyRotateFile)({
1436 filename: fullname + '-%DATE%.log',
1437 datePattern: 'DD-MM-YYYY',
1438 zippedArchive: true,
1439 maxSize: '20m',
1440 maxFiles: '14d',
1441 level: this._configuration.level,
1442 json: false
1443 });
1444
1445 const transports = [fileTransport];
1446 if (this._configuration.console) {
1447 transports.push(new winston.transports.Console({ json: false, colorize: true, level: this._configuration.level }));
1448 }
1449
1450 this._logger = new (winston.Logger)({
1451 transports,
1452 });
1453 this._logger.exitOnError = false;
1454 }
1455
1456 /**
1457 * Returns this logger object.
1458 * @return {winston.Logger} _logger - The internal winston logger instance.
1459 */
1460 get logger() {
1461 return this._logger;
1462 }
1463}
1464
1465module.exports = Logger;
1466/*!
1467 * node-mu
1468 * node.js minimalistic microservices framework on top of Express.js
1469 *
1470 * Copyright(c) 2018 IT Resources s.r.l.
1471 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1472 *
1473 * Permission is hereby granted, free of charge, to any person obtaining a copy
1474 * of this software and associated documentation files (the "Software"), to deal
1475 * in the Software without restriction, including without limitation the rights
1476 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1477 * copies of the Software, and to permit persons to whom the Software is
1478 * furnished to do so, subject to the following conditions:
1479 *
1480 * The above copyright notice and this permission notice shall be included in all
1481 * copies or substantial portions of the Software.
1482 *
1483 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1484 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1485 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1486 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1487 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1488 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1489 * SOFTWARE.
1490 *
1491 * See node-mu license text even in LICENSE file.
1492 *
1493 * lib/node-mu/providers/amqp/amqp-connection-manager.provider.js
1494 */
1495
1496'use strict';
1497
1498const {provider} = require('../../ioc');
1499const {LoggerWrapper} = require('../../logger');
1500const Provider = require('../provider');
1501const config = require('config');
1502const amqp = require('amqplib');
1503const axios = require('axios');
1504
1505module.exports =
1506 provider(
1507 class AmqpConnectionManager extends Provider {
1508 constructor() {
1509 super();
1510 }
1511
1512 async $start() {
1513 try {
1514 this._amqpConfig = config.get('amqp');
1515 this._logger.debug(JSON.stringify(this._amqpConfig));
1516
1517 await this.connect();
1518 } catch (err) {
1519 throw err;
1520 }
1521 }
1522
1523 async $stop() {
1524 try {
1525 await this._channel.close();
1526 this._logger.debug('AMQP Channel closed');
1527
1528 await this._connection.close();
1529 this._logger.debug('AMQP Connection closed');
1530 } catch (err) {
1531 throw err;
1532 }
1533 }
1534
1535 /** Connect to the AMQP Server and open a channel on the connetion. */
1536 async connect() {
1537 if (!this._connection) {
1538 try {
1539 this._connection = await amqp.connect(this._amqpConfig.url);
1540 this._logger.info(`AMQP connection established`);
1541 } catch (error) {
1542 this._logger.error(`error connecting to AMQP: ${error}`);
1543 throw error;
1544 }
1545 }
1546
1547 // here we open the channel to the queue
1548 if (!this._channel) {
1549 try {
1550 this._channel = await this._connection.createChannel();
1551 this._logger.info('AMQP channel opened');
1552
1553 this._channel.on('error', async (err) => {
1554 this._logger.error(`error on AMQP channel: ${err}`);
1555 });
1556 } catch (error) {
1557 this._logger.error(`error creating channel on AMQP connection: ${error}`);
1558 throw error;
1559 }
1560 }
1561 }
1562
1563 /**
1564 * Returns the AMQP connection channel.
1565 * @return {object} _channel - The AMQP connection channel.
1566 */
1567 get channel() {
1568 return this._channel;
1569 }
1570
1571 async getRabbitHealth() {
1572 try {
1573 return await axios.get('http://guest:guest@127.0.0.1:15672/api/aliveness-test/%2F');
1574 /*, {
1575 auth: {
1576 username: 'guest',
1577 password: 'guest'
1578 }
1579 })*/
1580 } catch (err) {
1581 throw err;
1582 }
1583 }
1584
1585 $isCheckableForHealth() {
1586 return true;
1587 }
1588
1589 async $health() {
1590 return new Promise(async (resolve, reject) => {
1591 try {
1592 const response = await this.getRabbitHealth();
1593 resolve({
1594 status: 'UP',
1595 message: response.data
1596 });
1597 } catch (err) {
1598 if (err.errno == 'ECONNREFUSED') {
1599 reject({
1600 status: 'DOWN',
1601 message: err.stack
1602 });
1603 } else if (err.message.indexOf('401')) {
1604 reject({
1605 status: 'UNKNOWN',
1606 message: 'unauthorized RabbitMQ user'
1607 });
1608 }
1609 }
1610 });
1611 }
1612
1613 get $healthId() {
1614 return 'amqp';
1615 }
1616
1617 }
1618 );
1619/*!
1620 * node-mu
1621 * node.js minimalistic microservices framework on top of Express.js
1622 *
1623 * Copyright(c) 2018 IT Resources s.r.l.
1624 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1625 *
1626 * Permission is hereby granted, free of charge, to any person obtaining a copy
1627 * of this software and associated documentation files (the "Software"), to deal
1628 * in the Software without restriction, including without limitation the rights
1629 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1630 * copies of the Software, and to permit persons to whom the Software is
1631 * furnished to do so, subject to the following conditions:
1632 *
1633 * The above copyright notice and this permission notice shall be included in all
1634 * copies or substantial portions of the Software.
1635 *
1636 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1637 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1638 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1639 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1640 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1641 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1642 * SOFTWARE.
1643 *
1644 * See node-mu license text even in LICENSE file.
1645 *
1646 * lib/node-mu/providers/amqp/amqp-publisher.factory.js
1647 */
1648
1649'use strict';
1650
1651const {container, factoryFunction} = require('../../ioc');
1652
1653module.exports =
1654 factoryFunction(
1655 function AmqpPublisherFactory(destination) {
1656 return {
1657 newPublisher: (destination) => {
1658 const publisher = container.get('AmqpPublisher');
1659 publisher.init(destination);
1660 return publisher;
1661 }
1662 }
1663 }
1664 );
1665/*!
1666 * node-mu
1667 * node.js minimalistic microservices framework on top of Express.js
1668 *
1669 * Copyright(c) 2018 IT Resources s.r.l.
1670 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1671 *
1672 * Permission is hereby granted, free of charge, to any person obtaining a copy
1673 * of this software and associated documentation files (the "Software"), to deal
1674 * in the Software without restriction, including without limitation the rights
1675 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1676 * copies of the Software, and to permit persons to whom the Software is
1677 * furnished to do so, subject to the following conditions:
1678 *
1679 * The above copyright notice and this permission notice shall be included in all
1680 * copies or substantial portions of the Software.
1681 *
1682 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1683 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1684 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1685 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1686 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1687 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1688 * SOFTWARE.
1689 *
1690 * See node-mu license text even in LICENSE file.
1691 *
1692 * lib/node-mu/providers/amqp/amqp-publisher.provider.js
1693 */
1694
1695'use strict';
1696
1697const {inject, provider} = require('../../ioc');
1698const Provider = require('../provider');
1699const AmqpConnectionManager = require('./amqp-connection-manager.provider');
1700
1701module.exports =
1702 inject(
1703 [AmqpConnectionManager],
1704 provider(
1705 class AmqpPublisher extends Provider {
1706 constructor(amqpConnectionManager) {
1707 super();
1708 this._channel = amqpConnectionManager.channel;
1709 }
1710
1711 init(destination) {
1712 this._detination;
1713 this._logger.debug(`destination ${JSON.stringify(destination)} initialized`);
1714 }
1715
1716 publish(evt, dest = undefined) {
1717 const destination = dest || this._destination;
1718 this._logger.debug(`publishing to: ${JSON.stringify(destination)}`);
1719
1720 this._logger.debug('check exchange');
1721 this._channel.checkExchange(destination.name)
1722 .then((res, err) => {
1723 if (err) {
1724 this._logger.error('** ' + err);
1725 return;
1726 }
1727 this._logger.debug(`check exchange ${destination.name} ok`);
1728 const result = this._channel.publish(destination.name, destination.route, new Buffer(JSON.stringify(evt)));
1729 this._logger.debug(`publish result: ${result}`);
1730 })
1731 .catch((err) => {
1732 this._logger.error(`AMQP exchange ${destination.name} does not exists. Error: ${err}`);
1733 })
1734 }
1735 }
1736 )
1737 );
1738/*!
1739 * node-mu
1740 * node.js minimalistic microservices framework on top of Express.js
1741 *
1742 * Copyright(c) 2018 IT Resources s.r.l.
1743 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1744 *
1745 * Permission is hereby granted, free of charge, to any person obtaining a copy
1746 * of this software and associated documentation files (the "Software"), to deal
1747 * in the Software without restriction, including without limitation the rights
1748 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1749 * copies of the Software, and to permit persons to whom the Software is
1750 * furnished to do so, subject to the following conditions:
1751 *
1752 * The above copyright notice and this permission notice shall be included in all
1753 * copies or substantial portions of the Software.
1754 *
1755 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1756 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1757 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1758 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1759 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1760 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1761 * SOFTWARE.
1762 *
1763 * See node-mu license text even in LICENSE file.
1764 *
1765 * lib/node-mu/providers/amqp/index.js
1766 */
1767
1768'use strict';
1769
1770module.exports = {
1771 AmqpConnectionManager: require('./amqp-connection-manager.provider'),
1772 AmqpPublisher: require('./amqp-publisher.provider'),
1773 AmqpPublisherFactory: require('./amqp-publisher.factory')
1774};/*!
1775 * node-mu
1776 * node.js minimalistic microservices framework on top of Express.js
1777 *
1778 * Copyright(c) 2018 IT Resources s.r.l.
1779 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1780 *
1781 * Permission is hereby granted, free of charge, to any person obtaining a copy
1782 * of this software and associated documentation files (the "Software"), to deal
1783 * in the Software without restriction, including without limitation the rights
1784 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1785 * copies of the Software, and to permit persons to whom the Software is
1786 * furnished to do so, subject to the following conditions:
1787 *
1788 * The above copyright notice and this permission notice shall be included in all
1789 * copies or substantial portions of the Software.
1790 *
1791 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1792 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1793 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1794 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1795 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1796 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1797 * SOFTWARE.
1798 *
1799 * See node-mu license text even in LICENSE file.
1800 *
1801 * lib/node-mu/providers/api/api.provider.js
1802 */
1803
1804'use strict';
1805
1806const {container, provider} = require('../../ioc');
1807const express = require('express');
1808const Router = require('./router');
1809const http = require('http');
1810const bodyParser = require('body-parser');
1811const compression = require('compression');
1812const methodOverride = require('method-override');
1813const helmet = require('helmet');
1814const cors = require('cors');
1815const ignoreFavicon = require('./middlewares/ignore-favicon');
1816const errorMiddleware = require('./middlewares/error');
1817const enableDestroy = require('server-destroy');
1818const expressWinston = require('express-winston');
1819const RequestLoggerTransport = require('./request-logger-transport');
1820const passport = require('passport');
1821const passportStrategy = require('./passport-strategy');
1822const config = require('config');
1823const routesRegister = require('./routes-register');
1824
1825module.exports =
1826 provider(
1827 class Api extends Router {
1828 constructor() {
1829 super();
1830
1831 this._endpointConfig = config.get('api.endpoint');
1832 this._securityConfig = config.get('api.security');
1833 //this._jwtConfig = config.get('jwt');
1834
1835 this._app = express();
1836 this._configureApp();
1837
1838 this._logger.info('initializing API server');
1839 this._logger.info(`routing with basePath: ${this._endpointConfig.baseRoutingPath}`);
1840 this._app.use(this._endpointConfig.baseRoutingPath, this.routes);
1841
1842 this._logger.info('setting up error handler');
1843 this._setupErrorHandlers();
1844 }
1845
1846 async $start() {
1847 return new Promise((resolve, reject) => {
1848 this._logger.debug('starting API server');
1849 this._server = http.createServer(this._app);
1850 this._server.listen(this._endpointConfig.port, (err) => {
1851 if (err) {
1852 return reject(err);
1853 }
1854 this._logger.info(`API server Listening on http://${this._server.address().address}:${this._server.address().port}`);
1855
1856 return resolve();
1857 });
1858
1859 /* Hack to close all pending connections: https://github.com/isaacs/server-destroy */
1860 enableDestroy(this._server);
1861 });
1862 }
1863
1864 /** Stops the API Http server. */
1865 async $stop() {
1866 return new Promise((resolve, reject) => {
1867 this._logger.debug('gracefully shutting down the Api server');
1868 if (this._server) {
1869 this._server.destroy(() => {
1870 this._logger.debug('API server destroyed');
1871 return resolve(true);
1872 });
1873 } else {
1874 this._logger.warn('[API] API server destroyed (it was null!)');
1875 return resolve(true);
1876 }
1877 });
1878 }
1879
1880 /**
1881 * Configure the Express app.
1882 * @private
1883 */
1884 _configureApp() {
1885 this._logger.debug('configuring API express app');
1886
1887 this._requestLoggerTransport = new RequestLoggerTransport();
1888 this._app.use(expressWinston.logger(this._requestLoggerTransport.requestsLoggerTransports));
1889
1890 this._app.use(bodyParser.json());
1891 this._app.use(bodyParser.urlencoded({extended: true}));
1892 this._app.use(compression());
1893 this._app.use(methodOverride());
1894 this._app.use(helmet());
1895 this._app.use(cors());
1896 this._app.use(ignoreFavicon);
1897
1898 //if (this._endpointConfig.authEnabled) {
1899 if (this._securityConfig.enabled) {
1900 this._app.use(passport.initialize());
1901 passport.use('jwt', passportStrategy(this._securityConfig.jwt.secret));
1902 }
1903
1904 }
1905
1906 /**
1907 * Configure the Api error handlers.
1908 * @private
1909 */
1910 _setupErrorHandlers() {
1911 // configure error logger
1912 this._app.use(expressWinston.errorLogger(this._requestLoggerTransport.errorLoggerTransports));
1913 this._logger.debug('errorLogger ok');
1914
1915 // convert APIError error
1916 this._app.use(errorMiddleware.converter);
1917 this._logger.debug('errorMiddleware.converter ok');
1918
1919 // catch 404 and go on to error handler
1920 this._app.use(errorMiddleware.notFound);
1921 this._logger.debug('errorMiddleware.notFound ok');
1922
1923 // error handler: stacktrace is sent only in development
1924 this._app.use(errorMiddleware.handler);
1925 this._logger.debug('errorMiddleware.handler ok');
1926 }
1927
1928 get $healthId() {
1929 return 'api';
1930 }
1931 }
1932 );/*!
1933 * node-mu
1934 * node.js minimalistic microservices framework on top of Express.js
1935 *
1936 * Copyright(c) 2018 IT Resources s.r.l.
1937 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1938 *
1939 * Permission is hereby granted, free of charge, to any person obtaining a copy
1940 * of this software and associated documentation files (the "Software"), to deal
1941 * in the Software without restriction, including without limitation the rights
1942 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1943 * copies of the Software, and to permit persons to whom the Software is
1944 * furnished to do so, subject to the following conditions:
1945 *
1946 * The above copyright notice and this permission notice shall be included in all
1947 * copies or substantial portions of the Software.
1948 *
1949 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1950 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1951 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1952 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1953 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1954 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1955 * SOFTWARE.
1956 *
1957 * See node-mu license text even in LICENSE file.
1958 *
1959 * lib/node-mu/providers/api/index.js
1960 */
1961
1962'use strict';
1963
1964/** @module node-mu/api */
1965module.exports = {
1966 Api: require('./api.provider'),
1967 AuthMiddleware: require('./middlewares/auth').authorize
1968};/*!
1969 * node-mu
1970 * node.js minimalistic microservices framework on top of Express.js
1971 *
1972 * Copyright(c) 2018 IT Resources s.r.l.
1973 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
1974 *
1975 * Permission is hereby granted, free of charge, to any person obtaining a copy
1976 * of this software and associated documentation files (the "Software"), to deal
1977 * in the Software without restriction, including without limitation the rights
1978 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1979 * copies of the Software, and to permit persons to whom the Software is
1980 * furnished to do so, subject to the following conditions:
1981 *
1982 * The above copyright notice and this permission notice shall be included in all
1983 * copies or substantial portions of the Software.
1984 *
1985 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1986 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1987 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1988 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1989 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1990 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1991 * SOFTWARE.
1992 *
1993 * See node-mu license text even in LICENSE file.
1994 *
1995 * lib/node-muproviders/api/middlewares/auth.js
1996 */
1997
1998'use strict';
1999
2000const jwt = require('jsonwebtoken');
2001const httpStatus = require('http-status');
2002const passport = require('passport');
2003const { APIError } = require('../../../utils');
2004
2005
2006const handleJWT = (req, res, next, roles) => async (err, user, info) => {
2007 const error = err || info;
2008 const apiError = new APIError({
2009 message: error ? error.message : 'Unauthorized',
2010 status: httpStatus.UNAUTHORIZED,
2011 stack: error ? error.stack : undefined,
2012 });
2013
2014 // TODO: check if this is better
2015 // if (error || !user) {
2016 // return next(apiError);
2017 // }
2018 try {
2019 if (error || !user) {
2020 throw error;
2021 }
2022 } catch (err) {
2023 return next(apiError);
2024 }
2025
2026 const hasRole = user.auth.some(role => {
2027 return roles.indexOf(role) > -1;
2028 });
2029 if (!hasRole) {
2030 apiError.stack = 'User role has no permission for path ' + req.path;
2031 return next(apiError);
2032 }
2033
2034 req.user = user;
2035
2036 return next();
2037};
2038
2039// TODO: put roles in configuration file
2040exports.authorize = (roles = ['ROLE_ADMIN', 'ROLE_USER', 'ROLE_PARENT', 'ROLE_PEDIATRICIAN']) => (req, res, next) =>
2041 passport.authenticate(
2042 'jwt', { session: false },
2043 handleJWT(req, res, next, roles)
2044 )(req, res, next);/*!
2045 * node-mu
2046 * node.js minimalistic microservices framework on top of Express.js
2047 *
2048 * Copyright(c) 2018 IT Resources s.r.l.
2049 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2050 *
2051 * Permission is hereby granted, free of charge, to any person obtaining a copy
2052 * of this software and associated documentation files (the "Software"), to deal
2053 * in the Software without restriction, including without limitation the rights
2054 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2055 * copies of the Software, and to permit persons to whom the Software is
2056 * furnished to do so, subject to the following conditions:
2057 *
2058 * The above copyright notice and this permission notice shall be included in all
2059 * copies or substantial portions of the Software.
2060 *
2061 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2062 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2063 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2064 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2065 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2066 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2067 * SOFTWARE.
2068 *
2069 * See node-mu license text even in LICENSE file.
2070 *
2071 * lib/node-mu/providers/api/middlewares/error.js
2072 */
2073
2074'use strict';
2075
2076const httpStatus = require('http-status');
2077const expressValidation = require('express-validation');
2078const { APIError } = require('../../../utils');
2079const { LoggerWrapper } = require('../../../logger');
2080
2081/**
2082 * Error handler. Send stacktrace only during development
2083 * @public
2084 */
2085const handler = (err, req, res, next) => {
2086 const env = process.NODE_ENV || 'development';
2087 const response = {
2088 code: err.status,
2089 message: err.message || httpStatus[err.status],
2090 errors: err.errors,
2091 stack: err.stack,
2092 };
2093
2094 if (env !== 'development') {
2095 delete response.stack;
2096 }
2097
2098 res.status(err.status);
2099 res.json(response);
2100 res.end();
2101};
2102
2103/**
2104 * If error is not an instanceOf APIError, convert it.
2105 * @public
2106 */
2107const converter = (err, req, res, next) => {
2108 let convertedError = err;
2109
2110 if (err instanceof expressValidation.ValidationError) {
2111 convertedError = new APIError({
2112 message: 'Validation error',
2113 errors: err.errors,
2114 status: err.status,
2115 stack: err.stack,
2116 });
2117 } else if (!(err instanceof APIError)) {
2118 convertedError = new APIError({
2119 message: err.message,
2120 status: err.status,
2121 stack: err.stack,
2122 });
2123 }
2124
2125 return handler(convertedError, req, res);
2126};
2127
2128/**
2129 * Catch 404 and forward to error handler
2130 * @public
2131 */
2132const notFound = (req, res, next) => {
2133 const err = new APIError({
2134 message: 'Not found',
2135 status: httpStatus.NOT_FOUND,
2136 });
2137 return handler(err, req, res);
2138};
2139
2140module.exports = {
2141 handler, converter, notFound
2142}/*!
2143 * node-mu
2144 * node.js minimalistic microservices framework on top of Express.js
2145 *
2146 * Copyright(c) 2018 IT Resources s.r.l.
2147 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2148 *
2149 * Permission is hereby granted, free of charge, to any person obtaining a copy
2150 * of this software and associated documentation files (the "Software"), to deal
2151 * in the Software without restriction, including without limitation the rights
2152 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2153 * copies of the Software, and to permit persons to whom the Software is
2154 * furnished to do so, subject to the following conditions:
2155 *
2156 * The above copyright notice and this permission notice shall be included in all
2157 * copies or substantial portions of the Software.
2158 *
2159 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2160 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2161 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2162 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2163 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2164 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2165 * SOFTWARE.
2166 *
2167 * See node-mu license text even in LICENSE file.
2168 *
2169 * lib/node-mu/providers/api/middlewares/ignore-favicon.js
2170 */
2171
2172'use strict';
2173
2174/** A moddleware to ignore the browsers' favicon requests. */
2175module.exports = (req, res, next) => {
2176 if (req.originalUrl === '/favicon.ico') {
2177 res.status(204).json({ nope: true });
2178 } else {
2179 next();
2180 }
2181};/*!
2182 * node-mu
2183 * node.js minimalistic microservices framework on top of Express.js
2184 *
2185 * Copyright(c) 2018 IT Resources s.r.l.
2186 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2187 *
2188 * Permission is hereby granted, free of charge, to any person obtaining a copy
2189 * of this software and associated documentation files (the "Software"), to deal
2190 * in the Software without restriction, including without limitation the rights
2191 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2192 * copies of the Software, and to permit persons to whom the Software is
2193 * furnished to do so, subject to the following conditions:
2194 *
2195 * The above copyright notice and this permission notice shall be included in all
2196 * copies or substantial portions of the Software.
2197 *
2198 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2199 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2200 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2201 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2202 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2203 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2204 * SOFTWARE.
2205 *
2206 * See node-mu license text even in LICENSE file.
2207 *
2208 * lib/node-mu/providers/api/passport-strategy.js
2209 */
2210
2211'use strict';
2212
2213const JwtStrategy = require('passport-jwt').Strategy;
2214const BearerStrategy = require('passport-http-bearer');
2215const {ExtractJwt} = require('passport-jwt');
2216
2217module.exports = (secret) => {
2218 const jwtOptions = {
2219 secretOrKey: new Buffer(secret, 'base64'),
2220 jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('Bearer'),
2221 algorithms: ['HS512'],
2222 jsonWebTokenOptions: {algorithm: 'HS512'}
2223 };
2224
2225 const jwt = async (payload, done) => {
2226 try {
2227 if (payload) {
2228 return done(null, payload);
2229 }
2230 return done(null, false);
2231 } catch (error) {
2232 return done(error, false);
2233 }
2234 };
2235
2236 return new JwtStrategy(jwtOptions, jwt);
2237}/*!
2238 * node-mu
2239 * node.js minimalistic microservices framework on top of Express.js
2240 *
2241 * Copyright(c) 2018 IT Resources s.r.l.
2242 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2243 *
2244 * Permission is hereby granted, free of charge, to any person obtaining a copy
2245 * of this software and associated documentation files (the "Software"), to deal
2246 * in the Software without restriction, including without limitation the rights
2247 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2248 * copies of the Software, and to permit persons to whom the Software is
2249 * furnished to do so, subject to the following conditions:
2250 *
2251 * The above copyright notice and this permission notice shall be included in all
2252 * copies or substantial portions of the Software.
2253 *
2254 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2255 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2256 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2257 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2258 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2259 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2260 * SOFTWARE.
2261 *
2262 * See node-mu license text even in LICENSE file.
2263 *
2264 * lib/node-mu/providers/api/request-logger-transport.js
2265 */
2266
2267'use strict';
2268
2269const path = require('path');
2270const winston = require('winston');
2271require('winston-daily-rotate-file');
2272const fs = require('fs');
2273const config = require('config');
2274const {serviceInfo} = require('../../utils');
2275const {LoggerWrapper} = require('../../logger');
2276
2277const REQUESTS_LOGGER_TRANSPORTS = 'requests';
2278const ERRORS_LOGGER_TRANSPORTS = 'errors';
2279
2280/** Initialize express-winston to log Api http requests. */
2281class RequestLoggerTransport {
2282 constructor() {
2283 this._configuration = config.get('log');
2284 this._logger = new LoggerWrapper(this.constructor.name);
2285
2286 this._requestsLoggerTransports = this._configure(REQUESTS_LOGGER_TRANSPORTS);
2287 this._logger.debug('requests transports initialized');
2288
2289 this._errorsLoggerTransports = this._configure(ERRORS_LOGGER_TRANSPORTS);
2290 this._logger.debug('errors transports initialized');
2291 }
2292
2293 /**
2294 * Returns the winston logger transport for requests.
2295 * @return {object}
2296 */
2297 get requestsLoggerTransports() {
2298 return this._requestsLoggerTransports;
2299 }
2300
2301 /**
2302 * Returns the winston logger transport for errors.
2303 * @return {object}
2304 */
2305 get errorLoggerTransports() {
2306 return this._errorsLoggerTransports;
2307 }
2308
2309 /**
2310 * Switch to configure a winston transport.
2311 * @param {string} type - The logging reason ('requests' or 'errors').
2312 */
2313 _configure(type) {
2314 const fullPath = path.join(process.cwd(), this._configuration.path);
2315 if (!fs.existsSync(fullPath)) {
2316 fs.mkdirSync(fullPath);
2317 }
2318
2319 switch (type) {
2320 case REQUESTS_LOGGER_TRANSPORTS:
2321 const requestsLogFile = `${serviceInfo.name}-requests`;
2322 return this._configureTransports(fullPath, requestsLogFile, this._configuration.requests.console);
2323 break;
2324 case ERRORS_LOGGER_TRANSPORTS:
2325 const errorsLogFile = `${serviceInfo.name}-errors`;
2326 return this._configureTransports(fullPath, errorsLogFile, this._configuration.errors.console);
2327 break;
2328 default:
2329 logger.error('Unexpected express winston transport configuration type');
2330 }
2331 }
2332
2333 /**
2334 * Configure a winston transport.
2335 * @param {string} logFullPath - The log file full path.
2336 * @param {string} logFile - The log file name.
2337 * @param {boolean} logToConsole - wheter or not to log on console.
2338 */
2339 _configureTransports(logFullPath, logFile, logToConsole) {
2340 const fullname = path.join(logFullPath, logFile);
2341 const fileTransport = new (winston.transports.DailyRotateFile)({
2342 filename: fullname + '-%DATE%.log',
2343 datePattern: 'DD-MM-YYYY',
2344 zippedArchive: true,
2345 maxSize: '20m',
2346 maxFiles: '14d',
2347 level: this._configuration.level,
2348 json: false
2349 });
2350
2351 const transports = [fileTransport];
2352 if (logToConsole) {
2353 transports.push(new winston.transports.Console({json: false, colorize: true, level: this._configuration.level}));
2354 }
2355
2356 return {transports: transports, expressFormat: true};
2357 }
2358}
2359
2360module.exports = RequestLoggerTransport;
2361/*!
2362 * node-mu
2363 * node.js minimalistic microservices framework on top of Express.js
2364 *
2365 * Copyright(c) 2018 IT Resources s.r.l.
2366 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2367 *
2368 * Permission is hereby granted, free of charge, to any person obtaining a copy
2369 * of this software and associated documentation files (the "Software"), to deal
2370 * in the Software without restriction, including without limitation the rights
2371 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2372 * copies of the Software, and to permit persons to whom the Software is
2373 * furnished to do so, subject to the following conditions:
2374 *
2375 * The above copyright notice and this permission notice shall be included in all
2376 * copies or substantial portions of the Software.
2377 *
2378 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2379 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2380 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2381 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2382 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2383 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2384 * SOFTWARE.
2385 *
2386 * See node-mu license text even in LICENSE file.
2387 *
2388 * lib/node-mu/providers/api/router.js
2389 */
2390
2391'use strict';
2392
2393const express = require('express');
2394const Provider = require('../provider');
2395
2396class Router extends Provider {
2397 constructor() {
2398 super('component:provider:router');
2399 this._router = express.Router();
2400 }
2401
2402 /**
2403 * Returns this Router routes.
2404 * @return {express.Router} _router - This router.
2405 */
2406 get routes() {
2407 return this._router;
2408 }
2409
2410 /**
2411 * Adds a route to the Router.
2412 * @param {string} path - The route path.
2413 * @param {Route} route - The route object
2414 */
2415 addRoute(path, route) {
2416 this._router.use(path, route);
2417 }
2418}
2419
2420/** The Router base class for the API. */
2421module.exports = Router;/*!
2422 * node-mu
2423 * node.js minimalistic microservices framework on top of Express.js
2424 *
2425 * Copyright(c) 2018 IT Resources s.r.l.
2426 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2427 *
2428 * Permission is hereby granted, free of charge, to any person obtaining a copy
2429 * of this software and associated documentation files (the "Software"), to deal
2430 * in the Software without restriction, including without limitation the rights
2431 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2432 * copies of the Software, and to permit persons to whom the Software is
2433 * furnished to do so, subject to the following conditions:
2434 *
2435 * The above copyright notice and this permission notice shall be included in all
2436 * copies or substantial portions of the Software.
2437 *
2438 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2439 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2440 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2441 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2442 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2443 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2444 * SOFTWARE.
2445 *
2446 * See node-mu license text even in LICENSE file.
2447 *
2448 * lib/node-mu/providers/api/routes-register.js
2449 */
2450
2451'use strict';
2452
2453let RoutesIds = module.exports = {
2454 ids: [],
2455 register: (id) => {
2456 RoutesIds.ids.push(id);
2457 },
2458 remove: (id) => {
2459 const idx = RoutesIds.ids.indexOf(id);
2460 if (idx) RoutesIds.ids.splice(idx, 1);
2461 }
2462};/*!
2463 * node-mu
2464 * node.js minimalistic microservices framework on top of Express.js
2465 *
2466 * Copyright(c) 2018 IT Resources s.r.l.
2467 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2468 *
2469 * Permission is hereby granted, free of charge, to any person obtaining a copy
2470 * of this software and associated documentation files (the "Software"), to deal
2471 * in the Software without restriction, including without limitation the rights
2472 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2473 * copies of the Software, and to permit persons to whom the Software is
2474 * furnished to do so, subject to the following conditions:
2475 *
2476 * The above copyright notice and this permission notice shall be included in all
2477 * copies or substantial portions of the Software.
2478 *
2479 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2480 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2481 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2482 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2483 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2484 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2485 * SOFTWARE.
2486 *
2487 * See node-mu license text even in LICENSE file.
2488 *
2489 * lib/node-mu/providers/db/db-connection-manager.provider.js
2490 */
2491
2492'use strict';
2493
2494const {provider} = require('../../ioc');
2495const Provider = require('../provider');
2496const config = require('config');
2497const Knex = require('knex');
2498const {Model} = require('objection');
2499
2500module.exports =
2501 provider(
2502 class DbConnectionManager extends Provider {
2503 constructor() {
2504 super();
2505 }
2506
2507 init(model) {
2508 this._model = model;
2509 }
2510
2511 async $start() {
2512 try {
2513 this._knexConfig = config.get('db');
2514 this._logger.debug(`configuration: ${JSON.stringify(this._knexConfig)}`);
2515
2516 this.init(Model);
2517
2518 const knexConnection = await this.connect();
2519 this._model.knex(knexConnection);
2520 } catch (err) {
2521 throw err;
2522 }
2523 }
2524
2525 async $stop() {
2526 }
2527
2528 async connect() {
2529 this._logger.debug('configuring database connection');
2530 return new Promise((resolve, reject) => {
2531 this._knex = Knex(this._knexConfig);
2532 this._knex.raw('select 1 from dual').then(() => {
2533 this._logger.info('database connection established');
2534 resolve(this._knex);
2535 }).catch((err) => {
2536 this._logger.error('error connecting to database');
2537 reject(err);
2538 });
2539 });
2540 }
2541
2542 get knex() {
2543 this._logger.debug('returning Knex instance');
2544 return this._knex;
2545 }
2546
2547 get $healthId() {
2548 return 'db';
2549 }
2550
2551 $isCheckableForHealth() {
2552 return true;
2553 }
2554
2555 async $health() {
2556 return new Promise((resolve, reject) => {
2557 this._logger.debug('***** db health');
2558 this._knex.raw('select 1 from dual').then(() => {
2559 this._logger.debug('****database connection established');
2560 resolve({status: 'UP'});
2561 }).catch((err) => {
2562 this._logger.error('****error connecting to database');
2563 reject({status: 'DOWN', message: err.stack});
2564 });
2565 });
2566 }
2567
2568 get model() {
2569 return this._model;
2570 }
2571 }
2572 );
2573/*!
2574 * node-mu
2575 * node.js minimalistic microservices framework on top of Express.js
2576 *
2577 * Copyright(c) 2018 IT Resources s.r.l.
2578 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2579 *
2580 * Permission is hereby granted, free of charge, to any person obtaining a copy
2581 * of this software and associated documentation files (the "Software"), to deal
2582 * in the Software without restriction, including without limitation the rights
2583 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2584 * copies of the Software, and to permit persons to whom the Software is
2585 * furnished to do so, subject to the following conditions:
2586 *
2587 * The above copyright notice and this permission notice shall be included in all
2588 * copies or substantial portions of the Software.
2589 *
2590 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2591 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2592 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2593 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2594 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2595 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2596 * SOFTWARE.
2597 *
2598 * See node-mu license text even in LICENSE file.
2599 *
2600 * lib/node-mu/providers/db/index.js
2601 */
2602
2603'use strict';
2604
2605module.exports = require('./db-connection-manager.provider');/*!
2606 * node-mu
2607 * node.js minimalistic microservices framework on top of Express.js
2608 *
2609 * Copyright(c) 2018 IT Resources s.r.l.
2610 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2611 *
2612 * Permission is hereby granted, free of charge, to any person obtaining a copy
2613 * of this software and associated documentation files (the "Software"), to deal
2614 * in the Software without restriction, including without limitation the rights
2615 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2616 * copies of the Software, and to permit persons to whom the Software is
2617 * furnished to do so, subject to the following conditions:
2618 *
2619 * The above copyright notice and this permission notice shall be included in all
2620 * copies or substantial portions of the Software.
2621 *
2622 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2623 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2624 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2625 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2626 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2627 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2628 * SOFTWARE.
2629 *
2630 * See node-mu license text even in LICENSE file.
2631 *
2632 * lib/node-mu/providers/emitter/events-emitter.provider.js
2633 */
2634
2635'use strict';
2636
2637const {inject, provider} = require('../../ioc');
2638const Provider = require('../provider');
2639const Hertzy = require('hertzy');
2640const config = require('config');
2641const {AmqpPublisherFactory} = require('../amqp');
2642
2643const apiEvents = Hertzy.tune('api-events');
2644
2645/** The application Events Emitter. For each of the registered events can publish messeages on AMQP exchanges. */
2646module.exports =
2647 inject(
2648 [AmqpPublisherFactory],
2649 provider(
2650 class EventsEmitterProvider extends Provider {
2651 constructor(amqpPublisherFactory) {
2652 super();
2653 this._amqpPublisherFactory = amqpPublisherFactory;
2654 this._eventsMap = new Map();
2655 }
2656
2657 async $start() {
2658 try {
2659 const eventsMapFile = `${process.cwd()}/${config.get('events.mapFile')}`;
2660 this._eventsConfigMap = require(eventsMapFile).events;
2661
2662 this.registerEvents();
2663 } catch (err) {
2664 throw err;
2665 }
2666 }
2667
2668
2669 async $stop() {
2670 // nothing to stop here. AMQP stopping stuffs are in charge of the AmqpConnectionManager Provider
2671 }
2672
2673 /** Register events with their relative AMQP Publisher into the <evt;publisher> Map. */
2674 registerEvents() {
2675 for (const evt of this._eventsConfigMap) {
2676 // initialize Publisher and add to the <evt;publisher> map
2677 const amqpPublisher = this._amqpPublisherFactory().newPublisher(evt.amqpConfig.exchange);
2678 //const amqpPublisher = new AmqpPublisher(evt.amqpConfig.exchange);
2679 this._eventsMap.set(evt.name, amqpPublisher);
2680
2681 this._logger.debug(`registering event ${evt.name} on events-channel "api-events"`);
2682 // evt callback to publish evt on AMQP queue
2683 apiEvents.on(evt.name, (data) => {
2684 this._logger.debug(`got event ${evt.name} with data ${JSON.stringify(data)}`);
2685
2686 try {
2687 const amqpPublisher = this._eventsMap.get(evt.name);
2688 amqpPublisher.publish(data);
2689 this._logger.info(`${evt.name} event published on AMQP exchange`);
2690 } catch (err) {
2691 this._logger.error(`error sending event ${evt.name} - ${JSON.stringify(data)} - error: ${err}`);
2692 }
2693
2694 });
2695
2696 this._logger.info(`event: ${JSON.stringify(evt)} registered`);
2697 }
2698 }
2699
2700 /**
2701 * Returns the <event;publisher> Map.
2702 * @return {Map} _eventsMap - The <event;publisher> Map.
2703 */
2704 get eventsMap() {
2705 return this._eventsMap;
2706 }
2707
2708 /**
2709 * Returns the events configuration.
2710 * @return {object} _eventsConfigMap - The events configuration data structure.
2711 */
2712 get eventsConfigMap() {
2713 return this._eventsConfigMap;
2714 }
2715
2716 get $healthId() {
2717 return 'events-emitter';
2718 }
2719 }
2720 )
2721 );
2722/*!
2723 * node-mu
2724 * node.js minimalistic microservices framework on top of Express.js
2725 *
2726 * Copyright(c) 2018 IT Resources s.r.l.
2727 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2728 *
2729 * Permission is hereby granted, free of charge, to any person obtaining a copy
2730 * of this software and associated documentation files (the "Software"), to deal
2731 * in the Software without restriction, including without limitation the rights
2732 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2733 * copies of the Software, and to permit persons to whom the Software is
2734 * furnished to do so, subject to the following conditions:
2735 *
2736 * The above copyright notice and this permission notice shall be included in all
2737 * copies or substantial portions of the Software.
2738 *
2739 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2740 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2741 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2742 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2743 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2744 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2745 * SOFTWARE.
2746 *
2747 * See node-mu license text even in LICENSE file.
2748 *
2749 * lib/node-mu/providers/emitter/index.js
2750 */
2751
2752'use strict';
2753
2754module.exports = require('./events-emitter.provider');/*!
2755 * node-mu
2756 * node.js minimalistic microservices framework on top of Express.js
2757 *
2758 * Copyright(c) 2018 IT Resources s.r.l.
2759 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2760 *
2761 * Permission is hereby granted, free of charge, to any person obtaining a copy
2762 * of this software and associated documentation files (the "Software"), to deal
2763 * in the Software without restriction, including without limitation the rights
2764 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2765 * copies of the Software, and to permit persons to whom the Software is
2766 * furnished to do so, subject to the following conditions:
2767 *
2768 * The above copyright notice and this permission notice shall be included in all
2769 * copies or substantial portions of the Software.
2770 *
2771 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2772 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2773 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2774 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2775 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2776 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2777 * SOFTWARE.
2778 *
2779 * See node-mu license text even in LICENSE file.
2780 *
2781 * lib/node-mu/providers/health/index.js
2782 */
2783
2784'use strict';
2785
2786const {provider, container} = require('../../ioc');
2787const Provider = require('../provider');
2788const ProvidersRegister = require('./providers-register');
2789const autoBind = require('auto-bind');
2790const dayJs = require('dayjs');
2791
2792module.exports =
2793 provider(
2794 class Health extends Provider {
2795 constructor() {
2796 super();
2797 autoBind(this);
2798 }
2799
2800 async $start(providersIds) {
2801 if (providersIds) {
2802 ProvidersRegister.registerAll(providersIds);
2803 }
2804
2805 this._logger.info('providers list set');
2806 }
2807
2808 async $stop() {
2809 this._logger.debug('IMPLEMENT Health Provider stop functionality');
2810 }
2811
2812 async health() {
2813 return new Promise(async (resolve) => {
2814 this._logger.info('composing health info');
2815 const timestamp = new dayJs();
2816 const uptime = process.uptime();
2817 let healthResponse = {
2818 status: 'UP',
2819 starttime: timestamp.subtract(uptime, 'second'),
2820 uptime: uptime,
2821 timestamp: timestamp
2822 };
2823
2824 for (let providerIocId of ProvidersRegister.ids) {
2825 try {
2826 const provider = container.get(providerIocId);
2827 if (provider.$isCheckableForHealth()) {
2828 this._logger.debug(`getting health info for ${providerIocId} Provider`);
2829 let healthMsg = {};
2830 try {
2831 healthMsg = await provider.$health();
2832 } catch (err) {
2833 healthMsg = err;
2834 }
2835
2836 healthResponse[provider.$healthId] = healthMsg;
2837 this._logger.debug(`${providerIocId} Provider health response: ${JSON.stringify(healthMsg)}`);
2838 } else {
2839 this._logger.debug(`${providerIocId} Provider has not been set has health checkable`);
2840 }
2841 } catch (err) {
2842 this._logger.warn(`unable to get health info for ${providerIocId} Provider`);
2843 }
2844 }
2845
2846 this._logger.info(`health info: ${JSON.stringify(healthResponse)}`);
2847 resolve(healthResponse);
2848 });
2849
2850 }
2851 }
2852 );
2853
2854
2855/*!
2856 * node-mu
2857 * node.js minimalistic microservices framework on top of Express.js
2858 *
2859 * Copyright(c) 2018 IT Resources s.r.l.
2860 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2861 *
2862 * Permission is hereby granted, free of charge, to any person obtaining a copy
2863 * of this software and associated documentation files (the "Software"), to deal
2864 * in the Software without restriction, including without limitation the rights
2865 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2866 * copies of the Software, and to permit persons to whom the Software is
2867 * furnished to do so, subject to the following conditions:
2868 *
2869 * The above copyright notice and this permission notice shall be included in all
2870 * copies or substantial portions of the Software.
2871 *
2872 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2873 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2874 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2875 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2876 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2877 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2878 * SOFTWARE.
2879 *
2880 * See node-mu license text even in LICENSE file.
2881 *
2882 * lib/node-mu/providers/health/index.js
2883 */
2884
2885'use strict';
2886
2887module.exports = require('./health.provider');/*!
2888 * node-mu
2889 * node.js minimalistic microservices framework on top of Express.js
2890 *
2891 * Copyright(c) 2018 IT Resources s.r.l.
2892 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2893 *
2894 * Permission is hereby granted, free of charge, to any person obtaining a copy
2895 * of this software and associated documentation files (the "Software"), to deal
2896 * in the Software without restriction, including without limitation the rights
2897 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2898 * copies of the Software, and to permit persons to whom the Software is
2899 * furnished to do so, subject to the following conditions:
2900 *
2901 * The above copyright notice and this permission notice shall be included in all
2902 * copies or substantial portions of the Software.
2903 *
2904 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2905 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2906 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2907 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2908 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2909 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2910 * SOFTWARE.
2911 *
2912 * See node-mu license text even in LICENSE file.
2913 *
2914 * lib/node-mu/providers/health/providers-register.js
2915 */
2916
2917'use strict';
2918
2919let ProvidersIds = module.exports = {
2920 ids: [],
2921 register: (id) => {
2922 ProvidersIds.ids.push(id);
2923 },
2924 registerAll: (providerIds) => {
2925 ProvidersIds.concat(ProvidersIds);
2926 },
2927 remove: (id) => {
2928 const idx = ProvidersIds.ids.indexOf(id);
2929 if (idx) ProvidersIds.ids.splice(idx, 1);
2930 }
2931};/*!
2932 * node-mu
2933 * node.js minimalistic microservices framework on top of Express.js
2934 *
2935 * Copyright(c) 2018 IT Resources s.r.l.
2936 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2937 *
2938 * Permission is hereby granted, free of charge, to any person obtaining a copy
2939 * of this software and associated documentation files (the "Software"), to deal
2940 * in the Software without restriction, including without limitation the rights
2941 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2942 * copies of the Software, and to permit persons to whom the Software is
2943 * furnished to do so, subject to the following conditions:
2944 *
2945 * The above copyright notice and this permission notice shall be included in all
2946 * copies or substantial portions of the Software.
2947 *
2948 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2949 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2950 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2951 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2952 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2953 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2954 * SOFTWARE.
2955 *
2956 * See node-mu license text even in LICENSE file.
2957 *
2958 * lib/node-mu/providers/index.js
2959 */
2960
2961'use strict';
2962
2963module.exports = {
2964 Provider: require('./provider'),
2965 DbConnectionManager: require('./db'),
2966 Api: require('./api').Api,
2967 Router: require('./api').Router,
2968 AuthMiddleware: require('./api').AuthMiddleware,
2969 AmqpConnectionManager: require('./amqp').AmqpConnectionManager,
2970 AmqpPublisher: require('./amqp').AmqpPublisher,
2971 AmqpPublisherFactory: require('./amqp').AmqpPublisherFactory,
2972 EventsEmitter: require('./emitter'),
2973 Health: require('./health'),
2974 Management: require('./management')
2975};/*!
2976 * node-mu
2977 * node.js minimalistic microservices framework on top of Express.js
2978 *
2979 * Copyright(c) 2018 IT Resources s.r.l.
2980 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
2981 *
2982 * Permission is hereby granted, free of charge, to any person obtaining a copy
2983 * of this software and associated documentation files (the "Software"), to deal
2984 * in the Software without restriction, including without limitation the rights
2985 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2986 * copies of the Software, and to permit persons to whom the Software is
2987 * furnished to do so, subject to the following conditions:
2988 *
2989 * The above copyright notice and this permission notice shall be included in all
2990 * copies or substantial portions of the Software.
2991 *
2992 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2993 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2994 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2995 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2996 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2997 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2998 * SOFTWARE.
2999 *
3000 * See node-mu license text even in LICENSE file.
3001 *
3002 * lib/node-mu/providers/management/index.js
3003 */
3004
3005'use strict';
3006
3007/** @module node-mu/management */
3008module.exports = require('./management.provider');/*!
3009 * node-mu
3010 * node.js minimalistic microservices framework on top of Express.js
3011 *
3012 * Copyright(c) 2018 IT Resources s.r.l.
3013 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3014 *
3015 * Permission is hereby granted, free of charge, to any person obtaining a copy
3016 * of this software and associated documentation files (the "Software"), to deal
3017 * in the Software without restriction, including without limitation the rights
3018 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3019 * copies of the Software, and to permit persons to whom the Software is
3020 * furnished to do so, subject to the following conditions:
3021 *
3022 * The above copyright notice and this permission notice shall be included in all
3023 * copies or substantial portions of the Software.
3024 *
3025 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3026 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3027 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3028 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3029 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3030 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3031 * SOFTWARE.
3032 *
3033 * See node-mu license text even in LICENSE file.
3034 *
3035 * lib/node-mu/providers/management/management.provider.js
3036 */
3037
3038'use strict';
3039
3040const {provider} = require('../../ioc');
3041const express = require('express');
3042const Router = require('../api/router');
3043const http = require('http');
3044const bodyParser = require('body-parser');
3045const compression = require('compression');
3046const methodOverride = require('method-override');
3047const helmet = require('helmet');
3048const cors = require('cors');
3049const ignoreFavicon = require('../api/middlewares/ignore-favicon');
3050const errorMiddleware = require('../api/middlewares/error');
3051const enableDestroy = require('server-destroy');
3052const expressWinston = require('express-winston');
3053const RequestLoggerTransport = require('../api/request-logger-transport');
3054const config = require('config');
3055const {fullInfo} = require('../../utils').serviceInfo;
3056const ioc = require('../../ioc').container;
3057const os = require('os');
3058
3059module.exports =
3060 provider(
3061 class Management extends Router {
3062 constructor() {
3063 super();
3064 this._mgmtConfig = config.get('management');
3065 this._mgmtApp = express();
3066
3067 this._mgmtPath = this._mgmtConfig.endpoint.baseRoutingPath || '/management';
3068 this._configureApp();
3069
3070 this._logger.info('initializing Management server');
3071 this._logger.info(`routing with basePath ${this._mgmtPath}`);
3072 this._mgmtApp.use(this._mgmtPath, this.routes);
3073 }
3074
3075 async $start() {
3076 return new Promise((resolve, reject) => {
3077 this._logger.debug('starting Management server');
3078 this._server = http.createServer(this._mgmtApp);
3079 this._server.listen(this._mgmtConfig.endpoint.port, (err) => {
3080 if (err) {
3081 return reject(err);
3082 }
3083 this._logger.info(`Management server listening on http://${this._server.address().address}:${this._server.address().port}`);
3084 return resolve();
3085 });
3086
3087 /* Hack to close all pending connections: https://github.com/isaacs/server-destroy */
3088 enableDestroy(this._server);
3089 });
3090 }
3091
3092 /** Stops the Management Http server. */
3093 async $stop() {
3094 return new Promise((resolve, reject) => {
3095 this._logger.info('gracefully shutting down the Management server');
3096 if (this._server) {
3097 this._server.destroy(() => {
3098 this._logger.info('Management server destroyed');
3099 return resolve(true);
3100 });
3101 } else {
3102 this._logger.warn('[Management] Management server destroyed (it was null!)');
3103 return resolve(true);
3104 }
3105 });
3106 }
3107
3108 /**
3109 * Configure the Express app.
3110 * @private
3111 */
3112 _configureApp() {
3113 this._logger.debug('configuring Management express app');
3114
3115 this._requestLoggerTransport = new RequestLoggerTransport();
3116 this._mgmtApp.use(expressWinston.logger(this._requestLoggerTransport.requestsLoggerTransports));
3117
3118 this._mgmtApp.use(bodyParser.json());
3119 this._mgmtApp.use(bodyParser.urlencoded({extended: true}));
3120 this._mgmtApp.use(compression());
3121 this._mgmtApp.use(methodOverride());
3122 this._mgmtApp.use(helmet());
3123 this._mgmtApp.use(cors());
3124 this._mgmtApp.use(ignoreFavicon);
3125
3126 // TODO: add the ability to configure other Management endpoints
3127
3128 // service info endpoint
3129 this.addRoute('/info', (req, res) => {
3130 res.json(fullInfo());
3131 });
3132
3133 // service health endpoint
3134 this.addRoute('/health', async (req, res) => {
3135 try {
3136 const healthService = ioc.get('Health');
3137 const health = await healthService.health();
3138 return res.json(health);
3139 } catch (err) {
3140 throw err;
3141 }
3142 });
3143 }
3144
3145 get $healthId() {
3146 return 'management';
3147 }
3148 }
3149 );
3150/*!
3151 * node-mu
3152 * node.js minimalistic microservices framework on top of Express.js
3153 *
3154 * Copyright(c) 2018 IT Resources s.r.l.
3155 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3156 *
3157 * Permission is hereby granted, free of charge, to any person obtaining a copy
3158 * of this software and associated documentation files (the "Software"), to deal
3159 * in the Software without restriction, including without limitation the rights
3160 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3161 * copies of the Software, and to permit persons to whom the Software is
3162 * furnished to do so, subject to the following conditions:
3163 *
3164 * The above copyright notice and this permission notice shall be included in all
3165 * copies or substantial portions of the Software.
3166 *
3167 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3168 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3169 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3170 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3171 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3172 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3173 * SOFTWARE.
3174 *
3175 * See node-mu license text even in LICENSE file.
3176 *
3177 * lib/node-mu/providers/provider.js
3178 */
3179
3180'use strict';
3181
3182const {Component} = require('../components');
3183
3184class Provider extends Component {
3185 constructor(ctype = 'component:provider') {
3186 super(ctype);
3187 }
3188
3189 async $start(options) {
3190 throw Error(`${this.constructor.name}.$start() not implemented. Unable to mount the ${this.constructor.name} provider`);
3191 }
3192
3193 async $stop() {
3194 this._logger.warn(`${this.constructor.name} provider stoppped`);
3195 }
3196
3197 /**
3198 * Default health id which will compare in the json health response.
3199 *
3200 * NOTE: Override this in your provider if you want to use a different id for your provider.
3201 * @returns {*}
3202 */
3203 get $healthId() {
3204 return this.constructor.name;
3205 }
3206
3207 $isCheckableForHealth() {
3208 return false;
3209 }
3210
3211 /**
3212 * Default health method for a Provider.
3213 *
3214 * NOTE: Ovverride this in your provider in order to do real health checks.
3215 *
3216 * @returns {Promise<{status: string}>}
3217 */
3218 async $health() {
3219 return {
3220 status: "UP"
3221 }
3222 }
3223}
3224
3225module.exports = Provider;/*!
3226 * node-mu
3227 * node.js minimalistic microservices framework on top of Express.js
3228 *
3229 * Copyright(c) 2018 IT Resources s.r.l.
3230 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3231 *
3232 * Permission is hereby granted, free of charge, to any person obtaining a copy
3233 * of this software and associated documentation files (the "Software"), to deal
3234 * in the Software without restriction, including without limitation the rights
3235 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3236 * copies of the Software, and to permit persons to whom the Software is
3237 * furnished to do so, subject to the following conditions:
3238 *
3239 * The above copyright notice and this permission notice shall be included in all
3240 * copies or substantial portions of the Software.
3241 *
3242 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3243 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3244 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3245 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3246 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3247 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3248 * SOFTWARE.
3249 *
3250 * See node-mu license text even in LICENSE file.
3251 *
3252 * lib/node-mu/utils/api-error.js
3253 */
3254
3255'use strict';
3256
3257const httpStatus = require('http-status');
3258
3259/** An extendable base class for custom errors. It extends default Error. */
3260class ExtendableError extends Error {
3261 constructor({
3262 message, errors, status, isPublic, stack,
3263 }) {
3264 super(message);
3265 this.name = this.constructor.name;
3266 this.message = message;
3267 this.errors = errors;
3268 this.status = status;
3269 this.isPublic = isPublic;
3270 this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
3271 this.stack = stack;
3272 // Error.captureStackTrace(this, this.constructor.name);
3273 }
3274}
3275
3276/** Custom error returned by API to the client. */
3277class APIError extends ExtendableError {
3278 constructor({
3279 message,
3280 errors,
3281 stack,
3282 status = httpStatus.INTERNAL_SERVER_ERROR,
3283 isPublic = false,
3284 }) {
3285 super({
3286 message, errors, status, isPublic, stack,
3287 });
3288 }
3289}
3290
3291/** @module node-mu/utils/api-error */
3292module.exports = APIError;/*!
3293 * node-mu
3294 * node.js minimalistic microservices framework on top of Express.js
3295 *
3296 * Copyright(c) 2018 IT Resources s.r.l.
3297 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3298 *
3299 * Permission is hereby granted, free of charge, to any person obtaining a copy
3300 * of this software and associated documentation files (the "Software"), to deal
3301 * in the Software without restriction, including without limitation the rights
3302 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3303 * copies of the Software, and to permit persons to whom the Software is
3304 * furnished to do so, subject to the following conditions:
3305 *
3306 * The above copyright notice and this permission notice shall be included in all
3307 * copies or substantial portions of the Software.
3308 *
3309 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3310 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3311 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3312 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3313 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3314 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3315 * SOFTWARE.
3316 *
3317 * See node-mu license text even in LICENSE file.
3318 *
3319 * lib/node-mu/utils/index.js
3320 */
3321
3322'use strict';
3323
3324/** @module node-mu/utils */
3325module.exports = {
3326 serviceInfo: require('./service-info'),
3327 APIError: require('./api-error'),
3328 generateKey: require('./key-generator'),
3329 responseUtils : require('./response-utils')
3330};
3331/*!
3332 * node-mu
3333 * node.js minimalistic microservices framework on top of Express.js
3334 *
3335 * Copyright(c) 2018 IT Resources s.r.l.
3336 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3337 *
3338 * Permission is hereby granted, free of charge, to any person obtaining a copy
3339 * of this software and associated documentation files (the "Software"), to deal
3340 * in the Software without restriction, including without limitation the rights
3341 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3342 * copies of the Software, and to permit persons to whom the Software is
3343 * furnished to do so, subject to the following conditions:
3344 *
3345 * The above copyright notice and this permission notice shall be included in all
3346 * copies or substantial portions of the Software.
3347 *
3348 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3349 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3350 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3351 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3352 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3353 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3354 * SOFTWARE.
3355 *
3356 * See node-mu license text even in LICENSE file.
3357 *
3358 * lib/node-mu/utils/key-generator.js
3359 */
3360
3361'use strict';
3362
3363/**
3364 * Generates a random key of the specified length (default = 20).
3365 * @param n - the length of the key to generate
3366 * @returns {string} - the generated key
3367 */
3368const keyGenerator = (n = 20) => {
3369 const add = 1;
3370 let max = 12 - add;
3371
3372 if (n > max) {
3373 return keyGenerator(max) + keyGenerator(n - max);
3374 }
3375
3376 max = Math.pow(10, n + add);
3377 const min = max / 10;
3378 const number = Math.floor(Math.random() * (max - min + 1)) + min;
3379
3380 return ("" + number).substring(add);
3381};
3382
3383module.exports = keyGenerator;/*!
3384 * node-mu
3385 * node.js minimalistic microservices framework on top of Express.js
3386 *
3387 * Copyright(c) 2018 IT Resources s.r.l.
3388 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3389 *
3390 * Permission is hereby granted, free of charge, to any person obtaining a copy
3391 * of this software and associated documentation files (the "Software"), to deal
3392 * in the Software without restriction, including without limitation the rights
3393 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3394 * copies of the Software, and to permit persons to whom the Software is
3395 * furnished to do so, subject to the following conditions:
3396 *
3397 * The above copyright notice and this permission notice shall be included in all
3398 * copies or substantial portions of the Software.
3399 *
3400 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3401 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3402 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3403 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3404 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3405 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3406 * SOFTWARE.
3407 *
3408 * See node-mu license text even in LICENSE file.
3409 *
3410 * lib/node-mu/utils/response-utils.js
3411 */
3412
3413'use strict';
3414
3415const httpStatus = require('http-status');
3416
3417// Response error Utils
3418
3419const badRequestError = (message) => {
3420 return errorDescription(httpStatus.BAD_REQUEST, true, message);
3421};
3422
3423const unauthorizedError = (message = 'Unauthorized: incorrect username or password.') => {
3424 return errorDescription(httpStatus.UNAUTHORIZED, true, message);
3425};
3426
3427const errorDescription = (status, isPublic, message) => {
3428 return {
3429 status: status,
3430 isPublic: isPublic,
3431 message: message
3432 }
3433};
3434
3435// Headers Utils
3436
3437const getPagingParams = (req) => {
3438 const page = req.query.page || 0;
3439 const size = req.query.size || 0;
3440 const sort = req.query.sort;
3441 let sortField = 'id';
3442 let sortDirection = 'asc';
3443 if (sort && sort.indexOf(',') > -1) {
3444 const splitted = sort.split(',');
3445 sortField = splitted[0].trim();
3446 sortDirection = splitted[1].trim();
3447 }
3448
3449 return {
3450 page,
3451 size,
3452 sortField,
3453 sortDirection
3454 }
3455};
3456
3457const setPagingHeaders = (res, data, page, size, baseUrl) => {
3458 const totalCount = Number.parseInt(data.total || data.length, 10);
3459 res.set('X-Total-Count', data.total || data.length);
3460
3461 const _page = Number.parseInt(page, 10);
3462 const _size = Number.parseInt(size, 10);
3463
3464 let totalPages = Math.ceil(totalCount / size);
3465
3466 let link = '';
3467 if ((page + 1) < totalPages) {
3468 link = `<${baseUrl}?page=${_page + 1}&size=${_size}>; rel="next",`;
3469 }
3470
3471 if (page > 0) {
3472 link += `<${baseUrl}?page=${_page - 1}&size=${_size}>; rel="prev",`;
3473 }
3474
3475 let lastPage = 0;
3476 if (totalPages > 0) {
3477 lastPage = totalPages - 1;
3478 }
3479
3480 link += `<${baseUrl}?page=${lastPage}&size=${_size}>; rel="last",`;
3481 link += `<${baseUrl}?page=0&size=${_size}>; rel="first"`;
3482 res.set('link', link);
3483};
3484
3485module.exports = {badRequestError, unauthorizedError, errorDescription, getPagingParams, setPagingHeaders};/*!
3486 * node-mu
3487 * node.js minimalistic microservices framework on top of Express.js
3488 *
3489 * Copyright(c) 2018 IT Resources s.r.l.
3490 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3491 *
3492 * Permission is hereby granted, free of charge, to any person obtaining a copy
3493 * of this software and associated documentation files (the "Software"), to deal
3494 * in the Software without restriction, including without limitation the rights
3495 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3496 * copies of the Software, and to permit persons to whom the Software is
3497 * furnished to do so, subject to the following conditions:
3498 *
3499 * The above copyright notice and this permission notice shall be included in all
3500 * copies or substantial portions of the Software.
3501 *
3502 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3503 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3504 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3505 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3506 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3507 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3508 * SOFTWARE.
3509 *
3510 * See node-mu license text even in LICENSE file.
3511 *
3512 * lib/node-mu/utils/service-info.js
3513 */
3514
3515'use strict';
3516
3517const config = require('config');
3518const os = require('os');
3519
3520const env = process.env.NODE_ENV || 'development';
3521
3522const version = `${config.get('service.version.major')}.${config.get('service.version.minor')}.${config.get('service.version.status')}`;
3523const name = `${config.get('service.group')}-${config.get('service.name')}-${env.substring(0, 3)}_${version}`;
3524const serviceName = config.get('service.name');
3525const serviceGroup = config.get('service.group');
3526
3527const fullInfo = () => {
3528 const iocContainer = require('../ioc').container;
3529 const instanceId = iocContainer.get(APPLICATION_TYPE).id;
3530 const instanceName = `${instanceId}/${name}@${os.hostname()}`;
3531 return {serviceName, serviceGroup, name, instanceId, instanceName, version, env};
3532};
3533module.exports = {serviceName, serviceGroup, name, version, env, fullInfo};/*!
3534 * node-mu
3535 * node.js minimalistic microservices framework on top of Express.js
3536 *
3537 * Copyright(c) 2018 IT Resources s.r.l.
3538 * Copyright(c) 2018 Luca Stasio <joshuagame@gmail.com>
3539 *
3540 * Permission is hereby granted, free of charge, to any person obtaining a copy
3541 * of this software and associated documentation files (the "Software"), to deal
3542 * in the Software without restriction, including without limitation the rights
3543 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3544 * copies of the Software, and to permit persons to whom the Software is
3545 * furnished to do so, subject to the following conditions:
3546 *
3547 * The above copyright notice and this permission notice shall be included in all
3548 * copies or substantial portions of the Software.
3549 *
3550 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3551 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3552 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3553 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3554 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3555 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3556 * SOFTWARE.
3557 *
3558 * See node-mu license text even in LICENSE file.
3559 *
3560 * index.js
3561 */
3562
3563/*jslint node: true */
3564'use strict';
3565
3566const NodeMuLib = require('./lib');
3567module.exports = NodeMuLib;
\No newline at end of file