joola.io.engine
Version:
joola.io's Framework Engine
197 lines (184 loc) • 6.27 kB
JavaScript
/**
* joola.io
*
* Copyright Joola Smart Solutions, Ltd. <info@joo.la>
*
* Licensed under GNU General Public License 3.0 or later.
* Some rights reserved. See LICENSE, AUTHORS.
*
* @license GPL-3.0+ <http://spdx.org/licenses/GPL-3.0+>
*/
var cache = function (joola, next) {
joola.cache = {};
joola.cache.sweeperTimer = null;
joola.cache.sweeperTimeout = 10 * 1000;
joola.cache.redisCacheKey = "joola:cache";
joola.cache._start = function (joola, callback) {
joola.cache.runSweeper();
return callback();
};
joola.cache._teardown = function (joola, next) {
joola.cache.stopTimers(joola);
return next();
};
joola.cache.stopTimers = function (joola) {
clearTimeout(joola.cache.sweeperTimer);
};
joola.cache.prepareDomain = function () {
// until the redis module handles domains, we need to force the callback to be bound properly
// https://github.com/mranney/node_redis/pull/310/files
return {
bind: function (callback) {
return callback
}
}
};
joola.cache.size = function (next) {
var domain = joola.cache.prepareDomain();
joola.redis.client.hlen(joola.cache.redisCacheKey, domain.bind(function (err, count) {
next(null, count);
}));
};
joola.cache.load = function (store, key, options, next) {
if (typeof options == "function") {
next = options;
options = {}
}
var domain = joola.cache.prepareDomain();
joola.redis.client.hget(joola.cache.redisCacheKey + ':' + store, key, domain.bind(function (err, cacheObj) {
if (err != null) {
//joola.error(err);
return next(new Error("Failed to get value from redis"), null, null, null, null);
}
try {
cacheObj = JSON.parse(cacheObj);
} catch (e) {
}
if (cacheObj == null) {
if (typeof next == "function") {
process.nextTick(function () {
return next(new Error("Object not found"), null, null, null, null);
});
}
} else if (cacheObj.expireTimestamp >= new Date().getTime() || cacheObj.expireTimestamp == null) {
cacheObj.readAt = new Date().getTime();
if (cacheObj.expireTimestamp != null && options.expireTimeMS)
cacheObj.expireTimestamp = new Date().getTime() + options.expireTimeMS;
joola.redis.client.hset(joola.cache.redisCacheKey, key, JSON.stringify(cacheObj), domain.bind(function () {
if (typeof next == "function") {
process.nextTick(function () {
return next(null, cacheObj.value, cacheObj.expireTimestamp, cacheObj.createdAt, cacheObj.readAt);
});
}
}));
} else {
if (typeof next == "function") {
process.nextTick(function () {
return next(new Error("Object expired"), null, null, null, null);
});
}
}
}));
};
joola.cache.destroy = function (key, next) {
var domain = joola.cache.prepareDomain();
joola.redis.client.hdel(joola.cache.redisCacheKey, key, domain.bind(function (err, count) {
//joola.stats.increment("cache:cachedObjects", -1 );
if (err != null) {
joola.logger.error(err);
}
var resp = true;
if (count != 1) {
resp = false;
}
if (typeof next == "function") {
process.nextTick(function () {
next(null, resp);
});
}
}));
};
joola.cache.sweeper = function (next) {
var domain = joola.cache.prepareDomain();
joola.redis.client.hkeys(joola.cache.redisCacheKey, domain.bind(function (err, keys) {
var started = 0;
var sweepedKeys = [];
keys.forEach(function (key) {
started++;
joola.redis.client.hget(joola.cache.redisCacheKey, key, domain.bind(function (err, cacheObj) {
if (err != null) {
joola.logger.error(err);
}
try {
JSON.parse(cacheObj);
} catch (e) {
}
if (cacheObj != null) {
if (cacheObj.expireTimestamp != null && cacheObj.expireTimestamp < new Date().getTime()) {
joola.redis.client.hdel(joola.cache.redisCacheKey, key, domain.bind(function (err) {
sweepedKeys.push(key);
started--;
if (started == 0 && typeof next == "function") {
next(err, sweepedKeys);
}
}));
} else {
started--;
if (started == 0 && typeof next == "function") {
next(err, sweepedKeys);
}
}
} else {
started--;
if (started == 0 && typeof next == "function") {
next(err, sweepedKeys);
}
}
}));
});
if (keys.length == 0 && typeof next == "function") {
next(err, sweepedKeys);
}
}));
};
joola.cache.save = function (store, key, value, expireTimeMS, next) {
var domain = joola.cache.prepareDomain();
if (typeof expireTimeMS == "function" && typeof next == "undefined") {
next = expireTimeMS;
expireTimeMS = null;
}
if (expireTimeMS != null) {
var expireTimestamp = new Date().getTime() + expireTimeMS;
} else {
expireTimestamp = null;
}
var cacheObj = {
value: value,
expireTimestamp: expireTimestamp,
createdAt: new Date().getTime(),
readAt: null
};
joola.redis.client.hset(joola.cache.redisCacheKey + ':' + store, key, JSON.stringify(cacheObj), domain.bind(function () {
if (typeof next == "function") {
process.nextTick(function () {
next(null, true);
});
}
}));
};
joola.cache.runSweeper = function () {
clearTimeout(joola.cache.sweeperTimer);
joola.cache.sweeper(function (err, sweepedKeys) {
if (sweepedKeys.length > 0) {
joola.logger.info("cleaned " + sweepedKeys.length + " expired cache keys", "debug");
}
if (joola.running) {
joola.cache.sweeperTimer = setTimeout(joola.cache.runSweeper, joola.cache.sweeperTimeout, joola);
}
});
};
next();
};
/////////////////////////////////////////////////////////////////////
// exports
exports.cache = cache;