catbox-redis
Advanced tools
Comparing version 4.2.1 to 4.2.2
@@ -52,2 +52,3 @@ | ||
} | ||
internals.client.set(key, cacheValue, ttl, (error) => { | ||
@@ -54,0 +55,0 @@ |
230
lib/index.js
@@ -1,16 +0,7 @@ | ||
'use strict'; | ||
// Load modules | ||
const Redis = require('ioredis'); | ||
const Hoek = require('hoek'); | ||
// Declare internals | ||
const internals = {}; | ||
internals.defaults = { | ||
const defaults = { | ||
host: '127.0.0.1', | ||
@@ -20,179 +11,150 @@ port: 6379 | ||
exports = module.exports = class Connection { | ||
exports = module.exports = internals.Connection = function (options) { | ||
constructor(options) { | ||
Hoek.assert(this.constructor === internals.Connection, 'Redis cache client must be instantiated using new'); | ||
Hoek.assert(this instanceof Connection, 'Redis cache client must be instantiated using new'); | ||
this.settings = Object.assign({}, internals.defaults, options); | ||
this.client = null; | ||
return this; | ||
}; | ||
this.client = null; | ||
this.settings = Object.assign({}, defaults, options); | ||
// Async | ||
internals.Connection.prototype.start = function () { | ||
if (this.settings.client) { | ||
this.client = this.settings.client; | ||
return this; | ||
} | ||
if (this.client) { | ||
return Promise.resolve(); | ||
} | ||
async start() { | ||
// Return a promise that is resolved when everything is ready | ||
return new Promise((resolve, reject) => { | ||
if (this.settings.client) { | ||
this.client = this.settings.client; | ||
} | ||
let client; | ||
if (this.client) { | ||
return; | ||
} | ||
const options = { | ||
password: this.settings.password, | ||
const options = Object.assign({}, this.settings, { | ||
db: this.settings.database || this.settings.db, | ||
tls: this.settings.tls | ||
}; | ||
name: this.settings.sentinelName, | ||
tls: this.settings.tls, | ||
lazyConnect: true | ||
}); | ||
if (this.settings.sentinels && this.settings.sentinels.length) { | ||
options.sentinels = this.settings.sentinels; | ||
options.name = this.settings.sentinelName; | ||
client = Redis.createClient(options); | ||
} | ||
else if (this.settings.url) { | ||
client = Redis.createClient(this.settings.url, options); | ||
} | ||
else if (this.settings.socket) { | ||
client = Redis.createClient(this.settings.socket, options); | ||
} | ||
else { | ||
client = Redis.createClient(this.settings.port, this.settings.host, options); | ||
} | ||
const client = new Redis(options); | ||
// Listen to errors | ||
client.on('error', (err) => { | ||
client.on('error', () => { | ||
if (!this.client) { // Failed to connect | ||
client.end(false); | ||
return reject(err); | ||
if (!this.client) { // Failed to connect | ||
client.disconnect(); | ||
} | ||
}); | ||
// Wait for connection | ||
client.once('ready', () => { | ||
await client.connect(); | ||
this.client = client; | ||
} | ||
this.client = client; | ||
return resolve(); | ||
}); | ||
}); | ||
}; | ||
async stop() { | ||
internals.Connection.prototype.stop = async function () { | ||
try { | ||
if (this.client && !this.settings.client) { | ||
this.client.removeAllListeners(); | ||
await this.client.quit(); | ||
try { | ||
if (this.client && !this.settings.client) { | ||
this.client.removeAllListeners(); | ||
await this.client.disconnect(); | ||
} | ||
} | ||
finally { | ||
this.client = null; | ||
} | ||
} | ||
finally { | ||
this.client = null; | ||
} | ||
}; | ||
isReady() { | ||
internals.Connection.prototype.isReady = function () { | ||
return !!this.client && this.client.status === 'ready'; | ||
} | ||
return !!this.client && this.client.status === 'ready'; | ||
}; | ||
validateSegmentName(name) { | ||
if (!name) { | ||
return new Error('Empty string'); | ||
} | ||
internals.Connection.prototype.validateSegmentName = function (name) { | ||
if (name.indexOf('\0') !== -1) { | ||
return new Error('Includes null character'); | ||
} | ||
if (!name) { | ||
return new Error('Empty string'); | ||
return null; | ||
} | ||
if (name.indexOf('\0') !== -1) { | ||
return new Error('Includes null character'); | ||
} | ||
async get(key) { | ||
return null; | ||
}; | ||
if (!this.client) { | ||
throw Error('Connection not started'); | ||
} | ||
const result = await this.client.get(this.generateKey(key)); | ||
internals.Connection.prototype.get = async function (key) { | ||
if (!result) { | ||
return null; | ||
} | ||
if (!this.client) { | ||
throw Error('Connection not started'); | ||
} | ||
let envelope = null; | ||
const result = await this.client.get(this.generateKey(key)); | ||
try { | ||
envelope = JSON.parse(result); | ||
} | ||
catch (ignoreErr) { } // Handled by validation below | ||
if (!result) { | ||
return null; | ||
} | ||
if (!envelope) { | ||
throw Error('Bad envelope content'); | ||
} | ||
let envelope = null; | ||
try { | ||
envelope = JSON.parse(result); | ||
} | ||
catch (err) { } // Handled by validation below | ||
if (!envelope.stored || !envelope.hasOwnProperty('item')) { | ||
throw Error('Incorrect envelope structure'); | ||
} | ||
if (!envelope) { | ||
throw Error('Bad envelope content'); | ||
return envelope; | ||
} | ||
if (!envelope.stored || !envelope.hasOwnProperty('item')) { | ||
throw Error('Incorrect envelope structure'); | ||
} | ||
async set(key, value, ttl) { | ||
return envelope; | ||
}; | ||
if (!this.client) { | ||
throw Error('Connection not started'); | ||
} | ||
const envelope = { | ||
item: value, | ||
stored: Date.now(), | ||
ttl | ||
}; | ||
internals.Connection.prototype.set = async function (key, value, ttl) { | ||
const cacheKey = this.generateKey(key); | ||
const stringifiedEnvelope = JSON.stringify(envelope); | ||
if (!this.client) { | ||
throw Error('Connection not started'); | ||
} | ||
await this.client.set(cacheKey, stringifiedEnvelope); | ||
const envelope = { | ||
item: value, | ||
stored: Date.now(), | ||
ttl | ||
}; | ||
const ttlSec = Math.max(1, Math.floor(ttl / 1000)); | ||
const cacheKey = this.generateKey(key); | ||
// Use 'pexpire' with ttl in Redis 2.6.0 | ||
return this.client.expire(cacheKey, ttlSec); | ||
} | ||
const stringifiedEnvelope = JSON.stringify(envelope); | ||
async drop(key) { | ||
await this.client.set(cacheKey, stringifiedEnvelope); | ||
if (!this.client) { | ||
throw Error('Connection not started'); | ||
} | ||
const ttlSec = Math.max(1, Math.floor(ttl / 1000)); | ||
// Use 'pexpire' with ttl in Redis 2.6.0 | ||
return this.client.expire(cacheKey, ttlSec); | ||
}; | ||
return await this.client.del(this.generateKey(key)); | ||
} | ||
generateKey({ id, segment }) { | ||
// Async | ||
internals.Connection.prototype.drop = function (key) { | ||
const parts = []; | ||
if (!this.client) { | ||
throw Error('Connection not started'); | ||
} | ||
return this.client.del(this.generateKey(key)); | ||
}; | ||
if (this.settings.partition) { | ||
parts.push(encodeURIComponent(this.settings.partition)); | ||
} | ||
parts.push(encodeURIComponent(segment)); | ||
parts.push(encodeURIComponent(id)); | ||
internals.Connection.prototype.generateKey = function (key) { | ||
const parts = []; | ||
if (this.settings.partition) { | ||
parts.push(encodeURIComponent(this.settings.partition)); | ||
return parts.join(':'); | ||
} | ||
parts.push(encodeURIComponent(key.segment)); | ||
parts.push(encodeURIComponent(key.id)); | ||
return parts.join(':'); | ||
}; |
{ | ||
"name": "catbox-redis", | ||
"description": "Redis adapter for catbox", | ||
"version": "4.2.1", | ||
"version": "4.2.2", | ||
"author": "Eran Hammer <eran@hammer.io> (http://hueniverse.com)", | ||
"contributors": [ | ||
"Marcus Poehls <marcus@futurestud.io> (https://futurestud.io)", | ||
"Loic Mahieu (https://igloo.be)", | ||
"Wyatt Preul <wpreul@gmail.com> (http://jsgeek.com)" | ||
@@ -21,3 +23,3 @@ ], | ||
"hoek": "5.x.x", | ||
"ioredis": "3.x.x" | ||
"ioredis": "4.x.x" | ||
}, | ||
@@ -27,3 +29,4 @@ "devDependencies": { | ||
"code": "5.x.x", | ||
"lab": "15.x.x" | ||
"lab": "16.x.x", | ||
"redis-parser": "3.x.x" | ||
}, | ||
@@ -30,0 +33,0 @@ "scripts": { |
@@ -6,3 +6,3 @@ catbox-redis [![Build Status](https://travis-ci.org/hapijs/catbox-redis.svg?branch=master)](https://travis-ci.org/hapijs/catbox-redis) | ||
Lead Maintainer: [Loic Mahieu](https://github.com/LoicMahieu) | ||
Lead Maintainer: [Marcus Poehls](https://github.com/marcuspoehls) | ||
@@ -23,3 +23,2 @@ | ||
### Use a Custom Redis Client | ||
@@ -49,4 +48,4 @@ `catbox-redis` allows you to specify a custom Redis client. Using a custom `client` puts you in charge of lifecycle handling (client start/stop). | ||
```sh | ||
redis-server& | ||
redis-server & | ||
npm test | ||
``` |
@@ -1,2 +0,1 @@ | ||
'use strict'; | ||
@@ -11,3 +10,3 @@ | ||
const RedisClient = require('ioredis'); | ||
const EventEmitter = require('events').EventEmitter; | ||
const RedisMockServer = require('./utils/redis-mock-server'); | ||
@@ -26,4 +25,2 @@ | ||
const it = lab.test; | ||
const before = lab.before; | ||
const after = lab.after; | ||
@@ -78,6 +75,6 @@ | ||
const _get = redisClient.get; | ||
redisClient.get = function (key, callback) { | ||
redisClient.get = function (...args) { | ||
getCalled = true; | ||
return _get.apply(redisClient, arguments); | ||
return _get.apply(redisClient, args); | ||
}; | ||
@@ -146,6 +143,3 @@ | ||
await expect((() => { | ||
return client.set(key, value, 10); | ||
})()).to.reject(Error, 'Converting circular structure to JSON'); | ||
await expect(client.set(key, value, 10)).to.reject(Error, 'Converting circular structure to JSON'); | ||
}); | ||
@@ -213,6 +207,3 @@ | ||
await expect((() => { | ||
return client.set(null, {}, 1000); | ||
})()).to.reject(Error); | ||
await expect(client.set(null, {}, 1000)).to.reject(Error); | ||
}); | ||
@@ -225,6 +216,3 @@ | ||
await expect((() => { | ||
return client.get({}); | ||
})()).to.reject(Error); | ||
await expect(client.get({})).to.reject(Error); | ||
}); | ||
@@ -237,6 +225,3 @@ | ||
await expect((() => { | ||
return client.drop({}); | ||
})()).to.reject(Error); | ||
await expect(client.drop({})).to.reject(Error); | ||
}); | ||
@@ -249,6 +234,3 @@ | ||
await expect((() => { | ||
return client.set({}, {}, 1000); | ||
})()).to.reject(Error); | ||
await expect(client.set({}, {}, 1000)).to.reject(Error); | ||
}); | ||
@@ -269,6 +251,3 @@ | ||
await expect((() => { | ||
return client.drop(null); | ||
})()).to.reject(Error); | ||
await expect(client.drop(null)).to.reject(Error); | ||
}); | ||
@@ -282,6 +261,3 @@ | ||
const key = { id: 'x', segment: 'test' }; | ||
await expect((() => { | ||
return client.connection.get(key); | ||
})()).to.reject(Error, 'Connection not started'); | ||
await expect(client.connection.get(key)).to.reject(Error, 'Connection not started'); | ||
}); | ||
@@ -295,6 +271,3 @@ | ||
const key = { id: 'x', segment: 'test' }; | ||
await expect((() => { | ||
return client.connection.set(key, 'y', 1); | ||
})()).to.reject(Error, 'Connection not started'); | ||
await expect(client.connection.set(key, 'y', 1)).to.reject(Error, 'Connection not started'); | ||
}); | ||
@@ -308,6 +281,9 @@ | ||
const key = { id: 'x', segment: 'test' }; | ||
await expect((async () => { | ||
try { | ||
await client.connection.drop(key); | ||
})()).to.reject(Error, 'Connection not started'); | ||
} | ||
catch (err) { | ||
expect(err.message).to.equal('Connection not started'); | ||
} | ||
}); | ||
@@ -325,2 +301,3 @@ | ||
}; | ||
expect(fn).to.throw(Error); | ||
@@ -339,2 +316,3 @@ }); | ||
}; | ||
expect(fn).to.throw(Error); | ||
@@ -348,6 +326,3 @@ }); | ||
await expect((() => { | ||
return client.drop('a'); | ||
})()).to.reject(Error); | ||
await expect(client.drop('a')).to.reject(Error); | ||
}); | ||
@@ -395,7 +370,4 @@ | ||
await expect((() => { | ||
await expect(redis.start()).to.reject(Error); | ||
return redis.start(); | ||
})()).to.reject(Error); | ||
expect(redis.client).to.not.exist(); | ||
@@ -437,7 +409,4 @@ }); | ||
await expect((() => { | ||
await expect(redis.start()).to.reject(Error); | ||
return redis.start(); | ||
})()).to.reject(Error); | ||
expect(redis.client).to.not.exist(); | ||
@@ -500,30 +469,16 @@ }); | ||
const oldCreateClient = RedisClient.createClient; | ||
before(() => { | ||
it('connects to a sentinel cluster.', async () => { | ||
return new Promise((resolve, reject) => { | ||
const sentinel = new RedisMockServer(27379, (argv) => { | ||
RedisClient.createClient = function (opts) { | ||
if (argv[0] === 'sentinel' && argv[1] === 'get-master-addr-by-name') { | ||
return ['127.0.0.1', '6379']; | ||
} | ||
}); | ||
const out = new EventEmitter(); | ||
process.nextTick(() => { | ||
sentinel.once('connect', () => { | ||
out.emit('ready'); | ||
out.removeAllListeners(); | ||
}); | ||
out.callArgs = opts; | ||
return out; | ||
}; | ||
resolve(); | ||
sentinel.disconnect(); | ||
}); | ||
}); | ||
after(() => { | ||
RedisClient.createClient = oldCreateClient; | ||
}); | ||
it('connects to a sentinel cluster.', async () => { | ||
const options = { | ||
@@ -533,7 +488,7 @@ sentinels: [ | ||
host: '127.0.0.1', | ||
port: 26379 | ||
port: 27379 | ||
}, | ||
{ | ||
host: '127.0.0.2', | ||
port: 26379 | ||
port: 27379 | ||
} | ||
@@ -549,4 +504,4 @@ ], | ||
expect(client).to.exist(); | ||
expect(client.callArgs.sentinels).to.equal(options.sentinels); | ||
expect(client.callArgs.name).to.equal(options.sentinelName); | ||
expect(client.connector.options.sentinels).to.equal(options.sentinels); | ||
expect(client.connector.options.name).to.equal(options.sentinelName); | ||
}); | ||
@@ -664,6 +619,8 @@ }); | ||
await expect((async () => { | ||
try { | ||
await redis.get('test'); | ||
})()).to.reject(Error, 'Connection not started'); | ||
} | ||
catch (err) { | ||
expect(err.message).to.equal('Connection not started'); | ||
} | ||
}); | ||
@@ -686,6 +643,3 @@ | ||
await expect((() => { | ||
return redis.get('test'); | ||
})()).to.reject(Error); | ||
await expect(redis.get('test')).to.reject(Error); | ||
}); | ||
@@ -709,6 +663,3 @@ | ||
await expect((() => { | ||
return redis.get('test'); | ||
})()).to.reject(Error, 'Bad envelope content'); | ||
await expect(redis.get('test')).to.reject(Error, 'Bad envelope content'); | ||
}); | ||
@@ -731,6 +682,3 @@ | ||
await expect((() => { | ||
return redis.get('test'); | ||
})()).to.reject(Error, 'Incorrect envelope structure'); | ||
await expect(redis.get('test')).to.reject(Error, 'Incorrect envelope structure'); | ||
}); | ||
@@ -753,6 +701,3 @@ | ||
await expect((() => { | ||
return redis.get('test'); | ||
})()).to.reject(Error, 'Incorrect envelope structure'); | ||
await expect(redis.get('test')).to.reject(Error, 'Incorrect envelope structure'); | ||
}); | ||
@@ -847,6 +792,8 @@ | ||
await expect((async () => { | ||
try { | ||
await redis.set('test1', 'test1', 3600); | ||
})()).to.reject(Error, 'Connection not started'); | ||
} | ||
catch (err) { | ||
expect(err.message).to.equal('Connection not started'); | ||
} | ||
}); | ||
@@ -869,6 +816,3 @@ | ||
await expect((() => { | ||
return redis.set('test', 'test', 3600); | ||
})()).to.reject(Error); | ||
await expect(redis.set('test', 'test', 3600)).to.reject(Error); | ||
}); | ||
@@ -888,6 +832,8 @@ }); | ||
await expect((async () => { | ||
try { | ||
await redis.drop('test2'); | ||
})()).to.reject(Error, 'Connection not started'); | ||
} | ||
catch (err) { | ||
expect(err.message).to.equal('Connection not started'); | ||
} | ||
}); | ||
@@ -894,0 +840,0 @@ |
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
Network access
Supply chain riskThis module accesses the network.
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
37931
10
900
4
49
2
+ Addeddebug@4.3.7(transitive)
+ Addedioredis@4.28.5(transitive)
+ Addedlodash.isarguments@3.1.0(transitive)
+ Addedms@2.1.3(transitive)
+ Addedp-map@2.1.0(transitive)
+ Addedredis-errors@1.2.0(transitive)
+ Addedredis-parser@3.0.0(transitive)
+ Addedstandard-as-callback@2.1.0(transitive)
- Removedbluebird@3.7.2(transitive)
- Removeddebug@2.6.9(transitive)
- Removedflexbuffer@0.0.6(transitive)
- Removedioredis@3.2.2(transitive)
- Removedlodash.assign@4.2.0(transitive)
- Removedlodash.bind@4.2.1(transitive)
- Removedlodash.clone@4.5.0(transitive)
- Removedlodash.clonedeep@4.5.0(transitive)
- Removedlodash.difference@4.5.0(transitive)
- Removedlodash.foreach@4.5.0(transitive)
- Removedlodash.isempty@4.4.0(transitive)
- Removedlodash.keys@4.2.0(transitive)
- Removedlodash.noop@3.0.1(transitive)
- Removedlodash.partial@4.2.1(transitive)
- Removedlodash.pick@4.4.0(transitive)
- Removedlodash.sample@4.2.1(transitive)
- Removedlodash.shuffle@4.2.0(transitive)
- Removedlodash.values@4.3.0(transitive)
- Removedms@2.0.0(transitive)
- Removedredis-parser@2.6.0(transitive)
Updatedioredis@4.x.x