-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
82 lines (72 loc) · 2.82 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
'use strict';
const {promisify} = require("util");
class ReadThroughCache {
static Unstable = 2;
static Valid = true;
static Invalid = false;
constructor(client) {
this.setClient(client)
}
setClient(client) {
this.getAsync = promisify(client.get).bind(client);
this.setAsync = promisify(client.set).bind(client);
this.delAsync = promisify(client.del).bind(client);
}
async get(key,
readFunction,
ttl = 0,
cachedDataValidator = () => true,
freshDataValidator = () => true) {
let redisData = null;
const callTime = Math.round(new Date().getTime() / 1000);
try {
redisData = await this.getAsync(key);
} catch (e) {
return this.readData(key, readFunction, freshDataValidator, false, {}, callTime);
}
if (redisData == null) {
return this.readData(key, readFunction, freshDataValidator, false, {}, callTime);
}
try {
const parsedJson = JSON.parse(redisData)
const data = parsedJson.data;
const meta = parsedJson.meta;
const cacheExpired = (ttl > 0) && ((meta.updated + ttl) < callTime)
if (cacheExpired) {
return this.readData(key, readFunction, freshDataValidator, false, meta, callTime);
} else {
switch (cachedDataValidator(data, meta)) {
case ReadThroughCache.Valid:
return data;
case ReadThroughCache.Unstable:
return this.readData(key, readFunction, freshDataValidator, true, meta, callTime);
default:
return this.readData(key, readFunction, freshDataValidator, false, meta, callTime);
}
}
} catch (e) {
return this.readData(key, readFunction, freshDataValidator, false, {}, callTime);
}
}
async readData(key, readFunction, freshDataValidator, skipSaving, meta = {}, callTime) {
let freshData = await readFunction();
if (!skipSaving) {
if (freshDataValidator(freshData)) {
let createdTime, updateTime;
if (Object.entries(meta).length === 0) {
createdTime = callTime;
updateTime = callTime;
} else {
createdTime = meta.created;
updateTime = callTime;
}
let dataWithMeta = {data: freshData, meta: {created: createdTime, updated: updateTime}}
this.setAsync(key, JSON.stringify(dataWithMeta)).then()
} else {
this.delAsync(key).then()
}
}
return freshData;
}
}
module.exports = ReadThroughCache;