-
Notifications
You must be signed in to change notification settings - Fork 467
/
ImageCacheManager.js
141 lines (125 loc) · 5.03 KB
/
ImageCacheManager.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
'use strict';
const _ = require('lodash');
const fsUtils = require('./utils/fsUtils');
const pathUtils = require('./utils/pathUtils');
const MemoryCache = require('react-native-clcasher/MemoryCache').default;
module.exports = (defaultOptions = {}, urlCache = MemoryCache, fs = fsUtils, path = pathUtils) => {
const defaultDefaultOptions = {
headers: {},
ttl: 60 * 60 * 24 * 14, // 2 weeks
useQueryParamsInCacheKey: false,
cacheLocation: fs.getCacheDir(),
allowSelfSignedSSL: false,
};
// apply default options
_.defaults(defaultOptions, defaultDefaultOptions);
function isCacheable(url) {
return _.isString(url) && (_.startsWith(url.toLowerCase(), 'http://') || _.startsWith(url.toLowerCase(), 'https://'));
}
function cacheUrl(url, options, getCachedFile) {
if (!isCacheable(url)) {
return Promise.reject(new Error('Url is not cacheable'));
}
// allow CachedImage to provide custom options
_.defaults(options, defaultOptions);
// cacheableUrl contains only the needed query params
const cacheableUrl = path.getCacheableUrl(url, options.useQueryParamsInCacheKey);
// note: urlCache may remove the entry if it expired so we need to remove the leftover file manually
return urlCache.get(cacheableUrl)
.then(fileRelativePath => {
if (!fileRelativePath) {
// console.log('ImageCacheManager: url cache miss', cacheableUrl);
throw new Error('URL expired or not in cache');
}
// console.log('ImageCacheManager: url cache hit', cacheableUrl);
const cachedFilePath = `${options.cacheLocation}/${fileRelativePath}`;
return fs.exists(cachedFilePath)
.then((exists) => {
if (exists) {
return cachedFilePath
} else {
throw new Error('file under URL stored in url cache doesn\'t exsts');
}
});
})
// url is not found in the cache or is expired
.catch(() => {
const fileRelativePath = path.getImageRelativeFilePath(cacheableUrl);
const filePath = `${options.cacheLocation}/${fileRelativePath}`
// remove expired file if exists
return fs.deleteFile(filePath)
// get the image to cache (download / copy / etc)
.then(() => getCachedFile(filePath))
// add to cache
.then(() => urlCache.set(cacheableUrl, fileRelativePath, options.ttl))
// return filePath
.then(() => filePath);
});
}
return {
/**
* download an image and cache the result according to the given options
* @param url
* @param options
* @returns {Promise}
*/
downloadAndCacheUrl(url, options = {}) {
return cacheUrl(
url,
options,
filePath => fs.downloadFile(url, filePath, options.headers)
);
},
/**
* seed the cache for a specific url with a local file
* @param url
* @param seedPath
* @param options
* @returns {Promise}
*/
seedAndCacheUrl(url, seedPath, options = {}) {
return cacheUrl(
url,
options,
filePath => fs.copyFile(seedPath, filePath)
);
},
/**
* delete the cache entry and file for a given url
* @param url
* @param options
* @returns {Promise}
*/
deleteUrl(url, options = {}) {
if (!isCacheable(url)) {
return Promise.reject(new Error('Url is not cacheable'));
}
_.defaults(options, defaultOptions);
const cacheableUrl = path.getCacheableUrl(url, options.useQueryParamsInCacheKey);
const filePath = path.getImageFilePath(cacheableUrl, options.cacheLocation);
// remove file from cache
return urlCache.remove(cacheableUrl)
// remove file from disc
.then(() => fs.deleteFile(filePath));
},
/**
* delete all cached file from the filesystem and cache
* @param options
* @returns {Promise}
*/
clearCache(options = {}) {
_.defaults(options, defaultOptions);
return urlCache.flush()
.then(() => fs.cleanDir(options.cacheLocation));
},
/**
* return info about the cache, list of files and the total size of the cache
* @param options
* @returns {Promise.<{file: Array, size: Number}>}
*/
getCacheInfo(options = {}) {
_.defaults(options, defaultOptions);
return fs.getDirInfo(options.cacheLocation);
},
};
};