rascal 13.1.0 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.husky/pre-commit +1 -1
  2. package/.prettierrc.json +4 -0
  3. package/CHANGELOG.md +212 -1
  4. package/README.md +601 -382
  5. package/examples/advanced/cluster.js +8 -8
  6. package/examples/advanced/config.js +121 -123
  7. package/examples/advanced/handlers/deleteUser.js +16 -17
  8. package/examples/advanced/handlers/saveUser.js +32 -33
  9. package/examples/advanced/index.js +85 -80
  10. package/examples/busy-publisher/config.js +19 -22
  11. package/examples/busy-publisher/index.js +11 -12
  12. package/examples/default-exchange/config.js +13 -13
  13. package/examples/default-exchange/index.js +22 -18
  14. package/examples/mocha/config.js +13 -15
  15. package/examples/mocha/test.js +34 -35
  16. package/examples/promises/config.js +15 -17
  17. package/examples/promises/index.js +14 -12
  18. package/examples/simple/config.js +21 -23
  19. package/examples/simple/index.js +20 -22
  20. package/index.js +1 -1
  21. package/lib/amqp/Broker.js +105 -82
  22. package/lib/amqp/BrokerAsPromised.js +40 -28
  23. package/lib/amqp/Publication.js +15 -14
  24. package/lib/amqp/PublicationSession.js +6 -7
  25. package/lib/amqp/SubscriberError.js +159 -124
  26. package/lib/amqp/SubscriberSession.js +87 -68
  27. package/lib/amqp/SubscriberSessionAsPromised.js +1 -3
  28. package/lib/amqp/Subscription.js +25 -24
  29. package/lib/amqp/Vhost.js +92 -68
  30. package/lib/amqp/tasks/applyBindings.js +9 -6
  31. package/lib/amqp/tasks/assertExchanges.js +9 -5
  32. package/lib/amqp/tasks/assertQueues.js +9 -5
  33. package/lib/amqp/tasks/assertVhost.js +17 -13
  34. package/lib/amqp/tasks/bounceVhost.js +1 -1
  35. package/lib/amqp/tasks/checkExchanges.js +9 -5
  36. package/lib/amqp/tasks/checkQueues.js +9 -5
  37. package/lib/amqp/tasks/checkVhost.js +17 -13
  38. package/lib/amqp/tasks/closeChannel.js +0 -1
  39. package/lib/amqp/tasks/createChannel.js +0 -1
  40. package/lib/amqp/tasks/createConnection.js +20 -15
  41. package/lib/amqp/tasks/deleteExchanges.js +9 -5
  42. package/lib/amqp/tasks/deleteQueues.js +9 -5
  43. package/lib/amqp/tasks/deleteVhost.js +17 -13
  44. package/lib/amqp/tasks/forewarnVhost.js +1 -1
  45. package/lib/amqp/tasks/initCounters.js +12 -8
  46. package/lib/amqp/tasks/initPublications.js +13 -9
  47. package/lib/amqp/tasks/initShovels.js +9 -5
  48. package/lib/amqp/tasks/initSubscriptions.js +12 -8
  49. package/lib/amqp/tasks/initVhosts.js +16 -12
  50. package/lib/amqp/tasks/nukeVhost.js +1 -1
  51. package/lib/amqp/tasks/purgeQueues.js +9 -5
  52. package/lib/amqp/tasks/purgeVhost.js +1 -1
  53. package/lib/amqp/tasks/shutdownVhost.js +1 -1
  54. package/lib/backoff/exponential.js +1 -2
  55. package/lib/backoff/index.js +1 -1
  56. package/lib/backoff/linear.js +2 -4
  57. package/lib/config/baseline.js +12 -23
  58. package/lib/config/configure.js +89 -41
  59. package/lib/config/tests.js +30 -27
  60. package/lib/config/validate.js +22 -3
  61. package/lib/counters/inMemoryCluster.js +33 -22
  62. package/lib/counters/index.js +1 -1
  63. package/lib/counters/stub.js +2 -3
  64. package/lib/management/client.js +3 -9
  65. package/lib/utils/setTimeoutUnref.js +1 -1
  66. package/package.json +12 -4
@@ -28,7 +28,6 @@ module.exports = {
28
28
  inherits(Broker, EventEmitter);
29
29
 
30
30
  function Broker(config, components) {
31
-
32
31
  const self = this;
33
32
  let vhosts = {};
34
33
  let publications = {};
@@ -40,12 +39,16 @@ function Broker(config, components) {
40
39
  const forewarnVhost = tasks.forewarnVhost;
41
40
  const shutdownVhost = tasks.shutdownVhost;
42
41
  const bounceVhost = tasks.bounceVhost;
43
- const counters = _.defaults({}, components.counters, { stub, inMemory, inMemoryCluster });
42
+ const counters = _.defaults({}, components.counters, {
43
+ stub,
44
+ inMemory,
45
+ inMemoryCluster,
46
+ });
44
47
 
45
48
  this.config = config;
46
49
  this.promises = false;
47
50
 
48
- this._init = function(next) {
51
+ this._init = function (next) {
49
52
  debug('Initialising broker');
50
53
  vhosts = {};
51
54
  publications = {};
@@ -59,87 +62,107 @@ function Broker(config, components) {
59
62
  });
60
63
  };
61
64
 
62
- this.connect = function(name, next) {
65
+ this.connect = function (name, next) {
63
66
  if (!vhosts[name]) return next(new Error(format('Unknown vhost: %s', name)));
64
67
  vhosts[name].connect(next);
65
68
  };
66
69
 
67
- this.nuke = function(next) {
68
- debug('Nuking broker');
69
- self.unsubscribeAll((err) => {
70
- if (err) return next(err);
71
- async.eachSeries(_.values(vhosts), (vhost, callback) => {
72
- nukeVhost(config, { vhost }, callback);
73
- }, (err) => {
70
+ this.purge = function (next) {
71
+ debug('Purging all queues in all vhosts');
72
+ async.eachSeries(
73
+ _.values(vhosts),
74
+ (vhost, callback) => {
75
+ purgeVhost(config, { vhost }, callback);
76
+ },
77
+ (err) => {
74
78
  if (err) return next(err);
75
- vhosts = publications = subscriptions = {};
76
- clearInterval(self.keepActive);
77
- debug('Finished nuking broker');
79
+ debug('Finished purging all queues in all vhosts');
78
80
  next();
79
- });
80
- });
81
- };
82
-
83
- this.purge = function(next) {
84
- debug('Purging all queues in all vhosts');
85
- async.eachSeries(_.values(vhosts), (vhost, callback) => {
86
- purgeVhost(config, { vhost }, callback);
87
- }, (err) => {
88
- if (err) return next(err);
89
- debug('Finished purging all queues in all vhosts');
90
- next();
91
- });
81
+ }
82
+ );
92
83
  };
93
84
 
94
- this.shutdown = function(next) {
85
+ this.shutdown = function (next) {
95
86
  debug('Shutting down broker');
96
- async.eachSeries(_.values(vhosts), (vhost, callback) => {
97
- forewarnVhost(config, { vhost }, callback);
98
- }, (err) => {
99
- if (err) return next(err);
100
- self.unsubscribeAll((err) => {
87
+ async.eachSeries(
88
+ _.values(vhosts),
89
+ (vhost, callback) => {
90
+ forewarnVhost(config, { vhost }, callback);
91
+ },
92
+ (err) => {
101
93
  if (err) return next(err);
102
- async.eachSeries(_.values(vhosts), (vhost, callback) => {
103
- shutdownVhost(config, { vhost }, callback);
104
- }, (err) => {
94
+ self.unsubscribeAll((err) => {
95
+ if (err) self.emit('error', err);
96
+ async.eachSeries(
97
+ _.values(vhosts),
98
+ (vhost, callback) => {
99
+ shutdownVhost(config, { vhost }, callback);
100
+ },
101
+ (err) => {
102
+ if (err) return next(err);
103
+ clearInterval(self.keepActive);
104
+ debug('Finished shutting down broker');
105
+ next();
106
+ }
107
+ );
108
+ });
109
+ }
110
+ );
111
+ };
112
+
113
+ this.bounce = function (next) {
114
+ debug('Bouncing broker');
115
+ self.unsubscribeAll((err) => {
116
+ if (err) self.emit('error', err);
117
+ async.eachSeries(
118
+ _.values(vhosts),
119
+ (vhost, callback) => {
120
+ bounceVhost(config, { vhost }, callback);
121
+ },
122
+ (err) => {
105
123
  if (err) return next(err);
106
- clearInterval(self.keepActive);
107
- debug('Finished shutting down broker');
124
+ debug('Finished bouncing broker');
108
125
  next();
109
- });
110
- });
126
+ }
127
+ );
111
128
  });
112
129
  };
113
130
 
114
- this.bounce = function(next) {
115
- debug('Bouncing broker');
131
+ this.nuke = function (next) {
132
+ debug('Nuking broker');
116
133
  self.unsubscribeAll((err) => {
117
- if (err) return next(err);
118
- async.eachSeries(_.values(vhosts), (vhost, callback) => {
119
- bounceVhost(config, { vhost }, callback);
120
- }, (err) => {
121
- if (err) return next(err);
122
- debug('Finished bouncing broker');
123
- next();
124
- });
134
+ if (err) self.emit('error', err);
135
+ async.eachSeries(
136
+ _.values(vhosts),
137
+ (vhost, callback) => {
138
+ nukeVhost(config, { vhost }, callback);
139
+ },
140
+ (err) => {
141
+ if (err) return next(err);
142
+ vhosts = publications = subscriptions = {};
143
+ clearInterval(self.keepActive);
144
+ debug('Finished nuking broker');
145
+ next();
146
+ }
147
+ );
125
148
  });
126
149
  };
127
150
 
128
- this.publish = function(name, message, overrides, next) {
151
+ this.publish = function (name, message, overrides, next) {
129
152
  if (arguments.length === 3) return self.publish(name, message, {}, arguments[2]);
130
153
  if (_.isString(overrides)) return self.publish(name, message, { routingKey: overrides }, next);
131
154
  if (!publications[name]) return next(new Error(format('Unknown publication: %s', name)));
132
155
  publications[name].publish(message, overrides, next);
133
156
  };
134
157
 
135
- this.forward = function(name, message, overrides, next) {
158
+ this.forward = function (name, message, overrides, next) {
136
159
  if (arguments.length === 3) return self.forward(name, message, {}, arguments[2]);
137
160
  if (_.isString(overrides)) return self.forward(name, message, { routingKey: overrides }, next);
138
161
  if (!config.publications[name]) return next(new Error(format('Unknown publication: %s', name)));
139
162
  publications[name].forward(message, overrides, next);
140
163
  };
141
164
 
142
- this.subscribe = function(name, overrides, next) {
165
+ this.subscribe = function (name, overrides, next) {
143
166
  if (arguments.length === 2) return self.subscribe(name, {}, arguments[1]);
144
167
  if (!subscriptions[name]) return next(new Error(format('Unknown subscription: %s', name)));
145
168
  subscriptions[name].subscribe(overrides, (err, session) => {
@@ -149,54 +172,54 @@ function Broker(config, components) {
149
172
  });
150
173
  };
151
174
 
152
- this.subscribeAll = function(filter, next) {
153
- if (arguments.length === 1) return self.subscribeAll(() => { return true; }, arguments[0]);
175
+ this.subscribeAll = function (filter, next) {
176
+ if (arguments.length === 1)
177
+ return self.subscribeAll(() => {
178
+ return true;
179
+ }, arguments[0]);
154
180
  const filteredSubscriptions = _.chain(config.subscriptions).values().filter(filter).value();
155
- async.mapSeries(filteredSubscriptions, (subscriptionConfig, cb) => {
156
- self.subscribe(subscriptionConfig.name, (err, subscription) => {
157
- if (err) return cb(err);
158
- cb(null, subscription);
159
- });
160
- }, next);
181
+ async.mapSeries(
182
+ filteredSubscriptions,
183
+ (subscriptionConfig, cb) => {
184
+ self.subscribe(subscriptionConfig.name, (err, subscription) => {
185
+ if (err) return cb(err);
186
+ cb(null, subscription);
187
+ });
188
+ },
189
+ next
190
+ );
161
191
  };
162
192
 
163
- this.unsubscribeAll = function(next) {
164
- const timeout = getMaxDeferCloseChannelTimeout();
165
- async.eachSeries(sessions.slice(), (session, cb) => {
166
- sessions.shift();
167
- session.cancel(cb);
168
- }, (err) => {
169
- if (err) return next(err);
170
- debug('Waiting %dms for all subscriber channels to close', timeout);
171
- setTimeoutUnref(next, timeout);
172
- });
193
+ this.unsubscribeAll = function (next) {
194
+ async.each(
195
+ sessions.slice(),
196
+ (session, cb) => {
197
+ sessions.shift();
198
+ session.cancel(cb);
199
+ },
200
+ next
201
+ );
173
202
  };
174
203
 
175
- this.getConnections = function() {
204
+ this.getConnections = function () {
176
205
  return Object.keys(vhosts).map((name) => {
177
206
  return vhosts[name].getConnectionDetails();
178
207
  });
179
208
  };
180
209
 
181
- this.getFullyQualifiedName = this.qualify = function(vhost, name) {
210
+ this.getFullyQualifiedName = this.qualify = function (vhost, name) {
182
211
  return fqn.qualify(name, config.vhosts[vhost].namespace);
183
212
  };
184
213
 
185
- this._addVhost = function(vhost) {
214
+ this._addVhost = function (vhost) {
186
215
  vhosts[vhost.name] = vhost;
187
216
  };
188
217
 
189
- this._addPublication = function(publication) {
218
+ this._addPublication = function (publication) {
190
219
  publications[publication.name] = publication;
191
220
  };
192
221
 
193
- this._addSubscription = function(subscription) {
222
+ this._addSubscription = function (subscription) {
194
223
  subscriptions[subscription.name] = subscription;
195
224
  };
196
-
197
- function getMaxDeferCloseChannelTimeout() {
198
- return sessions.reduce((value, session) => {
199
- return session._maxDeferCloseChannel(value);
200
- }, 0);
201
- }
202
225
  }
@@ -9,15 +9,20 @@ module.exports = {
9
9
  create() {
10
10
  const args = Array.prototype.slice.call(arguments);
11
11
  return new Promise((resolve, reject) => {
12
- Broker.create(...args.concat((err, broker) => {
13
- if (err && !broker) return reject(err);
14
- broker.promises = true;
15
- const brokerAsPromised = new BrokerAsPromised(broker);
16
- if (!err) return resolve(brokerAsPromised);
17
- err.broker = Symbol();
18
- Object.defineProperty(err, err.broker, { enumerable: false, value: brokerAsPromised });
19
- return reject(err);
20
- }));
12
+ Broker.create(
13
+ ...args.concat((err, broker) => {
14
+ if (err && !broker) return reject(err);
15
+ broker.promises = true;
16
+ const brokerAsPromised = new BrokerAsPromised(broker);
17
+ if (!err) return resolve(brokerAsPromised);
18
+ err.broker = Symbol();
19
+ Object.defineProperty(err, err.broker, {
20
+ enumerable: false,
21
+ value: brokerAsPromised,
22
+ });
23
+ return reject(err);
24
+ })
25
+ );
21
26
  });
22
27
  },
23
28
  };
@@ -25,20 +30,21 @@ module.exports = {
25
30
  inherits(BrokerAsPromised, EventEmitter);
26
31
 
27
32
  function BrokerAsPromised(broker) {
28
-
29
33
  const methods = ['connect', 'nuke', 'purge', 'shutdown', 'bounce', 'publish', 'forward', 'unsubscribeAll'];
30
34
  const self = this;
31
35
 
32
36
  forwardEvents(broker, this);
33
37
 
34
38
  _.each(methods, (method) => {
35
- self[method] = function() {
39
+ self[method] = function () {
36
40
  const args = Array.prototype.slice.call(arguments);
37
41
  return new Promise((resolve, reject) => {
38
- broker[method](...args.concat((err, result) => {
39
- if (err) return reject(err);
40
- resolve(result);
41
- }));
42
+ broker[method](
43
+ ...args.concat((err, result) => {
44
+ if (err) return reject(err);
45
+ resolve(result);
46
+ })
47
+ );
42
48
  });
43
49
  };
44
50
  });
@@ -46,29 +52,35 @@ function BrokerAsPromised(broker) {
46
52
  this.config = broker.config;
47
53
  this.getConnections = broker.getConnections;
48
54
 
49
- this.subscribe = function() {
55
+ this.subscribe = function () {
50
56
  const args = Array.prototype.slice.call(arguments);
51
57
  return new Promise((resolve, reject) => {
52
- broker.subscribe(...args.concat((err, session) => {
53
- if (err) return reject(err);
54
- resolve(new SubscriberSessionAsPromised(session));
55
- }));
58
+ broker.subscribe(
59
+ ...args.concat((err, session) => {
60
+ if (err) return reject(err);
61
+ resolve(new SubscriberSessionAsPromised(session));
62
+ })
63
+ );
56
64
  });
57
65
  };
58
66
 
59
- this.subscribeAll = function() {
67
+ this.subscribeAll = function () {
60
68
  const args = Array.prototype.slice.call(arguments);
61
69
  return new Promise((resolve, reject) => {
62
- broker.subscribeAll(...args.concat((err, sessions) => {
63
- if (err) return reject(err);
64
- resolve(sessions.map((session) => {
65
- return new SubscriberSessionAsPromised(session);
66
- }));
67
- }));
70
+ broker.subscribeAll(
71
+ ...args.concat((err, sessions) => {
72
+ if (err) return reject(err);
73
+ resolve(
74
+ sessions.map((session) => {
75
+ return new SubscriberSessionAsPromised(session);
76
+ })
77
+ );
78
+ })
79
+ );
68
80
  });
69
81
  };
70
82
 
71
- this.getFullyQualifiedName = this.qualify = function(vhost, name) {
83
+ this.getFullyQualifiedName = this.qualify = function (vhost, name) {
72
84
  return broker.qualify(vhost, name);
73
85
  };
74
86
  }
@@ -23,30 +23,29 @@ module.exports = {
23
23
  };
24
24
 
25
25
  function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn, publishFn, config) {
26
-
27
26
  const self = this;
28
27
 
29
28
  this.name = config.name;
30
29
 
31
- this.init = function(next) {
30
+ this.init = function (next) {
32
31
  debug('Initialising publication: %s', config.name);
33
32
  next(null, self);
34
33
  };
35
34
 
36
- this.publish = function(payload, overrides, next) {
35
+ this.publish = function (payload, overrides, next) {
37
36
  const publishConfig = _.defaultsDeep({}, overrides, config);
38
37
  const content = getContent(payload);
39
38
  publishConfig.options.contentType = publishConfig.options.contentType || content.type;
40
39
  publishConfig.options.messageId = publishConfig.options.messageId || uuid();
41
40
 
42
- publishConfig.encryption
43
- ? _publishEncrypted(content.buffer, publishConfig, next)
44
- : _publish(content.buffer, publishConfig, next);
41
+ publishConfig.encryption ? _publishEncrypted(content.buffer, publishConfig, next) : _publish(content.buffer, publishConfig, next);
45
42
  };
46
43
 
47
- this.forward = function(message, overrides, next) {
44
+ this.forward = function (message, overrides, next) {
48
45
  const originalQueue = message.properties.headers.rascal.originalQueue;
49
- const publishConfig = _.defaultsDeep({}, overrides, config, { routingKey: message.fields.routingKey });
46
+ const publishConfig = _.defaultsDeep({}, overrides, config, {
47
+ routingKey: message.fields.routingKey,
48
+ });
50
49
 
51
50
  publishConfig.options = _.defaultsDeep(publishConfig.options, message.properties);
52
51
 
@@ -64,7 +63,7 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
64
63
  if (err) return next(err);
65
64
  debug('Message was encrypted using encryption profile: %s', encryptionConfig.name);
66
65
  _.set(publishConfig, 'options.headers.rascal.encryption.name', encryptionConfig.name);
67
- _.set(publishConfig, 'options.headers.rascal.encryption.iv', iv );
66
+ _.set(publishConfig, 'options.headers.rascal.encryption.iv', iv);
68
67
  _.set(publishConfig, 'options.headers.rascal.encryption.originalContentType', publishConfig.options.contentType);
69
68
  _.set(publishConfig, 'options.contentType', 'application/octet-stream');
70
69
 
@@ -106,12 +105,11 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
106
105
  return session.emit('error', err, messageId);
107
106
  }
108
107
 
109
- ok ? returnChannel(channel, errorHandler, returnHandler)
110
- : deferReturnChannel(channel, errorHandler, returnHandler);
108
+ ok ? returnChannel(channel, errorHandler, returnHandler) : deferReturnChannel(channel, errorHandler, returnHandler);
111
109
 
112
110
  session.emit('success', messageId);
113
111
  });
114
- } catch(err) {
112
+ } catch (err) {
115
113
  returnChannel(channel, errorHandler, returnHandler);
116
114
  return session.emit('error', err, messageId);
117
115
  }
@@ -152,11 +150,14 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
152
150
  }
153
151
 
154
152
  function textMessage(payload) {
155
- return { buffer: Buffer.from(payload), type : 'text/plain' };
153
+ return { buffer: Buffer.from(payload), type: 'text/plain' };
156
154
  }
157
155
 
158
156
  function jsonMessage(payload) {
159
- return { buffer: Buffer.from(JSON.stringify(payload)), type: 'application/json' };
157
+ return {
158
+ buffer: Buffer.from(JSON.stringify(payload)),
159
+ type: 'application/json',
160
+ };
160
161
  }
161
162
  }
162
163
 
@@ -7,29 +7,28 @@ module.exports = PublicationSession;
7
7
  inherits(PublicationSession, EventEmitter);
8
8
 
9
9
  function PublicationSession(vhost, messageId) {
10
-
11
10
  const self = this;
12
11
  let aborted = false;
13
12
 
14
13
  this.stats = {};
15
14
 
16
- this.abort = function() {
15
+ this.abort = function () {
17
16
  aborted = true;
18
17
  };
19
18
 
20
- this.isAborted = function() {
19
+ this.isAborted = function () {
21
20
  return aborted;
22
21
  };
23
22
 
24
- this._removePausedListener = function() {
25
- vhost.removeListener('paused',emitPaused);
23
+ this._removePausedListener = function () {
24
+ vhost.removeListener('paused', emitPaused);
26
25
  };
27
26
 
28
- this._startPublish = function() {
27
+ this._startPublish = function () {
29
28
  this.started = Date.now();
30
29
  };
31
30
 
32
- this._endPublish = function() {
31
+ this._endPublish = function () {
33
32
  this.stats.duration = Date.now() - this.started;
34
33
  };
35
34