UNPKG

@foxpage/foxpage-manager

Version:

foxpage resource manager

303 lines (302 loc) 8.77 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ManagerBaseImpl = void 0; const lodash_1 = __importDefault(require("lodash")); const foxpage_shared_1 = require("@foxpage/foxpage-shared"); const cache_1 = require("../cache"); const common_1 = require("../common"); const event_1 = require("./event"); /** * manager base * * @export * @abstract * @class ManagerBase */ class ManagerBaseImpl extends event_1.FPEventEmitterInstance { constructor(app, opt) { var _a, _b, _c; super(); /** * need update source keys * for record the no update source key, call the thread to refresh next request * @private * @type {string[]} */ this.needUpdates = []; this.appId = app.appId; this.appSlug = app.slug; this.logger = (0, common_1.createLogger)(`App@${app.appId} ${opt === null || opt === void 0 ? void 0 : opt.type}Manager`); // DATA_PULL app.on('DATA_PULL', async (data) => { try { await this.onPull(data || {}); } catch (e) { this.logger.error('DATA_PULL error:', e); } }); // DATA_STASH app.on('DATA_STASH', (data) => { try { this.onStash(data); } catch (e) { this.logger.error('DATA_STASH error:', e); } }); // cache this.hotResources = (0, cache_1.createLRUCache)((_a = opt === null || opt === void 0 ? void 0 : opt.lruCache) === null || _a === void 0 ? void 0 : _a.size, { cloned: (_b = opt === null || opt === void 0 ? void 0 : opt.lruCache) === null || _b === void 0 ? void 0 : _b.cloned }); if ((_c = opt === null || opt === void 0 ? void 0 : opt.diskCache) === null || _c === void 0 ? void 0 : _c.enable) { this.diskResources = (0, cache_1.createDiskCache)({ appId: this.appId, type: `${(opt === null || opt === void 0 ? void 0 : opt.type) || 'default'}s`, logger: this.logger, }); } } /** * DATA_PULL listener * * @protected * @param {ResourceUpdateInfo} _data */ async onPull(_data) { } /** * DATA_STASH listener * * @protected * @param {Relations} _data */ onStash(_data) { } /** * add source * * @protected * @param {string} key * @param {T} content * @param {T} instance */ addOne(key, content, instance) { var _a; // cache content instance to memory this.hotResources.set(key, instance); // cache origin content to disk (_a = this.diskResources) === null || _a === void 0 ? void 0 : _a.set(key, content); // remove no updates this.removeNeedUpdates([key]); } /** * find source from local * find from hot cache, * if not exist will find from disk * @protected * @param {string} key * @return {*} */ async findOneFromLocal(key) { var _a; let resource = this.hotResources.get(key); if (!resource) { resource = await ((_a = this.diskResources) === null || _a === void 0 ? void 0 : _a.get(key)); // will set to hot if (resource) { const resourceInstance = await this.createInstance(resource); this.hotResources.set(key, resourceInstance); return resourceInstance; } } return resource; } /** * * @param key * @returns */ findOne(key) { const resource = this.hotResources.get(key); return resource; } /** * [batch] find all sources from local via source keys * * @protected * @param {string[]} keys * @return {*} */ async findFromLocal(keys) { return (await Promise.all(keys.map(async (key) => { const local = await this.findOneFromLocal(key); if (!local) { this.logger.warn(`not exist the "${key}" content`); return null; } return local; }))).filter(foxpage_shared_1.isNotNill); } /** * remove source * * @protected * @param {string} key */ removeOne(key) { var _a; this.hotResources.delete(key); (_a = this.diskResources) === null || _a === void 0 ? void 0 : _a.delete(key); } /** * [batch] remove all sources from via source keys * * @protected * @param {string[]} keys * @memberof ManagerBaseImpl */ remove(keys) { keys.forEach(key => { this.removeOne(key); }); } /** * check if has the source * * @protected * @param {string} key * @return {*} */ async has(key) { var _a; return this.hotResources.has(key) || (await ((_a = this.diskResources) === null || _a === void 0 ? void 0 : _a.has(key))); } /** * add no updates * * @param {string[]} keys * @protected */ markNeedUpdates(keys = []) { keys.forEach(key => { if (!this.existInNeedUpdates(key)) { this.needUpdates.push(key); } }); } /** * remove the no updates * * @param {string[]} keys * @protected */ removeNeedUpdates(keys = []) { const result = lodash_1.default.remove(this.needUpdates, item => keys.indexOf(item) > -1); this.needUpdates = result; } /** * if exist the no update source * * @protected * @param {string} key * @return {boolean} */ existInNeedUpdates(key) { return this.needUpdates.indexOf(key) > -1; } /** * chunk * if exist local will add to ins, or add to outs * * @protected * @param {string[]} keys * @return {*} {Promise<string[][]>} [ins, outs, invalids] ins(in local), outs(not in local), invalids(in local but is not valid) */ async chunk(keys) { const ins = []; const invalids = []; const outs = []; for (const item of keys) { if (await this.has(item)) { ins.push(item); } else if (this.existInNeedUpdates(item)) { invalids.push(item); } else { outs.push(item); } } return [ins, outs, invalids]; } /** * get sources * first get local source, then fetch outs via fetch func with opt * @protected * @param {string[]} keys * @param {{ autoFetch: boolean }} opt * @return {*} {Promise<T[]>} */ async find(keys, opt = { autoFetch: true, autoCache: true }) { const [ins, outs, invalids] = await this.chunk(keys); const inContents = await this.findFromLocal(ins.concat(invalids)); let outContents; if (opt.autoFetch && outs.length > 0) { this.logger.info('fetch out contents %j from server', outs); // fetch from server via outs outContents = await this.onFetch(outs, opt); } if (invalids.length > 0) { this.logger.info('fetch invalid contents %j from server', invalids); // async fetch invalid sources this.onFetch(invalids, opt); } if (outContents && outContents.length > 0) { return [...inContents, ...outContents]; } return inContents; } /** * filter not exist list * * @protected * @param {string[]} list * @return {*} */ async filterExists(list) { const notExists = []; for (const item of list) { if (await this.exist(item)) { notExists.push(item); } } return notExists; } /** * exist the source * * @param {string} key */ async exist(key) { return !!(await this.has(key)); } /** * memory count */ getHotCount() { return this.hotResources.getCurCount(); } getDiskCount() { var _a; return (_a = this.diskResources) === null || _a === void 0 ? void 0 : _a.getCurCount(); } /** * destroy the resource */ destroy() { var _a; this.hotResources.destroy(); (_a = this.diskResources) === null || _a === void 0 ? void 0 : _a.destroy(); } } exports.ManagerBaseImpl = ManagerBaseImpl;