-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcache.js
124 lines (106 loc) · 4.67 KB
/
cache.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Redis Cache
// (c)copyright 2015 by Gerald Wodni <[email protected]>
"use strict";
var fs = require("fs");
var _ = require("underscore");
module.exports = function _cache( k ) {
return function _createCache( opts ) {
opts = _.extend({
timeout: 6 * 60 * 60,
/* TODO: rename to cache: after migration period */
prefix: "cache2:",
prefixDependencies: "cache2-dependencies:"
}, opts || {} );
/* cache disabled, return dummy functions */
if( opts.disabled )
return {
get: function( filename, callback ) { callback( null, null ); },
set: function( filename, content, callback ) { callback( null, null ); }
}
/* start watches for keys currently in cache */
k.rdb.keys( opts.prefix + "*", function( err, keys ) {
if( err )
return console.log( "Cache-Error:".bold.red, err );
keys.forEach( function( key ) {
k.rdb.ttl( key, function( err, ttl ) {
var filename = key.substring( opts.prefix.length );
var website = filename.split(":")[1];
filename = website.substring( 0, filename.length - website.length - 1 );
/* watch dependencies */
var dKey = dependenciesKey( filename );
k.rdb.smembers( dKey, function( err, dependencies ) {
/* create watch for file */
try {
watchFile( { filename: filename, website: website }, dependencies, ttl );
} catch( e ) {
/* check why watch has failed */
if( e.code != "ENOENT" )
throw e;
/* file has been deleted, delete cache as well */
k.rdb.del( [key, dKey] );
}
});
});
});
});
/* generate key */
function key( obj ) {
return opts.prefix + obj.filename + ":" + obj.website;
}
function dependenciesKey( obj ) {
return opts.prefixDependencies + obj.filename + ":" + obj.website;
}
/* watch for changes to file */
function watchFile( filenameObj, dependencies, timeout ) {
/* start filewatch */
console.log( "Cache-Watch:", filenameObj.filename + " : " + filenameObj.website, dependencies )
var watcher = fs.watch( filenameObj.filename, fileChanged );
var dependencyWatchers = [];
function stopWatchers() {
if( watcher && watcher.close )
watcher.close()
dependencyWatchers.forEach( dependencyWatcher => {
if( dependencyWatcher && dependencyWatcher.close )
dependencyWatcher.close();
});
}
function fileChanged( event, fname ) {
console.log( "Cache Changed".grey, (filenameObj.filename + " : " + filenameObj.website).yellow, "origin:".grey, fname.yellow );
/* if a change occured, clear cache */
k.rdb.del( [key( filenameObj ), dependenciesKey( filenameObj )], stopWatchers );
}
dependencies.forEach( dependency => {
dependencyWatchers.push( fs.watch( dependency, fileChanged ) );
});
/* stop watcher when cache hits TTL */
setTimeout( stopWatchers, ( timeout || opts.timeout ) * 1000 );
}
/* load value */
function get( filenameObj, callback ) {
k.rdb.get( key( filenameObj ), callback );
}
/* store value and place TTL */
function set( filenameObj, content, callback ) {
var dependencies = filenameObj.dependencies || [];
var fileKey = key( filenameObj );
var fileDependenciesKey = dependenciesKey( filenameObj );
if( dependencies.length )
k.rdb.multi()
.set( fileKey, content )
.expire( fileKey, opts.timeout )
.sadd( fileDependenciesKey, dependencies )
.expire( fileDependenciesKey, opts.timeout )
.exec( callback );
else
k.rdb.multi()
.set( fileKey, content )
.expire( fileKey, opts.timeout )
.exec( callback );
watchFile( filenameObj, dependencies );
}
return {
get: get,
set: set
}
};
};