Last active
August 26, 2022 07:46
-
-
Save erdesigns-eu/7a962da1b167c2f801f4fda9ffc42509 to your computer and use it in GitHub Desktop.
Simple File Cache
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import os module | |
const os = require('os'); | |
// Import fs module | |
const fs = require('fs'); | |
// Import path module | |
const path = require('node:path'); | |
/** | |
* Simple file cache | |
*/ | |
module.exports = class FileCache { | |
// Cache object | |
#cache = Object.create(null); | |
// Cache size | |
#size = 0; | |
// Default cache timeout duration (1 Day) | |
#timeout = 86400000; | |
// Temp files directory | |
#tempDir = path.join(os.tmpdir(), 'FileCache'); | |
// Class constructor | |
constructor(options) { | |
const vm = this; | |
// Set default cache timeout | |
if (options && options.timeout && !isNaN(options.timeout)) { | |
vm.#timeout = parseInt(`${options.timeout}`); | |
} | |
// Override temp directory | |
if (options && options.tempDir && options.tempDir.length) { | |
vm.#tempDir = `${options.tempDir}`; | |
} | |
// If temp directory does not exist, create it | |
if (!fs.existsSync(this.#tempDir)){ | |
fs.mkdirSync(this.#tempDir, { recursive: true }); | |
} | |
// Clear "old" cache files, if any.. | |
fs.readdirSync(this.#tempDir).forEach((fn) => fs.rmSync(path.format({ | |
dir : this.#tempDir, | |
base : fn | |
}))); | |
} | |
// Save response stream to file, and add to cache | |
put(key, filename, res, timeout) { | |
// Validate timeout | |
if (typeof timeout !== 'undefined' && (typeof timeout !== 'number' || isNaN(timeout) || timeout <= 0)) { | |
throw new Error('Cache timeout must be a positive number'); | |
} | |
// Reference to cache (for timeout functon) | |
var cache = this.#cache; | |
// Reference to size (for timeout function) | |
var size = this.#size; | |
// Clear "old" timeout if record already exists in the cache | |
var oldRecord = cache[key]; | |
if (oldRecord) { | |
clearTimeout(oldRecord.timeout); | |
} else { | |
this.#size++; | |
} | |
// Construct filename | |
const fn = path.format({ | |
dir : this.#tempDir, | |
base : filename | |
}); | |
// Create new record for the cache | |
const expire = timeout ? timeout : this.#timeout; | |
var record = { | |
filename : fn, | |
expire : Date.now() + expire, | |
timeout : setTimeout(() => { | |
size--; | |
delete cache[key]; | |
fs.unlinkSync(fn); | |
}, expire) | |
} | |
// Write response stream to file | |
res.on('pipe', (readable) => { | |
readable.pipe(fs.createWriteStream(fn)); | |
}); | |
// Attach record to cache | |
cache[key] = record; | |
} | |
// Delete from cache | |
del(key) { | |
// Reference to cache | |
var cache = this.#cache; | |
// Reference to size | |
var size = this.#size; | |
// Can delete key? | |
var canDelete = true; | |
// Remove timeout from record | |
var oldRecord = cache[key]; | |
if (oldRecord) { | |
clearTimeout(oldRecord.timeout); | |
if (!isNaN(oldRecord.expire) && oldRecord.expire < Date.now()) { | |
canDelete = false; | |
} | |
} else { | |
canDelete = false; | |
} | |
// Delete key from cache and remove file | |
if (canDelete) { | |
size--; | |
fs.unlinkSync(cache[key].filename); | |
delete cache[key]; | |
} | |
// Return success | |
return canDelete; | |
} | |
// Clear cache | |
clear() { | |
// Reference to cache | |
var cache = this.#cache; | |
// Loop over keys in cache, and remove all timeouts and delete files | |
for (var key in cache) { | |
fs.unlinkSync(cache[key].filename); | |
clearTimeout(cache[key].timeout); | |
} | |
// Reset size | |
size = 0; | |
// Reset cache object | |
cache = Object.create(null); | |
} | |
// Get file stream of key from cache | |
get(key, res) { | |
// Reference to cache | |
var cache = this.#cache; | |
// Get record if not expired | |
var record = cache[key]; | |
if (typeof record !== 'undefined') { | |
if (isNaN(record.expire) || record.expire >= Date.now()) { | |
fs.createReadStream(record.filename).pipe(res); | |
} else { | |
size--; | |
delete cache[key]; | |
res.status(404); | |
} | |
} | |
} | |
// Check if key exists in cache | |
exists(key) { | |
// Reference to cache | |
var cache = this.#cache; | |
// Get record if not expired | |
var record = cache[key]; | |
// Return exists and not expired | |
return typeof record !== 'undefined' && (isNaN(record.expire) || record.expire >= Date.now()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment