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