@sera4/essentia 1.0.25 → 1.0.27

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sera4/essentia",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "A library of utilities for Teleporte Web Services",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -29,6 +29,7 @@
29
29
  "async": "^2.6.1",
30
30
  "fast-safe-stringify": "^2.0.6",
31
31
  "git-rev": "^0.2.1",
32
+ "url-parse": "^1.4.7",
32
33
  "uuid": "^3.3.3",
33
34
  "winston": "^3.2.1",
34
35
  "winston-logstash": "^0.4.0"
package/package.tar.gz CHANGED
Binary file
package/queue/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  const amqp = require("amqplib/callback_api");
3
3
  const logger = require("./queue-logger");
4
+ const urlParse = require("url-parse");
4
5
  const { Publisher } = require("./publisher");
5
6
  const { Subscriber } = require("./subscriber");
6
7
 
@@ -15,6 +16,38 @@ class S4Queue {
15
16
  this.subs = {};
16
17
  }
17
18
 
19
+ /**
20
+ * Opens a connection and immediately closes it.
21
+ * To be used for health checks.
22
+ * @param {Object} options Connection parameters. At the very least options.connectionUrl must be present.
23
+ */
24
+ async testConnection(options) {
25
+ return new Promise((resolve, reject) => {
26
+ // We may run into issues with SNI TLS if
27
+ // we host with 3rd parties using our own certs.
28
+ // To avoid any issues, let's parse the url
29
+ // and provide the server name in the socket options
30
+ const urlParts = urlParse(options.connectionUrl);
31
+ const socketOptions = {servername: urlParts.hostname};
32
+
33
+ amqp.connect(options.connectionUrl, socketOptions, (err, conn) => {
34
+ if (err) {
35
+ return reject(err);
36
+ }
37
+ if (!conn) {
38
+ return reject("Failed to obtain connection");
39
+ }
40
+ conn.close(e => {
41
+ if (e) {
42
+ reject(e)
43
+ } else {
44
+ resolve(true)
45
+ }
46
+ })
47
+ });
48
+ });
49
+ }
50
+
18
51
  /**
19
52
  * Opens a connection to AMQP server.
20
53
  * @param {Object} options Connection parameters. At the very least options.connectionUrl must be present.
@@ -37,7 +70,14 @@ class S4Queue {
37
70
  // when a callback isn't provided, therefore run
38
71
  // in a new Promise
39
72
  return new Promise((resolve, reject) => {
40
- amqp.connect(options.connectionUrl, (err, conn) => {
73
+ // We may run into issues with SNI TLS if
74
+ // we host with 3rd parties using our own certs.
75
+ // To avoid any issues, let's parse the url
76
+ // and provide the server name in the socket options
77
+ const urlParts = urlParse(options.connectionUrl);
78
+ const socketOptions = {servername: urlParts.hostname};
79
+
80
+ amqp.connect(options.connectionUrl, socketOptions, (err, conn) => {
41
81
 
42
82
  if (err) {
43
83
  return reject(err);
@@ -123,6 +163,22 @@ class S4Queue {
123
163
  this.pubs[name] = p;
124
164
  }
125
165
 
166
+ /**
167
+ * Registers a new topic publisher on the given exchange.
168
+ * If exchange doesn't exist, one will be created.
169
+ * @param {String} exchange the name of the exchange on AMQP service.
170
+ */
171
+ async registerTopicPublisher(exchange) {
172
+ const name = exchange;
173
+ if (Object.keys(this.pubs).includes(name)) {
174
+ throw new Error(`Publisher ${name} already registered`);
175
+ }
176
+
177
+ const p = new Publisher(exchange, 'topic', true, name);
178
+ await p.init(this.connection);
179
+ this.pubs[name] = p;
180
+ }
181
+
126
182
  /**
127
183
  * Registers a new direct subscriber on a given exchange and queue.
128
184
  * If exchange and queue don't exists, they'll be created
@@ -152,15 +208,15 @@ class S4Queue {
152
208
  const p = this.pubs[exchange];
153
209
 
154
210
  if (!key) {
155
- reject(new Error(`Direct message require a key`));
211
+ throw(new Error(`Direct message require a key`));
156
212
  }
157
213
 
158
214
  if (!p) {
159
- reject(new Error(`No PUB for ${exchange} found`));
215
+ throw(new Error(`No PUB for ${exchange} found`));
160
216
  }
161
217
 
162
218
  if (p.type !== 'direct') {
163
- reject(new Error(`PUB ${exchange} is not direct`));
219
+ throw(new Error(`PUB ${exchange} is not direct`));
164
220
  }
165
221
 
166
222
  let content = msg;
@@ -174,6 +230,38 @@ class S4Queue {
174
230
  return await p.publish({key, content});
175
231
  }
176
232
 
233
+ /**
234
+ * Publishes a message on a given exchange with a topic.
235
+ * @param {String} exchange the name of the exchange.
236
+ * @param {String} topic the name of the topic.
237
+ * @param {Object} msg a JSON object as the message.
238
+ */
239
+ async publishTopicMessage(exchange, topic, msg) {
240
+ const p = this.pubs[exchange];
241
+
242
+ if (!topic) {
243
+ throw(new Error(`Topic message require a topic`));
244
+ }
245
+
246
+ if (!p) {
247
+ throw(new Error(`No PUB for ${exchange} found`));
248
+ }
249
+
250
+ if (p.type !== 'topic') {
251
+ throw(new Error(`PUB ${exchange} is not topic`));
252
+ }
253
+
254
+ let content = msg;
255
+ if (content.constructor !== ({}).constructor) {
256
+ // if not in JSON format, let's make it so
257
+ content = {
258
+ msg: msg
259
+ }
260
+ }
261
+
262
+ return await p.publish({key: topic, content});
263
+ }
264
+
177
265
  /**
178
266
  * Adds a listener for a specific key.
179
267
  * If a subscriber that was regitered was found
@@ -27,7 +27,7 @@ class Publisher {
27
27
  * @param {Object} conn amqp connection object
28
28
  */
29
29
  async init (conn) {
30
- logger.debug(`Initializing PUB channel for ${this.name}`);
30
+ logger.debug(`Initializing PUB channel for ${this.name}. Type: ${this.type}`);
31
31
 
32
32
  if(this.channel) {
33
33
  logger.warn(`PUB channel for ${this.name} already initialized`);
@@ -67,7 +67,9 @@ class Publisher {
67
67
  tracking_id: uuidv4(),
68
68
  data: msg.content
69
69
  }
70
- logger.debug("Publishing message", parcel);
70
+ logger.debug("Publishing message");
71
+ logger.debug("Key", msg.key);
72
+ logger.debug("Data", parcel);
71
73
 
72
74
  const content = Buffer.from(JSON.stringify(parcel));
73
75
  const res = await this.channel.publish(this.exchange, msg.key, content, {persistent: true});