Convert to class

This commit is contained in:
Cohee
2025-03-20 10:21:41 +02:00
parent df4700914c
commit 3355c682ca
2 changed files with 62 additions and 51 deletions

View File

@@ -66,7 +66,7 @@ import { init as statsInit, onExit as statsOnExit } from './src/endpoints/stats.
import { checkForNewContent } from './src/endpoints/content-manager.js'; import { checkForNewContent } from './src/endpoints/content-manager.js';
import { init as settingsInit } from './src/endpoints/settings.js'; import { init as settingsInit } from './src/endpoints/settings.js';
import { redirectDeprecatedEndpoints, ServerStartup, setupPrivateEndpoints } from './src/server-startup.js'; import { redirectDeprecatedEndpoints, ServerStartup, setupPrivateEndpoints } from './src/server-startup.js';
import { verifyCharactersDiskCache } from './src/endpoints/characters.js'; import { diskCache } from './src/endpoints/characters.js';
// Unrestrict console logs display limit // Unrestrict console logs display limit
util.inspect.defaultOptions.maxArrayLength = null; util.inspect.defaultOptions.maxArrayLength = null;
@@ -269,7 +269,7 @@ async function preSetupTasks() {
const directories = await getUserDirectoriesList(); const directories = await getUserDirectoriesList();
await checkForNewContent(directories); await checkForNewContent(directories);
await ensureThumbnailCache(); await ensureThumbnailCache();
await verifyCharactersDiskCache(directories); await diskCache.verify(directories);
cleanUploads(); cleanUploads();
migrateAccessLog(); migrateAccessLog();

View File

@@ -32,90 +32,101 @@ const isAndroid = process.platform === 'android';
const useShallowCharacters = !!getConfigValue('performance.lazyLoadCharacters', false, 'boolean'); const useShallowCharacters = !!getConfigValue('performance.lazyLoadCharacters', false, 'boolean');
const useDiskCache = !!getConfigValue('performance.useDiskCache', true, 'boolean'); const useDiskCache = !!getConfigValue('performance.useDiskCache', true, 'boolean');
const diskCache = { class DiskCache {
/** @type {string} */
static DIRECTORY = 'characters';
/** @type {number} */
static REMOVAL_INTERVAL = 60000;
/** @type {import('node-persist').LocalStorage} */
#instance;
/** @type {NodeJS.Timeout} */
#removalInterval;
/** /**
* @type {import('node-persist').LocalStorage?} * Queue for removal of cache entries.
* @private * @type {Set<string>}
*/ */
_instance: null, removalQueue = new Set();
/**
* @type {NodeJS.Timeout?}
* @private
*/
_removalInterval: null,
/** /**
* Processes the removal queue. * Processes the removal queue.
* @returns {Promise<void>} * @returns {Promise<void>}
* @private
*/ */
_removeCacheEntries: async function() { async #removeCacheEntries() {
try { try {
if (!useDiskCache || this.removalQueue.size === 0) { if (!useDiskCache || this.removalQueue.size === 0) {
return; return;
} }
const keys = await diskCache.instance().then(i => i.keys()); const keys = await this.instance().then(i => i.keys());
for (const item of this.removalQueue) { for (const item of this.removalQueue) {
const key = keys.find(k => k.startsWith(item)); const key = keys.find(k => k.startsWith(item));
if (key) { if (key) {
await diskCache.instance().then(i => i.removeItem(key)); await this.instance().then(i => i.removeItem(key));
} }
} }
this.removalQueue.clear(); this.removalQueue.clear();
} catch (error) { } catch (error) {
console.error('Error while removing cache entries:', error); console.error('Error while removing cache entries:', error);
} }
}, };
/** /**
* Gets the disk cache instance. * Gets the disk cache instance.
* @returns {Promise<import('node-persist').LocalStorage>} * @returns {Promise<import('node-persist').LocalStorage>}
*/ */
instance: async function() { async instance() {
if (this._instance) { if (this.#instance) {
return this._instance; return this.#instance;
} }
const cacheDir = path.join(globalThis.DATA_ROOT, '_cache', 'characters'); const cacheDir = path.join(globalThis.DATA_ROOT, '_cache', DiskCache.DIRECTORY);
this._instance = storage.create({ dir: cacheDir, ttl: false }); this.#instance = storage.create({ dir: cacheDir, ttl: false });
await this._instance.init(); await this.#instance.init();
this._removalInterval = setInterval(this._removeCacheEntries.bind(this), 60000); this.#removalInterval = setInterval(this.#removeCacheEntries.bind(this), DiskCache.REMOVAL_INTERVAL);
return this._instance; return this.#instance;
}, }
/** /**
* Queue for removal of cache entries. * Verifies disk cache size and prunes it if necessary.
* @type {Set<string>} * @param {import('../users.js').UserDirectoryList[]} directoriesList List of user directories
* @returns {Promise<void>}
*/ */
removalQueue: new Set(), async verify(directoriesList) {
}; if (!useDiskCache) {
return;
}
/** const cache = await this.instance();
* Verifies disk cache size and prunes it if necessary. const validKeys = [];
* @param {import('../users.js').UserDirectoryList[]} directoriesList List of user directories for (const dir of directoriesList) {
* @returns {Promise<void>} const files = fs.readdirSync(dir.characters);
*/ for (const file of files) {
export async function verifyCharactersDiskCache(directoriesList) { const filePath = path.join(dir.characters, file);
if (!useDiskCache) { const stat = fs.statSync(filePath);
return; validKeys.push(`${filePath}-${stat.mtimeMs}`);
} }
}
const cache = await diskCache.instance(); const cacheKeys = await cache.keys();
const validKeys = []; for (const key of cacheKeys) {
for (const dir of directoriesList) { if (!validKeys.includes(key)) {
const files = fs.readdirSync(dir.characters); await cache.removeItem(key);
for (const file of files) { }
const filePath = path.join(dir.characters, file);
const stat = fs.statSync(filePath);
validKeys.push(`${filePath}-${stat.mtimeMs}`);
} }
} }
const cacheKeys = await cache.keys();
for (const key of cacheKeys) { dispose() {
if (!validKeys.includes(key)) { if (this.#removalInterval) {
await cache.removeItem(key); clearInterval(this.#removalInterval);
} }
} }
} }
export const diskCache = new DiskCache();
/** /**
* Reads the character card from the specified image file. * Reads the character card from the specified image file.
* @param {string} inputFile - Path to the image file * @param {string} inputFile - Path to the image file