UNPKG

thywill

Version:

A Node.js clustered framework for single page web applications based on asynchronous messaging.

194 lines (175 loc) 5.29 kB
/** * @fileOverview * RedisResourceManager class definition. */ var util = require('util'); var Thywill = require('thywill'); var Resource = require('./resource'); //----------------------------------------------------------- // Class Definition //----------------------------------------------------------- /** * @class * A resource manager backed by Redis and the Thywill cache. Suitable for * clustered Thywill processes. */ function RedisResourceManager () { RedisResourceManager.super_.call(this); } util.inherits(RedisResourceManager, Thywill.getBaseClass('ResourceManager')); var p = RedisResourceManager.prototype; //----------------------------------------------------------- // 'Static' parameters //----------------------------------------------------------- RedisResourceManager.CONFIG_TEMPLATE = { cacheSize: { _configInfo: { description: 'Maximum number of resources that can be cached at one time.', types: 'integer', required: true } }, redisPrefix: { _configInfo: { description: 'A prefix applied to Redis keys.', types: 'string', required: true } }, redisClient: { _configInfo: { description: 'A Redis client instance from package "redis".', types: 'object', required: true } } }; //----------------------------------------------------------- //Initialization //----------------------------------------------------------- /** * @see Component#_configure */ p._configure = function (thywill, config, callback) { // Minimal configuration - all we're doing here is storing it for posterity. this.thywill = thywill; this.config = config; this.readyCallback = callback; // Set up a cache. this.cache = this.thywill.cacheManager.createCache('thywill.resourceManager.cache', this.config.cacheSize); // There are no asynchronous initialization functions here or in the // superclasses. So we can just call them and forge ahead without having // to wait around or check for completion. this._announceReady(this.NO_ERRORS); }; //----------------------------------------------------------- // Methods //----------------------------------------------------------- /** * @see ResourceManager#store */ p.store = function (key, resource, callback) { var self = this; var json = this.resourceToRedisJson(resource); this.config.redisClient.set(this.config.redisPrefix + key, json, function (error) { if (!error) { // Add to the cache. self.cache.set(key, resource); } callback(error); }); }; /** * @see ResourceManager#remove */ p.remove = function (key, callback) { var self = this; var prefixedKey = this.config.redisPrefix + key; // Remove from the cache regardless of what happens with Redis. this.cache.clear(key); // Remove from Redis. this.config.redisClient.multi() .get(prefixedKey) .del(prefixedKey) .exec(function (error, results) { var resource; if (!error && results[0]) { resource = self.redisJsonToResource(results[0]); } callback(error, resource); }); }; /** * @see ResourceManager#load */ p.load = function (key, callback) { var self = this; // Check the cache. var resource = this.cache.get(key); if (resource) { callback(this.NO_ERRORS, resource); } // Not in the cache, worse luck, so load from Redis. else { this.config.redisClient.get(this.config.redisPrefix + key, function (error, json) { var resource = null; if (!error && json) { resource = self.redisJsonToResource(json); } // Put the resource into the cache if we found one. if (resource) { self.cache.set(key, resource); } callback(error, resource); }); } }; /** * Obtain a JSON string suitable to write to Redis. * * @param {Resource} resource * A Resource instance. * @return {string} * JSON suitable to write to Redis. */ p.resourceToRedisJson = function (resource) { var stored = {}; for (var prop in resource) { if (prop !== 'buffer') { stored[prop] = resource[prop]; } } // If it has a buffer, encode to base64. It might be binary data. if (resource.buffer) { stored.base64 = resource.buffer.toString('base64'); } return JSON.stringify(stored); }; /** * Turn a JSON string from Redis into a Resource. * * @param {string} * JSON suitable to write to Redis. * @return {Resource} resource * A Resource instance. */ p.redisJsonToResource = function (json) { var resource; try { var attributes = JSON.parse(json); var buffer = null; // If data was encoded, put it back into a buffer. if (attributes.base64) { buffer = new Buffer(attributes.base64, 'base64'); delete attributes.base64; } resource = this.createResource(buffer, attributes); } catch (e) { this.thywill.log.error(e); } return resource; }; //----------------------------------------------------------- // Exports - Class Constructor //----------------------------------------------------------- module.exports = RedisResourceManager;