-
Notifications
You must be signed in to change notification settings - Fork 121
Expand file tree
/
Copy pathCacheManager.ts
More file actions
90 lines (78 loc) · 2.7 KB
/
Copy pathCacheManager.ts
File metadata and controls
90 lines (78 loc) · 2.7 KB
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
// @flow
import * as _ from "lodash";
import * as FileSystem from "expo-file-system";
import SHA1 from "crypto-js/sha1";
export interface DownloadOptions {
md5?: boolean;
headers?: { [name: string]: string };
}
const BASE_DIR = `${FileSystem.cacheDirectory}expo-image-cache/`;
export class CacheEntry {
uri: string;
options: DownloadOptions;
constructor(uri: string, options: DownloadOptions) {
this.uri = uri;
this.options = options;
}
async getPath(): Promise<string | undefined> {
const { uri, options } = this;
const { path, exists, tmpPath } = await getCacheEntry(uri);
if (exists) {
return path;
}
const result = await FileSystem.createDownloadResumable(uri, tmpPath, options).downloadAsync();
// If the image download failed, we don't cache anything
if (result && result.status !== 200) {
return undefined;
}
await FileSystem.moveAsync({ from: tmpPath, to: path });
return path;
}
}
export default class CacheManager {
static entries: { [uri: string]: CacheEntry } = {};
static get(uri: string, options: DownloadOptions): CacheEntry {
if (!CacheManager.entries[uri]) {
CacheManager.entries[uri] = new CacheEntry(uri, options);
}
return CacheManager.entries[uri];
}
static async clearCache(): Promise<void> {
await FileSystem.deleteAsync(BASE_DIR, { idempotent: true });
await FileSystem.makeDirectoryAsync(BASE_DIR);
}
static async getCacheSize(): Promise<number> {
const result = await FileSystem.getInfoAsync(BASE_DIR);
if (!result.exists) {
throw new Error(`${BASE_DIR} not found`);
}
return result.size;
}
}
/*
* Returns the index of the query tail (i.e. the first ? or & after the last forward slash)
* , or the length of the string if there is no query tail.
*/
const getIndexOfQueryTail = (uri: string, minIndex: number = 0): number => {
for (let i = minIndex; i < uri.length; i += 1) {
if (uri.charAt(i) === "?" || uri.charAt(i) === "&") {
return i;
}
}
return uri.length;
};
const getCacheEntry = async (uri: string): Promise<{ exists: boolean; path: string; tmpPath: string }> => {
const filename = uri.substring(uri.lastIndexOf("/"), getIndexOfQueryTail(uri, uri.lastIndexOf("/")));
const ext = filename.indexOf(".") === -1 ? ".jpg" : filename.substring(filename.lastIndexOf("."));
const path = `${BASE_DIR}${SHA1(uri)}${ext}`;
const tmpPath = `${BASE_DIR}${SHA1(uri)}-${_.uniqueId()}${ext}`;
// TODO: maybe we don't have to do this every time
try {
await FileSystem.makeDirectoryAsync(BASE_DIR);
} catch (e) {
// do nothing
}
const info = await FileSystem.getInfoAsync(path);
const { exists } = info;
return { exists, path, tmpPath };
};