haraka-plugin-redis
Advanced tools
Comparing version 1.0.13 to 2.0.0
### 2.0.0 - 2022-03-29 | ||
- bump redis major version 3 -> 4 | ||
- API change, callbacks replaced by promises | ||
- config.ini | ||
- [server] -> [socket] | ||
- opts.db -> opts.database (to match upstream) | ||
### 1.0.13 - 2021-10-14 | ||
@@ -3,0 +13,0 @@ |
183
index.js
@@ -7,15 +7,13 @@ 'use strict'; | ||
exports.register = function () { | ||
const plugin = this; | ||
this.load_redis_ini(); | ||
plugin.load_redis_ini(); | ||
// another plugin has called us with: inherits('haraka-plugin-redis') | ||
if (plugin.name !== 'redis') return; | ||
if (this.name !== 'redis') return; | ||
// register when 'redis' is declared in config/plugins | ||
plugin.register_hook('init_master', 'init_redis_shared'); | ||
plugin.register_hook('init_child', 'init_redis_shared'); | ||
this.register_hook('init_master', 'init_redis_shared'); | ||
this.register_hook('init_child', 'init_redis_shared'); | ||
} | ||
const defaultOpts = { host: '127.0.0.1', port: '6379' }; | ||
const defaultOpts = { socket: { host: '127.0.0.1', port: '6379' } } | ||
@@ -32,16 +30,32 @@ exports.load_redis_ini = function () { | ||
const rc = plugin.redisCfg; | ||
plugin.redisCfg.server = Object.assign({}, defaultOpts, rc.opts, rc.server); | ||
if (rc.server.ip && !rc.server.host) rc.server.host = rc.server.ip; // backwards compat | ||
plugin.redisCfg.server = Object.assign({}, defaultOpts, rc.opts, rc.socket); | ||
plugin.redisCfg.pubsub = Object.assign({}, defaultOpts, rc.opts, rc.server, rc.pubsub); | ||
// backwards compat | ||
if (rc.server.ip && !rc.server.host) { | ||
rc.server.host = rc.server.ip | ||
delete rc.server.ip | ||
} | ||
// backwards compat with node-redis < 4 | ||
if (rc.server && !rc.socket) { | ||
rc.socket = rc.server | ||
delete rc.server | ||
} | ||
// same as above | ||
if (rc.db && !rc.database) { | ||
rc.database = rc.db | ||
delete rc.db | ||
} | ||
plugin.redisCfg.pubsub = Object.assign({}, defaultOpts, rc.opts, rc.socket, rc.pubsub); | ||
} | ||
exports.merge_redis_ini = function () { | ||
const plugin = this; | ||
if (!plugin.cfg) plugin.cfg = {}; // no <plugin>.ini loaded? | ||
if (!plugin.cfg.redis) plugin.cfg.redis = {}; // no [redis] in <plugin>.ini file | ||
if (!plugin.redisCfg) plugin.load_redis_ini(); | ||
if (!this.cfg) this.cfg = {}; // no <plugin>.ini loaded? | ||
if (!this.cfg.redis) this.cfg.redis = {}; // no [redis] in <plugin>.ini file | ||
if (!this.redisCfg) this.load_redis_ini(); | ||
plugin.cfg.redis = Object.assign({}, plugin.redisCfg.server, plugin.cfg.redis); | ||
this.cfg.redis = Object.assign({}, this.redisCfg.server, this.cfg.redis); | ||
} | ||
@@ -92,3 +106,3 @@ | ||
const pidb = plugin.cfg.redis.db; | ||
const pidb = plugin.cfg.redis.database; | ||
if (server.notes.redis) { // server-wide redis is available | ||
@@ -108,35 +122,32 @@ // and the DB not specified or is the same as server-wide | ||
exports.shutdown = function () { | ||
if (this.db) this.db.quit(); | ||
if (this.db) this.db.disconnect(); | ||
if (server && server.notes && server.notes.redis) { | ||
server.notes.redis.quit(); | ||
server.notes.redis.disconnect(); | ||
} | ||
} | ||
exports.redis_ping = function (done) { | ||
const plugin = this; | ||
exports.redis_ping = async function () { | ||
function nope (err) { | ||
if (err) plugin.logerror(err.message); | ||
plugin.redis_pings=false; | ||
done(err); | ||
this.redis_pings=false; | ||
if (!this.db) { | ||
return new Error('redis not initialized'); | ||
} | ||
if (!plugin.db) { | ||
return nope(new Error('redis not initialized')); | ||
try { | ||
const r = await this.db.ping() | ||
if (r !== 'PONG') return new Error('not PONG'); | ||
this.redis_pings=true | ||
} | ||
plugin.db.ping((err, res) => { | ||
if (err) return nope(err); | ||
if (res !== 'PONG') return nope(new Error('not PONG')); | ||
plugin.redis_pings=true; | ||
done(err, true); | ||
}); | ||
catch (e) { | ||
this.logerror(e.message) | ||
} | ||
} | ||
function getUriStr (client, opts) { | ||
let msg = `redis://${opts.host}:${opts.port}`; | ||
if (opts.db) msg += `/${opts.db}`; | ||
if (client && client.server_info && client.server_info.redis_version) { | ||
msg += `\tv${client.server_info.redis_version}`; | ||
let msg = `redis://${opts?.socket?.host}:${opts?.socket?.port}`; | ||
if (opts.database) msg += `/${opts.database}`; | ||
if (client?.server_info?.redis_version) { | ||
msg += `\tv${client?.server_info?.redis_version}`; | ||
} | ||
@@ -146,21 +157,31 @@ return msg; | ||
exports.get_redis_client = function (opts, next) { | ||
exports.get_redis_client = async function (opts) { | ||
const client = redis.createClient(opts); | ||
const urlStr = getUriStr(client, opts); | ||
const client = redis.createClient(opts) | ||
let urlStr | ||
client | ||
.on('error', (err) => { | ||
this.logerror(err.message); | ||
next(err); | ||
}) | ||
.on('ready', () => { | ||
this.loginfo(`connected to ${urlStr}`); | ||
next(); | ||
}) | ||
.on('end', () => { | ||
this.loginfo(`Disconnected from ${urlStr}`); | ||
}); | ||
}) | ||
return client; | ||
try { | ||
await client.connect() | ||
if (opts.database) client.dbid = opts.database | ||
client.server_info = await client.info() | ||
urlStr = getUriStr(client, opts) | ||
this.loginfo(`connected to ${urlStr}`); | ||
return client | ||
} | ||
catch (e) { | ||
console.error(e) | ||
} | ||
} | ||
@@ -176,63 +197,33 @@ | ||
exports.redis_subscribe_pattern = function (pattern, next) { | ||
const plugin = this; | ||
exports.redis_subscribe_pattern = async function (pattern) { | ||
if (plugin.redis) return next(); // already subscribed? | ||
if (this.redis) return // already subscribed? | ||
plugin.redis = require('redis').createClient(plugin.redisCfg.pubsub) | ||
.on('error', function (err) { | ||
next(err.message); | ||
}) | ||
.on('psubscribe', function (pattern2, count) { | ||
plugin.logdebug(plugin, `psubscribed to ${pattern2}`); | ||
next(); | ||
}) | ||
.on('punsubscribe', function (pattern3, count) { | ||
plugin.logdebug(plugin, `unsubsubscribed from ${pattern3}`); | ||
connection.notes.redis.quit(); | ||
}); | ||
this.redis = await redis.createClient(this.redisCfg.pubsub) | ||
plugin.redis.psubscribe(pattern); | ||
await this.redis.psubscribe(pattern); | ||
this.logdebug(this, `psubscribed to ${pattern}`); | ||
} | ||
exports.redis_subscribe = function (connection, next) { | ||
const plugin = this; | ||
exports.redis_subscribe = async function (connection) { | ||
if (connection.notes.redis) { | ||
connection.logdebug(plugin, `redis already subscribed`); | ||
// another plugin has already called this. Do nothing | ||
return next(); | ||
connection.logdebug(this, `redis already subscribed`); | ||
return; // another plugin has already called this. | ||
} | ||
let calledNext = false; | ||
function nextOnce (errMsg) { | ||
if (calledNext) return; | ||
calledNext = true; | ||
if (errMsg && connection) connection.logerror(plugin, errMsg); | ||
next(); | ||
} | ||
const timer = setTimeout(() => { | ||
nextOnce('redis psubscribe timed out'); | ||
connection.logerror('redis psubscribe timed out'); | ||
}, 3 * 1000); | ||
connection.notes.redis = require('redis').createClient(plugin.redisCfg.pubsub) | ||
.on('error', (err) => { | ||
clearTimeout(timer); | ||
nextOnce(err.message); | ||
}) | ||
.on('psubscribe', function (pattern, count) { | ||
clearTimeout(timer); | ||
connection.logdebug(plugin, `psubscribed to ${pattern}`); | ||
nextOnce(); | ||
}) | ||
.on('punsubscribe', function (pattern, count) { | ||
connection.logdebug(plugin, `unsubsubscribed from ${pattern}`); | ||
connection.notes.redis.quit(); | ||
}); | ||
connection.notes.redis = await redis.createClient(this.redisCfg.pubsub) | ||
connection.notes.redis.psubscribe(plugin.get_redis_sub_channel(connection)); | ||
clearTimeout(timer); | ||
const pattern = this.get_redis_sub_channel(connection) | ||
connection.notes.redis.psubscribe(pattern); | ||
connection.logdebug(this, `psubscribed to ${pattern}`); | ||
} | ||
exports.redis_unsubscribe = function (connection) { | ||
exports.redis_unsubscribe = async function (connection) { | ||
@@ -243,3 +234,7 @@ if (!connection.notes.redis) { | ||
} | ||
connection.notes.redis.punsubscribe(this.get_redis_sub_channel(connection)); | ||
const pattern = this.get_redis_sub_channel(connection) | ||
await connection.notes.redis.punsubscribe(pattern); | ||
connection.logdebug(this, `unsubsubscribed from ${pattern}`); | ||
connection.notes.redis.disconnect(); | ||
} |
{ | ||
"name": "haraka-plugin-redis", | ||
"version": "1.0.13", | ||
"version": "2.0.0", | ||
"description": "Redis plugin for Haraka & other plugins to inherit from", | ||
@@ -10,9 +10,9 @@ "main": "index.js", | ||
"dependencies": { | ||
"redis": "^3.1.2" | ||
"redis": "^4.0.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": ">=7", | ||
"eslint": "^8.12.0", | ||
"eslint-plugin-haraka": "*", | ||
"haraka-test-fixtures": "*", | ||
"mocha": "*" | ||
"mocha": "^9.2.0" | ||
}, | ||
@@ -23,3 +23,4 @@ "scripts": { | ||
"cover": "NODE_ENV=cov npx nyc --reporter=lcovonly npm run test", | ||
"test": "npx mocha --exit" | ||
"versions": "npx dependency-version-checker check", | ||
"test": "npx mocha" | ||
}, | ||
@@ -26,0 +27,0 @@ "repository": { |
@@ -14,3 +14,3 @@ # haraka-plugin-redis | ||
### [server] | ||
### [socket] | ||
@@ -29,3 +29,3 @@ ```ini | ||
Publish & Subscribe are DB agnostic and thus have no db setting. If host and port and not defined, they default to the same as [server] settings. | ||
Publish & Subscribe are DB agnostic and thus have no db setting. If host and port and not defined, they default to the same as [socket] settings. | ||
@@ -35,4 +35,4 @@ ### [opts] | ||
```ini | ||
; see https://www.npmjs.com/package/redis#options-object-properties | ||
; db=0 | ||
; see https://github.com/redis/node-redis/blob/HEAD/docs/client-configuration.md | ||
; database=0 | ||
; password=battery-horse-staple | ||
@@ -80,13 +80,12 @@ ``` | ||
exports.register = function () { | ||
const plugin = this; | ||
plugin.inherits('redis'); | ||
this.inherits('redis'); | ||
plugin.cfg = plugin.config.get('my-plugin.ini'); | ||
this.cfg = this.config.get('my-plugin.ini'); | ||
// populate plugin.cfg.redis with defaults from redis.ini | ||
plugin.merge_redis_ini(); | ||
this.merge_redis_ini(); | ||
// cluster aware redis connection(s) | ||
plugin.register_hook('init_master', 'init_redis_plugin'); | ||
plugin.register_hook('init_child', 'init_redis_plugin'); | ||
this.register_hook('init_master', 'init_redis_plugin'); | ||
this.register_hook('init_child', 'init_redis_plugin'); | ||
} | ||
@@ -108,6 +107,5 @@ ``` | ||
[ci-img]: https://github.com/haraka/haraka-plugin-redis/workflows/Tests/badge.svg | ||
[ci-url]: https://github.com/haraka/haraka-plugin-redis/actions?query=workflow%3ATests | ||
[ci-img]: https://github.com/haraka/haraka-plugin-redis/actions/workflows/ci-test.yml/badge.svg | ||
[ci-url]: https://github.com/haraka/haraka-plugin-redis/actions/workflows/ci-test.yml | ||
[clim-img]: https://codeclimate.com/github/haraka/haraka-plugin-redis/badges/gpa.svg | ||
[clim-url]: https://codeclimate.com/github/haraka/haraka-plugin-redis |
@@ -16,20 +16,17 @@ 'use strict'; | ||
describe('config', function () { | ||
before(function (done) { | ||
before(async function () { | ||
this.plugin = new fixtures.plugin('index') | ||
this.plugin.register() | ||
done() | ||
}) | ||
it('loads', function (done) { | ||
it('loads', async function () { | ||
assert.equal(this.plugin.name, 'index'); | ||
done() | ||
}) | ||
it('config defaults', function (done) { | ||
assert.equal(this.plugin.redisCfg.server.host, '127.0.0.1') | ||
assert.equal(this.plugin.redisCfg.server.port, 6379) | ||
done() | ||
it('config defaults', async function () { | ||
assert.equal(this.plugin.redisCfg.server.socket.host, '127.0.0.1') | ||
assert.equal(this.plugin.redisCfg.server.socket.port, 6379) | ||
}) | ||
it('merges [opts] into server config', function (done) { | ||
it('merges [opts] into server config', async function () { | ||
this.plugin.config = this.plugin.config.module_config(path.resolve('test')); | ||
@@ -39,20 +36,24 @@ this.plugin.load_redis_ini(); | ||
main: {}, | ||
socket: {}, | ||
pubsub: { | ||
host: '127.0.0.1', | ||
port: '6379', | ||
db: 5, | ||
socket: { | ||
host: '127.0.0.1', | ||
port: '6379', | ||
}, | ||
database: 5, | ||
password: 'dontUseThisOne' | ||
}, | ||
opts: { db: 5, password: 'dontUseThisOne' }, | ||
opts: { database: 5, password: 'dontUseThisOne' }, | ||
server: { | ||
host: '127.0.0.1', | ||
port: '6379', | ||
db: 5, | ||
socket: { | ||
host: '127.0.0.1', | ||
port: '6379', | ||
}, | ||
database: 5, | ||
password: 'dontUseThisOne' | ||
} | ||
}); | ||
done(); | ||
}) | ||
it('merges redis.ini [opts] into plugin config', function (done) { | ||
it('merges redis.ini [opts] into plugin config', async function () { | ||
this.plugin.config = this.plugin.config.module_config(path.resolve('test')); | ||
@@ -64,9 +65,10 @@ this.plugin.load_redis_ini(); | ||
redis: { | ||
host: '127.0.0.1', | ||
port: '6379', | ||
db: 5, | ||
socket: { | ||
host: '127.0.0.1', | ||
port: '6379', | ||
}, | ||
database: 5, | ||
password: 'dontUseThisOne' | ||
} | ||
}) | ||
done() | ||
}) | ||
@@ -76,43 +78,39 @@ }) | ||
describe('connects', function () { | ||
before(function (done) { | ||
before(async function () { | ||
this.plugin = new fixtures.plugin('index') | ||
this.plugin.register() | ||
done() | ||
}) | ||
it('loads', function (done) { | ||
it('loads', async function () { | ||
assert.equal(this.plugin.name, 'index'); | ||
done(); | ||
}) | ||
it('connects', function (done) { | ||
const redis = this.plugin.get_redis_client({ | ||
host: this.plugin.redisCfg.server.host, | ||
port: this.plugin.redisCfg.server.port, | ||
it('connects', async function () { | ||
const redis = await this.plugin.get_redis_client({ | ||
socket: { | ||
host: this.plugin.redisCfg.server.host, | ||
port: this.plugin.redisCfg.server.port, | ||
}, | ||
retry_strategy: retry, | ||
}, | ||
function () { | ||
assert.ok(redis.connected); | ||
done(); | ||
}); | ||
}) | ||
assert.ok(redis); | ||
redis.disconnect() | ||
}) | ||
it('populates plugin.cfg.redis when asked', function (done) { | ||
it('populates plugin.cfg.redis when asked', async function () { | ||
assert.equal(this.plugin.cfg, undefined); | ||
this.plugin.merge_redis_ini(); | ||
assert.deepEqual(this.plugin.cfg.redis, { host: '127.0.0.1', port: '6379' }); | ||
done(); | ||
assert.deepEqual(this.plugin.cfg.redis, { socket: { host: '127.0.0.1', port: '6379' } }); | ||
}) | ||
it('connects to a different redis db', function (done) { | ||
it('connects to a different redis db', async function () { | ||
this.plugin.merge_redis_ini(); | ||
this.plugin.cfg.redis.db = 2; | ||
this.plugin.cfg.redis.database = 2; | ||
this.plugin.cfg.redis.retry_strategy = retry; | ||
const client = this.plugin.get_redis_client(this.plugin.cfg.redis, function () { | ||
// console.log(client); | ||
assert.equal(client.connected, true) | ||
assert.equal(client.selected_db, 2) | ||
done() | ||
}) | ||
const client = await this.plugin.get_redis_client(this.plugin.cfg.redis) | ||
const res = await client.ping() | ||
assert.equal(res, 'PONG') | ||
assert.ok(client) | ||
await client.disconnect() | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16654
8
275
107
+ Added@redis/bloom@1.2.0(transitive)
+ Added@redis/client@1.6.0(transitive)
+ Added@redis/graph@1.1.1(transitive)
+ Added@redis/json@1.0.7(transitive)
+ Added@redis/search@1.2.0(transitive)
+ Added@redis/time-series@1.1.0(transitive)
+ Addedcluster-key-slot@1.1.2(transitive)
+ Addedgeneric-pool@3.9.0(transitive)
+ Addedredis@4.7.0(transitive)
+ Addedyallist@4.0.0(transitive)
- Removeddenque@1.5.1(transitive)
- Removedredis@3.1.2(transitive)
- Removedredis-commands@1.7.0(transitive)
- Removedredis-errors@1.2.0(transitive)
- Removedredis-parser@3.0.0(transitive)
Updatedredis@^4.0.0