/**
* @file services/cache.js
* @copyright @spmhome @_2025
* @author Scott Meesseman @spmeesseman
*//** */
const { dirname } = require("path");
const { writeFile } = require("fs/promises");
const { createDirSync, existsSync, resolvePath, writeFileSync, readFileSync } = require("@spmhome/cmn-utils");
const { merge, clone, safeStringify, cryptoUtils, safeParse, create: createObj } = require("@spmhome/type-utils");
/**
* @class WpwCache
* @implements {IDisposable}
*/
class WpwCache
{
/**
* @type {WpwCrypto}
*/
_crypto;
/**
* @private
* @type {Record<string, any>}
*/
_store;
/**
* @private
* @type {string}
*/
_file;
/**
* @type {WpwLogger}
*/
_logger;
/**
* @param {WpwCacheOptions} options
*/
constructor(options)
{
this._logger = options.logger;
this._crypto = merge({ type: "none" }, options.crypto);
const fileName = options.slug.replace(/\.json$/, "").replace(/^\./, "");
this._file = resolvePath(options.dir, `.${fileName}`);
this._store = this.read();
}
/**
* @returns {Record<string, any>}
*/
get data() { return this._store; }
dispose() { /* this.saveAsync(); */ }
/**
* @param {string} data
* @returns {string}
*/
decrypt(data)
{
if (this._crypto.type === "none") {
return data;
}
if (this._crypto.strength === "256-bit") {
return cryptoUtils.decryptAes256(this._crypto.key, data);
}
return cryptoUtils.decryptAes128(this._crypto.key, data);
}
/**
* @param {string} data
* @returns {string}
*/
encrypt(data)
{
if (this._crypto.type === "none") {
return data;
} if (this._crypto.strength === "256-bit") {
return cryptoUtils.encryptAes256(this._crypto.key, data);
} return cryptoUtils.encryptAes128(this._crypto.key, data);
}
/**
* @template D
* @overload
* @param {string} item
* @returns {D | undefined}
*/
/**
* @template D
* @overload
* @param {string} item
* @param {D} defValue
* @returns {D}
*/
/**
* @template D
* @param {string} item
* @param {D} [defValue]
* @returns {D | undefined}
*/
get(item, defValue) { return this._store[item] ? clone(this._store[item]) : defValue; }
/**
* @returns {Record<string, any>}
*/
read()
{
if (!existsSync(dirname(this._file)))
{
createDirSync(dirname(this._file));
}
if (!existsSync(this._file))
{
writeFileSync(this._file, this.encrypt("{}"));
}
try {
return safeParse(this.decrypt(readFileSync(this._file)));
}
catch (e)
{ this._logger.error(e);
writeFileSync(this._file, this.encrypt("{}"));
}
return createObj();
};
/**
* @param {Record<string, any>} [store] The _store, as a JSON object
*/
reset(store) { this._store = createObj(store); this.save(); };
/**
* @param {Record<string, any>} store The _store, as a JSON object
* @returns {Promise<void>}
*/
resetAsync(store) { this._store = createObj(store); return this.saveAsync(); };
save() { writeFileSync(this._file, this.encrypt(safeStringify(this._store))); }
/**
* @returns {Promise<void>}
*/
saveAsync() { return writeFile(this._file, this.encrypt(safeStringify(this._store))); }
/**
* @param {Record<string, any>} cacheObj The _store, as a JSON object
*/
set(cacheObj) { merge(this._store, cacheObj); this.save(); };
/**
* @param {Record<string, any>} cacheObj The _store, as a JSON object
* @returns {Promise<void>}
*/
setAsync(cacheObj) { merge(this._store, cacheObj); return this.saveAsync(); };
}
module.exports = WpwCache;