@johnmmackey/ms-utils 3.3.3 → 4.1.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.
- package/CHANGELOG.md +16 -3
- package/README.md +8 -1
- package/index.js +2 -2
- package/lib/config.js +13 -5
- package/lib/mail.js +69 -64
- package/lib/winston-mslogger.js +1 -10
- package/package.json +5 -5
- package/tests/priorityTest.js +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
## Version
|
|
1
|
+
## Version 4.1.0
|
|
2
|
+
Added functionality:
|
|
3
|
+
* uses ```dotenv``` to load a local .env file
|
|
4
|
+
* pushes configuration into environment variables
|
|
5
|
+
|
|
6
|
+
## Version 4.0.0
|
|
7
|
+
BREAKING CHANGES
|
|
8
|
+
* @johnmmackey/amqp-utils removed as a dependency
|
|
9
|
+
* sendmail is removed, and replaced with the Mailer Class
|
|
10
|
+
```js
|
|
11
|
+
let m = new Mailer(connectionManager);
|
|
12
|
+
await m.send(recipients, options);
|
|
13
|
+
```
|
|
14
|
+
* winstonMSLoggerFactory now requires the third parameter of connectionManager
|
|
15
|
+
* mail attachements now placed in REDIS with base64 encoding
|
|
16
|
+
* new REDIS client and other dependency upgrades
|
|
2
17
|
|
|
3
|
-
* updated Buffer() to Buffer.from()
|
|
4
|
-
* updated to latest @johnmmackey/amqp-utils package
|
|
5
18
|
## Version 3.3.1
|
|
6
19
|
|
|
7
20
|
* updated etcd3 package to v1.1.0 (major rev upgrade)
|
package/README.md
CHANGED
|
@@ -28,7 +28,6 @@ let x = Config.get('key'); //typeof string
|
|
|
28
28
|
let y = Config.getObj('key'); // typeof Object
|
|
29
29
|
|
|
30
30
|
sendmail(
|
|
31
|
-
[
|
|
32
31
|
{"email": "user1@gmail.com","name": "John Smith"},
|
|
33
32
|
{"email": "user2@yahoo.com","name": "Jane Doe"},
|
|
34
33
|
{"email": "user3@aol.com","name": "Karen from Texas"}
|
|
@@ -42,6 +41,14 @@ sendmail(
|
|
|
42
41
|
.then( () => console.log('Success'))
|
|
43
42
|
.catch( err => console.log(err))
|
|
44
43
|
```
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
```Config.load``` now has 2 side effects:
|
|
47
|
+
* uses ```dotenv``` to load a .env file in the current working directory into the environment
|
|
48
|
+
* pushes all items loaded from etcd into the environment.
|
|
49
|
+
|
|
50
|
+
The order of precedence: .env > etcd > external set environment
|
|
51
|
+
|
|
45
52
|
## Future
|
|
46
53
|
* Add local queueing for log events when AMQP is not operative.
|
|
47
54
|
* Configurable logging setup (drivers)
|
package/index.js
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
const Config = require('./lib/config');
|
|
4
4
|
const winstonMSLoggerFactory = require('./lib/winston-mslogger');
|
|
5
5
|
const Utils = require('./lib/utils');
|
|
6
|
-
const
|
|
6
|
+
const Mailer = require('./lib/mail');
|
|
7
7
|
|
|
8
|
-
module.exports = { Utils, Config, winstonMSLoggerFactory,
|
|
8
|
+
module.exports = { Utils, Config, winstonMSLoggerFactory, Mailer };
|
package/lib/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { Etcd3 } = require('etcd3');
|
|
4
|
+
const dotenv = require('dotenv');
|
|
4
5
|
const client = new Etcd3({ hosts: process.env.ETCD_URI || 'http://localhost:2379' });
|
|
5
6
|
|
|
6
7
|
|
|
@@ -24,7 +25,14 @@ async function tryLoad(serviceName) {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
async function load(serviceName) {
|
|
27
|
-
|
|
28
|
+
await Promise.retry(10, tryLoad.bind(this, serviceName), 5000);
|
|
29
|
+
|
|
30
|
+
// as a side-effect, load these into process.env
|
|
31
|
+
dotenv.populate(process.env, config, { override: true });
|
|
32
|
+
|
|
33
|
+
// load any .env file that may be present into the environment
|
|
34
|
+
dotenv.config({ override: true });
|
|
35
|
+
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
function get(k) {
|
|
@@ -34,10 +42,10 @@ function get(k) {
|
|
|
34
42
|
function getObj(k) {
|
|
35
43
|
try {
|
|
36
44
|
return JSON.parse(config[k]);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
module.exports = { load, get, getObj }
|
package/lib/mail.js
CHANGED
|
@@ -3,79 +3,84 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const redis = require("redis");
|
|
5
5
|
const { v4: uuid } = require('uuid');
|
|
6
|
-
|
|
7
|
-
const { ConnectionManager: aC } = require('@johnmmackey/amqp-utils');
|
|
8
|
-
|
|
9
|
-
const rClient = redis.createClient({ url: process.env.REDIS_URI || 'redis://localhost' });
|
|
10
|
-
|
|
11
6
|
const { promisify } = require('util');
|
|
12
|
-
const setAsync = promisify(rClient.set).bind(rClient);
|
|
13
|
-
const expireAsync = promisify(rClient.expire).bind(rClient);
|
|
14
7
|
const readFileAsync = promisify(fs.readFile);
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// htmlBody
|
|
27
|
-
// attachments[]
|
|
28
|
-
// includeUnsubscribeLink
|
|
29
|
-
|
|
30
|
-
// returns a promise
|
|
31
|
-
|
|
32
|
-
module.exports = async function (recipients, options) {
|
|
33
|
-
|
|
34
|
-
if (!options.htmlBody) // Always want a html body
|
|
35
|
-
options.htmlBody = (options.textBody || '').replace(/\r?\n/g, '<br>');
|
|
36
|
-
|
|
37
|
-
var msg = {
|
|
38
|
-
from: options.from || "",
|
|
39
|
-
subject: options.subject || "",
|
|
40
|
-
attachments: [],
|
|
41
|
-
includeUnsubscribeLink: options.includeUnsubscribeLink
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (options.textBody) {
|
|
45
|
-
msg.textBodyKey = await writeKey(options.textBody, 'txt');
|
|
9
|
+
module.exports = class Mailer {
|
|
10
|
+
constructor(connectionManager) {
|
|
11
|
+
// param is amqp connection manager - see @johnmmackey/amqp-utils
|
|
12
|
+
this.aC = connectionManager;
|
|
13
|
+
this.rClient = redis.createClient({ url: process.env.REDIS_URI || 'redis://localhost' });
|
|
14
|
+
// while this is async, it has a retry, so should be OK
|
|
15
|
+
this.rClient.connect();
|
|
16
|
+
this.aC.addConfig(ch => {
|
|
17
|
+
ch.assertQueue('email', { durable: true });
|
|
18
|
+
})
|
|
46
19
|
}
|
|
47
20
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
21
|
+
// recipients structure: [{"email": "johnmmackey@yahoo.ca","name": "John Mackey"}]
|
|
22
|
+
// options:
|
|
23
|
+
// from
|
|
24
|
+
// subject
|
|
25
|
+
// replyTo
|
|
26
|
+
// textBody
|
|
27
|
+
// htmlBody
|
|
28
|
+
// attachments[]
|
|
29
|
+
// includeUnsubscribeLink
|
|
30
|
+
|
|
31
|
+
// returns a promise
|
|
32
|
+
|
|
33
|
+
async send(recipients, options) {
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
if (!options.htmlBody) // Always want a html body
|
|
37
|
+
options.htmlBody = (options.textBody || '').replace(/\r?\n/g, '<br>');
|
|
38
|
+
|
|
39
|
+
var msg = {
|
|
40
|
+
from: options.from || "",
|
|
41
|
+
subject: options.subject || "",
|
|
42
|
+
attachments: [],
|
|
43
|
+
includeUnsubscribeLink: options.includeUnsubscribeLink,
|
|
44
|
+
...(options.mailingLists ? {mailingLists: options.mailingLists} : {})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (options.textBody) {
|
|
48
|
+
msg.textBodyKey = await this.writeKey(options.textBody, 'txt');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
msg.htmlBodyKey = await this.writeKey(options.htmlBody, 'html');
|
|
52
|
+
|
|
53
|
+
for (let a of (options.attachments || [])) {
|
|
54
|
+
var da = {
|
|
55
|
+
filename: a.originalname,
|
|
56
|
+
contentType: a.mimetype
|
|
57
|
+
};
|
|
58
|
+
a.contentDisposition && (da.contentDisposition = a.contentDisposition);
|
|
59
|
+
a.cid && (da.cid = a.cid);
|
|
60
|
+
|
|
61
|
+
da.key = await this.writeKey(
|
|
62
|
+
Buffer.from(a.path ? await readFileAsync(a.path) : a.content).toString('base64'),
|
|
63
|
+
'attachment'
|
|
64
|
+
);
|
|
65
|
+
msg.attachments.push(da);
|
|
54
66
|
};
|
|
55
|
-
a.contentDisposition && (da.contentDisposition = a.contentDisposition);
|
|
56
|
-
a.cid && (da.cid = a.cid);
|
|
57
67
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'attachment'
|
|
61
|
-
);
|
|
62
|
-
msg.attachments.push(da);
|
|
63
|
-
};
|
|
68
|
+
if (options.replyTo)
|
|
69
|
+
msg.replyTo = options.replyTo;
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
msg.replyTo = options.replyTo;
|
|
71
|
+
msg.recipientsKey = await this.writeKey(JSON.stringify(recipients), 'recipients');
|
|
67
72
|
|
|
68
|
-
|
|
73
|
+
// Send it to queue here
|
|
74
|
+
if (!this.aC.ch)
|
|
75
|
+
throw new Error('No current AMQP channel available');
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
throw new Error('No current AMQP channel available');
|
|
73
|
-
aC.ch.sendToQueue('email', new Buffer.from(JSON.stringify(msg)));
|
|
74
|
-
}
|
|
77
|
+
this.aC.ch.sendToQueue('email', Buffer.from(JSON.stringify(msg)));
|
|
78
|
+
}
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.
|
|
80
|
-
|
|
80
|
+
async writeKey(v, type) {
|
|
81
|
+
let k = 'mail:' + uuid() + ':' + type;
|
|
82
|
+
await this.rClient.set(k, v);
|
|
83
|
+
await this.rClient.expire(k, 60 * 60 * 24);
|
|
84
|
+
return k;
|
|
85
|
+
}
|
|
81
86
|
}
|
package/lib/winston-mslogger.js
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const util = require('util');
|
|
4
|
-
const {ConnectionManagerClass} = require('@johnmmackey/amqp-utils');
|
|
5
4
|
|
|
6
|
-
module.exports = function(winston, serviceName,
|
|
5
|
+
module.exports = function(winston, serviceName, cm) {
|
|
7
6
|
|
|
8
|
-
var cm;
|
|
9
|
-
|
|
10
|
-
if(existingConnectionManager) {
|
|
11
|
-
cm = existingConnectionManager;
|
|
12
|
-
} else {
|
|
13
|
-
cm = new ConnectionManagerClass();
|
|
14
|
-
cm.connect();
|
|
15
|
-
}
|
|
16
7
|
cm.addConfig(ch => {
|
|
17
8
|
ch.assertQueue('logger', { durable: true });
|
|
18
9
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmmackey/ms-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Utility functions for Microservice Architecture",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"license": "ISC",
|
|
15
15
|
"homepage": "https://bitbucket.org/52westlabs/ms-utils#readme",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"
|
|
18
|
-
"etcd3": "^1.1.
|
|
19
|
-
"redis": "^
|
|
20
|
-
"uuid": "^
|
|
17
|
+
"dotenv": "^16.4.7",
|
|
18
|
+
"etcd3": "^1.1.2",
|
|
19
|
+
"redis": "^4.6.12",
|
|
20
|
+
"uuid": "^9.0.1"
|
|
21
21
|
}
|
|
22
22
|
}
|