UNPKG

2.78 kBJavaScriptView Raw
1const { EventEmitter } = require('events');
2const Proto = require('uberproto');
3
4// Returns a hook that emits service events. Should always be
5// used as the very last hook in the chain
6const eventHook = exports.eventHook = function eventHook () {
7 return function (hook) {
8 const { app, service } = hook;
9 const eventName = hook.event === null ? hook.event : app.eventMappings[hook.method];
10 const isHookEvent = service._hookEvents && service._hookEvents.indexOf(eventName) !== -1;
11
12 // If this event is not being sent yet and we are not in an error hook
13 if (eventName && isHookEvent && hook.type !== 'error') {
14 const results = Array.isArray(hook.result) ? hook.result : [ hook.result ];
15
16 results.forEach(element => service.emit(eventName, element, hook));
17 }
18 };
19};
20
21// Mixin that turns a service into a Node event emitter
22const eventMixin = exports.eventMixin = function eventMixin (service) {
23 if (service._serviceEvents) {
24 return;
25 }
26
27 const app = this;
28 // Indicates if the service is already an event emitter
29 const isEmitter = typeof service.on === 'function' &&
30 typeof service.emit === 'function';
31
32 // If not, mix it in (the service is always an Uberproto object that has a .mixin)
33 if (typeof service.mixin === 'function' && !isEmitter) {
34 service.mixin(EventEmitter.prototype);
35 }
36
37 // Define non-enumerable properties of
38 Object.defineProperties(service, {
39 // A list of all events that this service sends
40 _serviceEvents: {
41 value: Array.isArray(service.events) ? service.events.slice() : []
42 },
43
44 // A list of events that should be handled through the event hooks
45 _hookEvents: {
46 value: []
47 }
48 });
49
50 // `app.eventMappings` has the mapping from method name to event name
51 Object.keys(app.eventMappings).forEach(method => {
52 const event = app.eventMappings[method];
53 const alreadyEmits = service._serviceEvents.indexOf(event) !== -1;
54
55 // Add events for known methods to _serviceEvents and _hookEvents
56 // if the service indicated it does not send it itself yet
57 if (typeof service[method] === 'function' && !alreadyEmits) {
58 service._serviceEvents.push(event);
59 service._hookEvents.push(event);
60 }
61 });
62};
63
64module.exports = function () {
65 return function (app) {
66 // Mappings from service method to event name
67 Object.assign(app, {
68 eventMappings: {
69 create: 'created',
70 update: 'updated',
71 remove: 'removed',
72 patch: 'patched'
73 }
74 });
75
76 // Register the event hook
77 // `finally` hooks always run last after `error` and `after` hooks
78 app.hooks({ finally: eventHook() });
79
80 // Make the app an event emitter
81 Proto.mixin(EventEmitter.prototype, app);
82
83 app.mixins.push(eventMixin);
84 };
85};