UNPKG

3.91 kBJavaScriptView Raw
1
2const _ = require('lodash');
3const redis = require('redis');
4
5const cls = require('./cls');
6const logger = require('./logger');
7const config = require('./config');
8
9let options = null;
10let redisclient = null;
11
12const retryStrategy = function(params) {
13 if (params.error.code === 'ECONNREFUSED') {
14 logger.error('Redis connection refused on host ' + options.host + ':' + options.port);
15 return params.error;
16 }
17 logger.error('Redis error ' + params.error);
18 // retry in n seconds
19 return params.attempt * 1000;
20};
21
22//
23const serialize = function(value) {
24 if (_.isBuffer(value)) {
25 return JSON.stringify({ buffer: value.toString('base64') });
26 }
27 return JSON.stringify({ v: value });
28}
29
30//
31const deserialize = function(data) {
32 const obj = JSON.parse(data);
33 if (obj.buffer) {
34 return Buffer.from(obj.buffer, 'base64');
35 }
36 if (obj.v !== undefined) { // can be null
37 deserializeDates(obj);
38 return obj.v;
39 }
40 return obj;
41}
42
43// init cache module : create redis client
44module.exports.init = function() {
45 options = config.redis || {};
46
47 options = _.defaultsDeep(options, {
48 timeout: null, // no timeout by default
49 no_ready_check: true,
50 retry_strategy: retryStrategy
51 });
52
53 redisclient = redis.createClient(options);
54 if (options.password) {
55 redisclient.auth(options.password);
56 }
57 redisclient.select(options.database || 0);
58 redisclient.on('error', function (err) {
59 logger.error(err);
60 });
61
62 if (config.env === 'test') {
63 module.exports.flushall();
64 }
65};
66
67//
68module.exports.redisclient = function() {
69 return redisclient;
70};
71
72//
73module.exports.put = function(namespace, id, value, callback, timeout) {
74 const k = namespace + '/' + id;
75 const v = serialize(value);
76
77 redisclient.set(k, v, cls.bind(function(err) {
78 if (callback) {
79 callback(null, value);
80 }
81 if (timeout || options.timeout) {
82 redisclient.expire(k, timeout || options.timeout);
83 }
84 }));
85};
86
87//
88module.exports.get = function(namespace, id, callback) {
89
90 const k = namespace + '/' + id;
91 redisclient.get(k, cls.bind(function(err, value) {
92 if (!value) {
93 return callback('notfound');
94 }
95 // found obj in redis
96 const obj = deserialize(value);
97 callback(null, obj);
98 }));
99};
100
101 // - returns object from cache if exists.
102 // - calls func(id, callback) otherwise and put result in cache
103module.exports.fetch = function(namespace, id, func, callback) {
104 module.exports.get(namespace, id, function(err, obj) {
105 if (err === 'notfound') {
106 // invoke
107 // console.log(namespace + '/' + id + ' not found in cache');
108 func(id, function(err, result) {
109 if (!err) {
110 // put in cache and return result obj
111 module.exports.put(namespace, id, result);
112 }
113 callback(err, result);
114 });
115 } else {
116 callback(err, obj);
117 }
118 });
119};
120
121// retro compatibility
122module.exports.getput = function(namespace, id, func, callback) {
123 console.warn('IGO: cache.getput() is deprecated, use cache.fetch() instead.');
124 module.exports.fetch(namespace, id, func, callback);
125};
126
127//
128module.exports.info = function(callback) {
129 redisclient.info(cls.bind(callback));
130};
131
132//
133module.exports.del = function(namespace, id, callback) {
134 const k = namespace+'/'+id;
135 // remove from redis
136 redisclient.del(k, cls.bind(callback));
137};
138
139//
140module.exports.flushall = function(callback) {
141 redisclient.flushall(cls.bind(callback));
142 logger.info('Cache flush');
143};
144
145
146const DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
147const deserializeDates = function(obj) {
148 if (_.isString(obj) && obj.match(DATE_REGEXP)) {
149 return new Date(obj);
150 } else if (_.isObject(obj) && _.keys(obj).length > 0) {
151 _.forIn(obj, function(value, key) {
152 obj[key] = deserializeDates(value);
153 });
154 }
155 return obj;
156};