76 lines
2.1 KiB
JavaScript
76 lines
2.1 KiB
JavaScript
import cacache from 'cacache';
|
|
import { Readable } from 'stream';
|
|
import { KeyTimeout } from './key_timeout.js';
|
|
|
|
function getBodyAndMetaKeys(key) {
|
|
return [`${key}body`, `${key}meta`];
|
|
}
|
|
|
|
export class FileSystemCache {
|
|
constructor(options = {}) {
|
|
this.ttl = options.ttl;
|
|
this.keyTimeout = new KeyTimeout();
|
|
this.cacheDirectory = options.cacheDirectory || '.cache';
|
|
}
|
|
|
|
async get(key) {
|
|
const [, metaKey] = getBodyAndMetaKeys(key);
|
|
|
|
const metaInfo = await cacache.get.info(this.cacheDirectory, metaKey);
|
|
|
|
if (!metaInfo) {
|
|
return undefined;
|
|
}
|
|
|
|
const metaBuffer = await cacache.get.byDigest(this.cacheDirectory, metaInfo.integrity);
|
|
const metaData = JSON.parse(metaBuffer);
|
|
const { bodyStreamIntegrity, bodyStreamLength } = metaData;
|
|
delete metaData.bodyStreamIntegrity;
|
|
delete metaData.bodyStreamLength;
|
|
|
|
const bodyStream = bodyStreamLength > 0
|
|
? cacache.get.stream.byDigest(this.cacheDirectory, bodyStreamIntegrity)
|
|
: Readable.from(Buffer.alloc(0));
|
|
|
|
return {
|
|
bodyStream,
|
|
metaData,
|
|
};
|
|
}
|
|
|
|
remove(key) {
|
|
const [bodyKey, metaKey] = getBodyAndMetaKeys(key);
|
|
|
|
this.keyTimeout.clearTimeout(key);
|
|
|
|
return Promise.all([
|
|
cacache.rm.entry(this.cacheDirectory, bodyKey),
|
|
cacache.rm.entry(this.cacheDirectory, metaKey),
|
|
]);
|
|
}
|
|
|
|
async set(key, bodyStream, metaData, bodyStreamLength) {
|
|
const [bodyKey, metaKey] = getBodyAndMetaKeys(key);
|
|
const metaCopy = { ...metaData, bodyStreamLength };
|
|
|
|
this.keyTimeout.clearTimeout(key);
|
|
|
|
if (bodyStreamLength > 0) {
|
|
metaCopy.bodyStreamIntegrity = await new Promise((fulfill, reject) => {
|
|
bodyStream.pipe(cacache.put.stream(this.cacheDirectory, bodyKey))
|
|
.on('integrity', (i) => fulfill(i))
|
|
.on('error', (e) => {
|
|
reject(e);
|
|
});
|
|
});
|
|
}
|
|
|
|
const metaBuffer = Buffer.from(JSON.stringify(metaCopy));
|
|
await cacache.put(this.cacheDirectory, metaKey, metaBuffer);
|
|
|
|
if (typeof this.ttl === 'number') {
|
|
this.keyTimeout.updateTimeout(key, this.ttl, () => this.remove(key));
|
|
}
|
|
}
|
|
}
|