UNPKG

2.63 kBPlain TextView Raw
1import { ICache } from "./icache";
2import { emptyDirSync, ensureFileSync, readJsonSync, removeSync, writeJsonSync } from "fs-extra";
3import { existsSync, readdirSync, renameSync } from "fs";
4import * as _ from "lodash";
5
6/**
7 * Saves data in new cache folder or reads it from old one.
8 * Avoids perpetually growing cache and situations when things need to consider changed and then reverted data to be changed.
9 */
10export class RollingCache<DataType> implements ICache<DataType>
11{
12 private oldCacheRoot: string;
13 private newCacheRoot: string;
14
15 private rolled: boolean = false;
16
17 /**
18 * @param cacheRoot: root folder for the cache
19 * @param checkNewCache: whether to also look in new cache when reading from cache
20 */
21 constructor(private cacheRoot: string, private checkNewCache: boolean)
22 {
23 this.oldCacheRoot = `${this.cacheRoot}/cache`;
24 this.newCacheRoot = `${this.cacheRoot}/cache_`;
25
26 emptyDirSync(this.newCacheRoot);
27 }
28
29 /**
30 * @returns true if name exist in old cache (or either old of new cache if checkNewCache is true)
31 */
32 public exists(name: string): boolean
33 {
34 if (this.rolled)
35 return false;
36
37 if (this.checkNewCache && existsSync(`${this.newCacheRoot}/${name}`))
38 return true;
39
40 return existsSync(`${this.oldCacheRoot}/${name}`);
41 }
42
43 public path(name: string): string
44 {
45 return `${this.oldCacheRoot}/${name}`;
46 }
47
48 /**
49 * @returns true if old cache contains all names and nothing more
50 */
51 public match(names: string[]): boolean
52 {
53 if (this.rolled)
54 return false;
55
56 if (!existsSync(this.oldCacheRoot))
57 return names.length === 0; // empty folder matches
58
59 return _.isEqual(readdirSync(this.oldCacheRoot).sort(), names.sort());
60 }
61
62 /**
63 * @returns data for name, must exist in old cache (or either old of new cache if checkNewCache is true)
64 */
65 public read(name: string): DataType | null | undefined
66 {
67 if (this.checkNewCache && existsSync(`${this.newCacheRoot}/${name}`))
68 return readJsonSync(`${this.newCacheRoot}/${name}`, { encoding: "utf8", throws: false });
69
70 return readJsonSync(`${this.oldCacheRoot}/${name}`, { encoding: "utf8", throws: false });
71 }
72
73 public write(name: string, data: DataType): void
74 {
75 if (this.rolled)
76 return;
77
78 if (data === undefined)
79 return;
80
81 writeJsonSync(`${this.newCacheRoot}/${name}`, data);
82 }
83
84 public touch(name: string)
85 {
86 if (this.rolled)
87 return;
88 ensureFileSync(`${this.newCacheRoot}/${name}`);
89 }
90
91 /**
92 * clears old cache and moves new in its place
93 */
94 public roll()
95 {
96 if (this.rolled)
97 return;
98
99 this.rolled = true;
100 removeSync(this.oldCacheRoot);
101 renameSync(this.newCacheRoot, this.oldCacheRoot);
102 }
103}