Sindbad~EG File Manager
'use strict';
const Boom = require('@hapi/boom');
const Hoek = require('@hapi/hoek');
const internals = {
maxTimer: 2147483647, // 2 ^ 31 - 1
entrySize: 144 // Approximate cache entry size without value: 144 bytes
};
internals.defaults = {
maxByteSize: 100 * 1024 * 1024, // 100MB
minCleanupIntervalMsec: 1000,
cloneBuffersOnGet: false
};
exports.Engine = class CatboxMemoryEngine {
constructor(options = {}) {
Hoek.assert(options.maxByteSize === undefined || options.maxByteSize >= 0, 'Invalid cache maxByteSize value');
Hoek.assert(options.allowMixedContent === undefined, 'allowMixedContent no longer supported');
Hoek.assert(options.minCleanupIntervalMsec === undefined || options.minCleanupIntervalMsec < internals.maxTimer, 'Invalid cache minCleanupIntervalMsec value');
Hoek.assert(options.cloneBuffersOnGet === undefined || typeof options.cloneBuffersOnGet === 'boolean', 'Invalid cloneBuffersOnGet value');
this.settings = Hoek.applyToDefaults(internals.defaults, options);
this.cache = null;
this._timer = null;
this._timerDue = null;
}
start() {
if (!this.cache) {
this.cache = new Map();
this.byteSize = 0;
}
}
_scheduleCleanup(msec) {
const cleanup = () => {
this._timer = null;
this._timerDue = null;
const now = Date.now();
let next = Infinity;
for (const [, segment] of this.cache) {
for (const [id, envelope] of segment) {
const ttl = envelope.stored + envelope.ttl - now;
if (ttl <= 0) {
segment.delete(id);
this.byteSize -= envelope.byteSize;
}
else {
next = Math.min(next, ttl);
}
}
}
if (next !== Infinity) {
this._scheduleCleanup(next);
}
};
const now = Date.now();
const timeout = Math.min(Math.max(this.settings.minCleanupIntervalMsec, msec), internals.maxTimer);
if (this._timer) {
if (this._timerDue - now < msec) {
return;
}
clearTimeout(this._timer);
}
this._timerDue = now + timeout;
this._timer = setTimeout(cleanup, timeout);
}
stop() {
clearTimeout(this._timer);
this._timer = null;
this._timerDue = null;
this.cache = null;
this.byteSize = 0;
}
isReady() {
return !!this.cache;
}
validateSegmentName(name) {
if (!name) {
throw new Boom.Boom('Empty string');
}
if (name.indexOf('\u0000') !== -1) {
throw new Boom.Boom('Includes null character');
}
return null;
}
get(key) {
if (!this.cache) {
throw new Boom.Boom('Connection not started');
}
const segment = this.cache.get(key.segment);
if (!segment) {
return null;
}
const envelope = segment.get(key.id);
if (!envelope) {
return null;
}
if (envelope.stored + envelope.ttl < Date.now()) {
this.drop(key);
return null;
}
let item = null;
if (Buffer.isBuffer(envelope.item)) {
item = envelope.item;
if (this.settings.cloneBuffersOnGet) {
const copy = Buffer.alloc(item.length);
item.copy(copy);
item = copy;
}
}
else {
try {
item = JSON.parse(envelope.item);
}
catch (err) {
throw new Boom.Boom('Bad value content');
}
}
const result = {
item,
stored: envelope.stored,
ttl: envelope.ttl
};
return result;
}
set(key, value, ttl) {
if (!this.cache) {
throw new Boom.Boom('Connection not started');
}
const envelope = new internals.MemoryCacheEntry(key, value, ttl);
let segment = this.cache.get(key.segment);
if (!segment) {
segment = new Map();
this.cache.set(key.segment, segment);
}
const cachedItem = segment.get(key.id);
if (cachedItem) {
this.byteSize -= cachedItem.byteSize; // If the item existed, decrement the byteSize as the value could be different
}
if (this.settings.maxByteSize &&
(this.byteSize + envelope.byteSize > this.settings.maxByteSize)) {
throw new Boom.Boom('Cache size limit reached');
}
this._scheduleCleanup(ttl);
segment.set(key.id, envelope);
this.byteSize += envelope.byteSize;
}
drop(key) {
if (!this.cache) {
throw new Boom.Boom('Connection not started');
}
const segment = this.cache.get(key.segment);
if (segment) {
const item = segment.get(key.id);
if (item) {
this.byteSize -= item.byteSize;
segment.delete(key.id);
}
}
}
};
internals.MemoryCacheEntry = class {
constructor(key, value, ttl) {
let valueByteSize = 0;
if (Buffer.isBuffer(value)) {
this.item = Buffer.alloc(value.length);
value.copy(this.item); // Copy buffer to prevent value from changing while in the cache
valueByteSize = this.item.length;
}
else {
this.item = JSON.stringify(value); // stringify() to prevent value from changing while in the cache
valueByteSize = Buffer.byteLength(this.item);
}
this.stored = Date.now();
this.ttl = ttl;
this.byteSize = internals.entrySize + valueByteSize + Buffer.byteLength(key.segment) + Buffer.byteLength(key.id);
this.timeoutId = null;
}
};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists