rascal 13.0.6 → 13.1.3

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 (70) hide show
  1. package/.husky/pre-commit +1 -1
  2. package/.prettierrc.json +1 -0
  3. package/CHANGELOG.md +204 -1
  4. package/README.md +634 -396
  5. package/examples/advanced/cluster.js +8 -8
  6. package/examples/advanced/config.js +117 -114
  7. package/examples/advanced/handlers/deleteUser.js +23 -17
  8. package/examples/advanced/handlers/saveUser.js +38 -32
  9. package/examples/advanced/index.js +105 -78
  10. package/examples/busy-publisher/config.js +14 -17
  11. package/examples/busy-publisher/index.js +27 -22
  12. package/examples/default-exchange/config.js +10 -10
  13. package/examples/default-exchange/index.js +27 -18
  14. package/examples/mocha/config.js +9 -11
  15. package/examples/mocha/test.js +42 -35
  16. package/examples/promises/config.js +11 -13
  17. package/examples/promises/index.js +24 -17
  18. package/examples/simple/config.js +18 -18
  19. package/examples/simple/index.js +25 -23
  20. package/index.js +7 -7
  21. package/lib/amqp/Broker.js +154 -99
  22. package/lib/amqp/BrokerAsPromised.js +56 -35
  23. package/lib/amqp/Publication.js +219 -78
  24. package/lib/amqp/PublicationSession.js +13 -14
  25. package/lib/amqp/SubscriberError.js +293 -132
  26. package/lib/amqp/SubscriberSession.js +95 -56
  27. package/lib/amqp/SubscriberSessionAsPromised.js +4 -6
  28. package/lib/amqp/Subscription.js +328 -110
  29. package/lib/amqp/Vhost.js +366 -171
  30. package/lib/amqp/tasks/applyBindings.js +51 -18
  31. package/lib/amqp/tasks/assertExchanges.js +20 -11
  32. package/lib/amqp/tasks/assertQueues.js +13 -9
  33. package/lib/amqp/tasks/assertVhost.js +21 -17
  34. package/lib/amqp/tasks/bounceVhost.js +1 -1
  35. package/lib/amqp/tasks/checkExchanges.js +13 -9
  36. package/lib/amqp/tasks/checkQueues.js +13 -9
  37. package/lib/amqp/tasks/checkVhost.js +21 -17
  38. package/lib/amqp/tasks/closeChannel.js +3 -4
  39. package/lib/amqp/tasks/closeConnection.js +3 -3
  40. package/lib/amqp/tasks/createChannel.js +3 -4
  41. package/lib/amqp/tasks/createConnection.js +71 -51
  42. package/lib/amqp/tasks/deleteExchanges.js +14 -10
  43. package/lib/amqp/tasks/deleteQueues.js +13 -9
  44. package/lib/amqp/tasks/deleteVhost.js +26 -17
  45. package/lib/amqp/tasks/forewarnVhost.js +1 -1
  46. package/lib/amqp/tasks/index.js +25 -25
  47. package/lib/amqp/tasks/initCounters.js +18 -13
  48. package/lib/amqp/tasks/initPublications.js +17 -13
  49. package/lib/amqp/tasks/initShovels.js +29 -20
  50. package/lib/amqp/tasks/initSubscriptions.js +23 -13
  51. package/lib/amqp/tasks/initVhosts.js +21 -17
  52. package/lib/amqp/tasks/nukeVhost.js +1 -1
  53. package/lib/amqp/tasks/purgeQueues.js +13 -9
  54. package/lib/amqp/tasks/purgeVhost.js +1 -1
  55. package/lib/amqp/tasks/shutdownVhost.js +1 -1
  56. package/lib/backoff/exponential.js +9 -8
  57. package/lib/backoff/index.js +3 -3
  58. package/lib/backoff/linear.js +5 -7
  59. package/lib/config/baseline.js +26 -34
  60. package/lib/config/configure.js +274 -101
  61. package/lib/config/fqn.js +3 -3
  62. package/lib/config/tests.js +32 -29
  63. package/lib/config/validate.js +460 -70
  64. package/lib/counters/inMemory.js +3 -3
  65. package/lib/counters/inMemoryCluster.js +48 -30
  66. package/lib/counters/index.js +4 -4
  67. package/lib/counters/stub.js +2 -3
  68. package/lib/management/client.js +47 -17
  69. package/lib/utils/setTimeoutUnref.js +1 -1
  70. package/package.json +12 -4
@@ -1,10 +1,10 @@
1
- const debug = require('debug')('rascal:Publication');
2
- const format = require('util').format;
3
- const _ = require('lodash');
4
- const uuid = require('uuid').v4;
5
- const crypto = require('crypto');
6
- const PublicationSession = require('./PublicationSession');
7
- const setTimeoutUnref = require('../utils/setTimeoutUnref');
1
+ const debug = require("debug")("rascal:Publication");
2
+ const format = require("util").format;
3
+ const _ = require("lodash");
4
+ const uuid = require("uuid").v4;
5
+ const crypto = require("crypto");
6
+ const PublicationSession = require("./PublicationSession");
7
+ const setTimeoutUnref = require("../utils/setTimeoutUnref");
8
8
 
9
9
  module.exports = {
10
10
  create(vhost, config, next) {
@@ -15,28 +15,70 @@ module.exports = {
15
15
  const returnChannel = vhost.returnChannel.bind(vhost);
16
16
  const destroyChannel = vhost.destroyChannel.bind(vhost);
17
17
 
18
- if (Object.prototype.hasOwnProperty.call(config, 'exchange') && config.confirm) return new Publication(vhost, borrowConfirmChannel, returnConfirmChannel, destroyConfirmChannel, publishToConfirmExchange, config).init(next);
19
- if (Object.prototype.hasOwnProperty.call(config, 'exchange')) return new Publication(vhost, borrowChannel, returnChannel, destroyChannel, publishToExchange, config).init(next);
20
- if (config.queue && config.confirm) return new Publication(vhost, borrowConfirmChannel, returnConfirmChannel, destroyConfirmChannel, sendToConfirmQueue, config).init(next);
21
- if (config.queue) return new Publication(vhost, borrowChannel, returnChannel, destroyChannel, sendToQueue, config).init(next);
18
+ if (
19
+ Object.prototype.hasOwnProperty.call(config, "exchange") &&
20
+ config.confirm
21
+ )
22
+ return new Publication(
23
+ vhost,
24
+ borrowConfirmChannel,
25
+ returnConfirmChannel,
26
+ destroyConfirmChannel,
27
+ publishToConfirmExchange,
28
+ config
29
+ ).init(next);
30
+ if (Object.prototype.hasOwnProperty.call(config, "exchange"))
31
+ return new Publication(
32
+ vhost,
33
+ borrowChannel,
34
+ returnChannel,
35
+ destroyChannel,
36
+ publishToExchange,
37
+ config
38
+ ).init(next);
39
+ if (config.queue && config.confirm)
40
+ return new Publication(
41
+ vhost,
42
+ borrowConfirmChannel,
43
+ returnConfirmChannel,
44
+ destroyConfirmChannel,
45
+ sendToConfirmQueue,
46
+ config
47
+ ).init(next);
48
+ if (config.queue)
49
+ return new Publication(
50
+ vhost,
51
+ borrowChannel,
52
+ returnChannel,
53
+ destroyChannel,
54
+ sendToQueue,
55
+ config
56
+ ).init(next);
22
57
  },
23
58
  };
24
59
 
25
- function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn, publishFn, config) {
26
-
60
+ function Publication(
61
+ vhost,
62
+ borrowChannelFn,
63
+ returnChannelFn,
64
+ destroyChannelFn,
65
+ publishFn,
66
+ config
67
+ ) {
27
68
  const self = this;
28
69
 
29
70
  this.name = config.name;
30
71
 
31
- this.init = function(next) {
32
- debug('Initialising publication: %s', config.name);
72
+ this.init = function (next) {
73
+ debug("Initialising publication: %s", config.name);
33
74
  next(null, self);
34
75
  };
35
76
 
36
- this.publish = function(payload, overrides, next) {
77
+ this.publish = function (payload, overrides, next) {
37
78
  const publishConfig = _.defaultsDeep({}, overrides, config);
38
79
  const content = getContent(payload);
39
- publishConfig.options.contentType = publishConfig.options.contentType || content.type;
80
+ publishConfig.options.contentType =
81
+ publishConfig.options.contentType || content.type;
40
82
  publishConfig.options.messageId = publishConfig.options.messageId || uuid();
41
83
 
42
84
  publishConfig.encryption
@@ -44,32 +86,77 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
44
86
  : _publish(content.buffer, publishConfig, next);
45
87
  };
46
88
 
47
- this.forward = function(message, overrides, next) {
89
+ this.forward = function (message, overrides, next) {
48
90
  const originalQueue = message.properties.headers.rascal.originalQueue;
49
- const publishConfig = _.defaultsDeep({}, overrides, config, { routingKey: message.fields.routingKey });
50
-
51
- publishConfig.options = _.defaultsDeep(publishConfig.options, message.properties);
91
+ const publishConfig = _.defaultsDeep({}, overrides, config, {
92
+ routingKey: message.fields.routingKey,
93
+ });
52
94
 
53
- _.set(publishConfig, 'options.headers.rascal.restoreRoutingHeaders', !!publishConfig.restoreRoutingHeaders);
54
- _.set(publishConfig, 'options.headers.rascal.originalExchange', message.fields.exchange);
55
- _.set(publishConfig, 'options.headers.rascal.originalRoutingKey', message.fields.routingKey);
56
- _.set(publishConfig, 'options.CC', _.chain([]).concat(publishConfig.options.CC, format('%s.%s', originalQueue, publishConfig.routingKey)).uniq().compact().value());
95
+ publishConfig.options = _.defaultsDeep(
96
+ publishConfig.options,
97
+ message.properties
98
+ );
99
+
100
+ _.set(
101
+ publishConfig,
102
+ "options.headers.rascal.restoreRoutingHeaders",
103
+ !!publishConfig.restoreRoutingHeaders
104
+ );
105
+ _.set(
106
+ publishConfig,
107
+ "options.headers.rascal.originalExchange",
108
+ message.fields.exchange
109
+ );
110
+ _.set(
111
+ publishConfig,
112
+ "options.headers.rascal.originalRoutingKey",
113
+ message.fields.routingKey
114
+ );
115
+ _.set(
116
+ publishConfig,
117
+ "options.CC",
118
+ _.chain([])
119
+ .concat(
120
+ publishConfig.options.CC,
121
+ format("%s.%s", originalQueue, publishConfig.routingKey)
122
+ )
123
+ .uniq()
124
+ .compact()
125
+ .value()
126
+ );
57
127
 
58
128
  _publish(message.content, publishConfig, next);
59
129
  };
60
130
 
61
131
  function _publishEncrypted(buffer, publishConfig, next) {
62
132
  const encryptionConfig = publishConfig.encryption;
63
- encrypt(encryptionConfig.algorithm, encryptionConfig.key, encryptionConfig.ivLength, buffer, (err, iv, encrypted) => {
64
- if (err) return next(err);
65
- debug('Message was encrypted using encryption profile: %s', encryptionConfig.name);
66
- _.set(publishConfig, 'options.headers.rascal.encryption.name', encryptionConfig.name);
67
- _.set(publishConfig, 'options.headers.rascal.encryption.iv', iv );
68
- _.set(publishConfig, 'options.headers.rascal.encryption.originalContentType', publishConfig.options.contentType);
69
- _.set(publishConfig, 'options.contentType', 'application/octet-stream');
70
-
71
- _publish(encrypted, publishConfig, next);
72
- });
133
+ encrypt(
134
+ encryptionConfig.algorithm,
135
+ encryptionConfig.key,
136
+ encryptionConfig.ivLength,
137
+ buffer,
138
+ (err, iv, encrypted) => {
139
+ if (err) return next(err);
140
+ debug(
141
+ "Message was encrypted using encryption profile: %s",
142
+ encryptionConfig.name
143
+ );
144
+ _.set(
145
+ publishConfig,
146
+ "options.headers.rascal.encryption.name",
147
+ encryptionConfig.name
148
+ );
149
+ _.set(publishConfig, "options.headers.rascal.encryption.iv", iv);
150
+ _.set(
151
+ publishConfig,
152
+ "options.headers.rascal.encryption.originalContentType",
153
+ publishConfig.options.contentType
154
+ );
155
+ _.set(publishConfig, "options.contentType", "application/octet-stream");
156
+
157
+ _publish(encrypted, publishConfig, next);
158
+ }
159
+ );
73
160
  }
74
161
 
75
162
  function encrypt(algorithm, keyHex, ivLength, unencrypted, next) {
@@ -77,13 +164,13 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
77
164
  if (err) return next(err);
78
165
  let encrypted;
79
166
  try {
80
- const key = Buffer.from(keyHex, 'hex');
167
+ const key = Buffer.from(keyHex, "hex");
81
168
  const cipher = crypto.createCipheriv(algorithm, key, iv);
82
169
  encrypted = Buffer.concat([cipher.update(unencrypted), cipher.final()]);
83
170
  } catch (err) {
84
171
  return next(err);
85
172
  }
86
- next(null, iv.toString('hex'), encrypted);
173
+ next(null, iv.toString("hex"), encrypted);
87
174
  });
88
175
  }
89
176
 
@@ -92,10 +179,12 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
92
179
  const session = new PublicationSession(vhost, messageId);
93
180
  borrowChannelFn((err, channel) => {
94
181
  session._removePausedListener();
95
- if (err) return session.emit('error', err, messageId);
182
+ if (err) return session.emit("error", err, messageId);
96
183
  if (session.isAborted()) return abortPublish(channel, messageId);
97
- const errorHandler = _.once(handleChannelError.bind(null, channel, messageId, session, config));
98
- const returnHandler = session.emit.bind(session, 'return');
184
+ const errorHandler = _.once(
185
+ handleChannelError.bind(null, channel, messageId, session, config)
186
+ );
187
+ const returnHandler = session.emit.bind(session, "return");
99
188
  addListeners(channel, errorHandler, returnHandler);
100
189
  try {
101
190
  session._startPublish();
@@ -103,17 +192,18 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
103
192
  session._endPublish();
104
193
  if (err) {
105
194
  destroyChannel(channel, errorHandler, returnHandler);
106
- return session.emit('error', err, messageId);
195
+ return session.emit("error", err, messageId);
107
196
  }
108
197
 
109
- ok ? returnChannel(channel, errorHandler, returnHandler)
110
- : deferReturnChannel(channel, errorHandler, returnHandler);
198
+ ok
199
+ ? returnChannel(channel, errorHandler, returnHandler)
200
+ : deferReturnChannel(channel, errorHandler, returnHandler);
111
201
 
112
- session.emit('success', messageId);
202
+ session.emit("success", messageId);
113
203
  });
114
- } catch(err) {
204
+ } catch (err) {
115
205
  returnChannel(channel, errorHandler, returnHandler);
116
- return session.emit('error', err, messageId);
206
+ return session.emit("error", err, messageId);
117
207
  }
118
208
  });
119
209
 
@@ -121,7 +211,7 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
121
211
  }
122
212
 
123
213
  function abortPublish(channel, messageId) {
124
- debug('Publication of message: %s was aborted', messageId);
214
+ debug("Publication of message: %s was aborted", messageId);
125
215
  returnChannelFn(channel);
126
216
  }
127
217
 
@@ -131,7 +221,7 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
131
221
  }
132
222
 
133
223
  function deferReturnChannel(channel, errorHandler, returnHandler) {
134
- channel.once('drain', () => {
224
+ channel.once("drain", () => {
135
225
  returnChannel(channel, errorHandler, returnHandler);
136
226
  });
137
227
  }
@@ -152,71 +242,122 @@ function Publication(vhost, borrowChannelFn, returnChannelFn, destroyChannelFn,
152
242
  }
153
243
 
154
244
  function textMessage(payload) {
155
- return { buffer: Buffer.from(payload), type : 'text/plain' };
245
+ return { buffer: Buffer.from(payload), type: "text/plain" };
156
246
  }
157
247
 
158
248
  function jsonMessage(payload) {
159
- return { buffer: Buffer.from(JSON.stringify(payload)), type: 'application/json' };
249
+ return {
250
+ buffer: Buffer.from(JSON.stringify(payload)),
251
+ type: "application/json",
252
+ };
160
253
  }
161
254
  }
162
255
 
163
256
  function addListeners(channel, errorHandler, returnHandler) {
164
- channel.on('error', errorHandler);
165
- channel.on('return', returnHandler);
166
- channel.connection.once('error', errorHandler);
167
- channel.connection.once('close', errorHandler);
257
+ channel.on("error", errorHandler);
258
+ channel.on("return", returnHandler);
259
+ channel.connection.once("error", errorHandler);
260
+ channel.connection.once("close", errorHandler);
168
261
  }
169
262
 
170
263
  function removeListeners(channel, errorHandler, returnHandler) {
171
- channel.removeListener('error', errorHandler);
172
- channel.removeListener('return', returnHandler);
173
- channel.connection.removeListener('error', errorHandler);
174
- channel.connection.removeListener('close', errorHandler);
264
+ channel.removeListener("error", errorHandler);
265
+ channel.removeListener("return", returnHandler);
266
+ channel.connection.removeListener("error", errorHandler);
267
+ channel.connection.removeListener("close", errorHandler);
175
268
  }
176
269
 
177
270
  function publishToExchange(channel, content, config, next) {
178
- debug('Publishing %d bytes to exchange: %s with routingKeys: %s', content.length, config.exchange, _.compact([].concat(config.routingKey, config.options.CC, config.options.BCC)).join(', '));
179
- const ok = channel.publish(config.destination, config.routingKey, content, config.options);
271
+ debug(
272
+ "Publishing %d bytes to exchange: %s with routingKeys: %s",
273
+ content.length,
274
+ config.exchange,
275
+ _.compact(
276
+ [].concat(config.routingKey, config.options.CC, config.options.BCC)
277
+ ).join(", ")
278
+ );
279
+ const ok = channel.publish(
280
+ config.destination,
281
+ config.routingKey,
282
+ content,
283
+ config.options
284
+ );
180
285
  next(null, ok);
181
286
  }
182
287
 
183
288
  function publishToConfirmExchange(channel, content, config, next) {
184
- debug('Publishing %d bytes to confirm exchange: %s with routingKeys: %s', content.length, config.exchange, _.compact([].concat(config.routingKey, config.options.CC, config.options.BCC)).join(', '));
289
+ debug(
290
+ "Publishing %d bytes to confirm exchange: %s with routingKeys: %s",
291
+ content.length,
292
+ config.exchange,
293
+ _.compact(
294
+ [].concat(config.routingKey, config.options.CC, config.options.BCC)
295
+ ).join(", ")
296
+ );
185
297
 
186
298
  const once = _.once(next);
187
- const timeout = config.timeout ? setConfirmationTimeout(config.timeout, config.destination, once) : null;
188
-
189
- const ok = channel.publish(config.destination, config.routingKey, content, config.options, (err) => {
190
- clearTimeout(timeout);
191
- once(err, ok);
192
- });
299
+ const timeout = config.timeout
300
+ ? setConfirmationTimeout(config.timeout, config.destination, once)
301
+ : null;
302
+
303
+ const ok = channel.publish(
304
+ config.destination,
305
+ config.routingKey,
306
+ content,
307
+ config.options,
308
+ (err) => {
309
+ clearTimeout(timeout);
310
+ once(err, ok);
311
+ }
312
+ );
193
313
  }
194
314
 
195
315
  function sendToQueue(channel, content, config, next) {
196
- debug('Publishing %d bytes to queue: %s', content.length, config.queue);
316
+ debug("Publishing %d bytes to queue: %s", content.length, config.queue);
197
317
  const ok = channel.sendToQueue(config.destination, content, config.options);
198
318
  next(null, ok);
199
319
  }
200
320
 
201
321
  function sendToConfirmQueue(channel, content, config, next) {
202
- debug('Publishing %d bytes to queue: %s', content.length, config.queue);
322
+ debug("Publishing %d bytes to queue: %s", content.length, config.queue);
203
323
 
204
324
  const once = _.once(next);
205
- const timeout = config.timeout ? setConfirmationTimeout(config.timeout, config.destination, once) : null;
206
-
207
- const ok = channel.sendToQueue(config.destination, content, config.options, (err) => {
208
- clearTimeout(timeout);
209
- next(err, ok);
210
- });
325
+ const timeout = config.timeout
326
+ ? setConfirmationTimeout(config.timeout, config.destination, once)
327
+ : null;
328
+
329
+ const ok = channel.sendToQueue(
330
+ config.destination,
331
+ content,
332
+ config.options,
333
+ (err) => {
334
+ clearTimeout(timeout);
335
+ next(err, ok);
336
+ }
337
+ );
211
338
  }
212
339
 
213
340
  function setConfirmationTimeout(timeout, destination, next) {
214
341
  return setTimeoutUnref(() => {
215
- next(new Error(format('Timedout after %dms waiting for broker to confirm publication to: %s', timeout, destination)));
342
+ next(
343
+ new Error(
344
+ format(
345
+ "Timedout after %dms waiting for broker to confirm publication to: %s",
346
+ timeout,
347
+ destination
348
+ )
349
+ )
350
+ );
216
351
  }, timeout);
217
352
  }
218
353
 
219
354
  function handleChannelError(borked, messageId, emitter, config, err) {
220
- debug('Channel error: %s during publication of message: %s to %s using channel: %s', err.message, messageId, config.name, borked._rascal_id);
221
- emitter.emit('error', err, messageId);
355
+ debug(
356
+ "Channel error: %s during publication of message: %s to %s using channel: %s",
357
+ err.message,
358
+ messageId,
359
+ config.name,
360
+ borked._rascal_id
361
+ );
362
+ emitter.emit("error", err, messageId);
222
363
  }
@@ -1,46 +1,45 @@
1
- const debug = require('debug')('rascal:SubscriberSession');
2
- const EventEmitter = require('events').EventEmitter;
3
- const inherits = require('util').inherits;
1
+ const debug = require("debug")("rascal:SubscriberSession");
2
+ const EventEmitter = require("events").EventEmitter;
3
+ const inherits = require("util").inherits;
4
4
 
5
5
  module.exports = PublicationSession;
6
6
 
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
 
36
35
  function emitPaused() {
37
- self.emit('paused', messageId);
36
+ self.emit("paused", messageId);
38
37
  }
39
38
 
40
- vhost.on('paused', emitPaused);
39
+ vhost.on("paused", emitPaused);
41
40
 
42
- self.on('newListener', (event) => {
43
- if (event !== 'paused') return;
41
+ self.on("newListener", (event) => {
42
+ if (event !== "paused") return;
44
43
  if (vhost.isPaused()) emitPaused();
45
44
  });
46
45
  }