-
Notifications
You must be signed in to change notification settings - Fork 0
The Initial CacheRedis #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,5 @@ notifications: | |
- d.f.ellis@ieee.org | ||
on_success: change | ||
on_failure: change | ||
|
||
services: redis |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,113 @@ | ||
function cacheRedis() { | ||
|
||
var redisManager = require('redis-manager'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var util = require('util'); | ||
|
||
function CacheRedis(config) { | ||
EventEmitter.call(this); | ||
this.host = config.host || 'localhost'; | ||
this.port = config.port || 6379; | ||
this.redisConfig = config.redisConfig || {}; | ||
this.namespace = config.namespace; | ||
this.lazy = config.lazy || false; | ||
this.redisClient = redisManager.getClient(this.port, this.host, this.redisConfig); | ||
this.redisClient.on('error', this.emit.bind(this, 'error')); | ||
this.cache = {}; | ||
|
||
if (!this.lazy) { | ||
this.redisClient.hgetall(this.namespace, function(err, cache) { | ||
if (err) this.emit('error', err); | ||
if (cache) { | ||
Object.keys(cache).forEach(function(key) { | ||
try { | ||
this.cache[key] = JSON.parse(cache[key]); | ||
} catch (e) { | ||
delete this.cache[key]; | ||
this.redisClient.hdel(this.namespace, key, function(err) { | ||
if (err) this.emit('error', err); | ||
}.bind(this)); | ||
} | ||
}.bind(this)); | ||
} | ||
}.bind(this)); | ||
} | ||
} | ||
|
||
module.exports = cacheRedis; | ||
util.inherits(CacheRedis, EventEmitter); | ||
|
||
CacheRedis.prototype.close = function() { | ||
redisManager.freeClient(this.redisClient); | ||
}; | ||
|
||
CacheRedis.prototype.set = function(key, val, callback) { | ||
this.cache[key] = val; | ||
this.redisClient.hset(this.namespace, key, JSON.stringify(val), callback); | ||
}; | ||
|
||
CacheRedis.prototype.getLocal = function(key) { | ||
return this.cache[key]; | ||
}; | ||
|
||
CacheRedis.prototype.get = function(key, callback) { | ||
if (this.cache.hasOwnProperty(key)) return process.nextTick(callback.bind(this, undefined, this.cache[key])); | ||
this.redisClient.hget(this.namespace, key, function(err, val) { | ||
if (err) return callback(err); | ||
if (val) { | ||
try { | ||
this.cache[key] = JSON.parse(val); | ||
} catch (e) { | ||
delete this.cache[key]; | ||
return this.redisClient.hdel(this.namespace, key, function(err) { | ||
if (err) return callback(err); | ||
callback(undefined, undefined); | ||
}); | ||
} | ||
} | ||
callback(undefined, this.cache[key]); | ||
}.bind(this)); | ||
}; | ||
|
||
CacheRedis.prototype.keysLocal = function() { | ||
return Object.keys(this.cache); | ||
}; | ||
|
||
CacheRedis.prototype.keys = function(callback) { | ||
this.redisClient.hkeys(this.namespace, callback); | ||
}; | ||
|
||
CacheRedis.prototype.valuesLocal = function() { | ||
return Object.keys(this.cache).map(function(key) { return this.cache[key]; }, this); | ||
}; | ||
|
||
CacheRedis.prototype.values = function(callback) { | ||
this.redisClient.hvals(this.namespace, function(err, values) { | ||
if (err) return callback(err); | ||
callback(undefined, values.map(function(value) { | ||
try { | ||
return JSON.parse(value); | ||
} catch (e) { | ||
return undefined; | ||
} | ||
}).filter(function(value) { | ||
return value !== undefined; | ||
})); | ||
}); | ||
}; | ||
|
||
CacheRedis.prototype.has = function(key, callback) { | ||
if (this.cache.hasOwnProperty(key)) { | ||
process.nextTick(callback.bind(this, true)); | ||
} else { | ||
this.redisClient.hexists(this.namespace, key, function(err, result) { | ||
if (err) return callback(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do not break the node callback convention even if error field is always There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but this is what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it can be a todo yes. for v2.0.0 ;) |
||
callback(!!result); // Cast to boolean | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same note as above, |
||
}); | ||
} | ||
}; | ||
|
||
CacheRedis.prototype.hasLocal = function(key) { | ||
return this.cache.hasOwnProperty(key); | ||
}; | ||
|
||
// TODO: Add other ES6 Map methods: items, forEach, iterator, delete, clear, toString, and the property size | ||
|
||
module.exports = CacheRedis; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module.exports = function mutate(obj, key, val, scope) { | ||
return function(test) { | ||
var old = obj[key]; | ||
obj[key] = val; | ||
var boundTestDone = test.end.bind(test); | ||
test.end = function() { | ||
obj[key] = old; | ||
boundTestDone(); | ||
}; | ||
try { | ||
scope.apply(this, arguments); | ||
} catch(e) { | ||
obj[key] = old; | ||
throw e; | ||
} | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we emit a ready event after all keys are loaded in the eager case, and right away in the lazy case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.