UNPKG

@foxpage/foxpage-manager

Version:

foxpage resource manager

341 lines (340 loc) 14.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApplicationImpl = void 0; const lodash_1 = __importDefault(require("lodash")); const foxpage_plugin_1 = require("@foxpage/foxpage-plugin"); const foxpage_shared_1 = require("@foxpage/foxpage-shared"); const block_1 = require("../block"); const common_1 = require("../common"); const condition_1 = require("../condition"); const data_service_1 = require("../data-service"); const file_1 = require("../file"); const function_1 = require("../function"); const library_1 = require("../library"); const material_1 = require("../material"); const mock_1 = require("../mock"); const package_1 = require("../package"); const page_1 = require("../page"); const plugin_1 = require("../plugin"); const reporter_1 = require("../reporter"); const router_1 = require("../router"); const security_1 = require("../security"); const tag_1 = require("../tag"); const template_1 = require("../template"); const variable_1 = require("../variable"); const config_1 = require("./config"); const schedule_1 = require("./schedule"); // interface RelationDetail extends Partial<ContentDetail>, CollectionType {} function createSourceUpdateSchedule(app) { const options = { appId: app.appId, interval: app.configs['schedule.interval'] || 40 * 1000, }; const updateTask = async (preData) => { var _a; const preTimestamp = (preData === null || preData === void 0 ? void 0 : preData.timestamp) || -1; // -1 will return all try { let result = await data_service_1.foxpageDataService.fetchContentChanges(app.appId, preTimestamp); if (!result) { result = { contents: {}, timestamp: preTimestamp, }; } result.appId = app.appId; return result; } catch (e) { (_a = app.logger) === null || _a === void 0 ? void 0 : _a.error(e.message); return { appId: app.appId, contents: {}, timestamp: preTimestamp, }; } }; const schedule = new schedule_1.Schedule(updateTask, options); return schedule; } /** * application * same to appContext that contains all resource(content,plugins,hooks...) of this application * @export * @class ApplicationImpl * @extends {AppEventsImpl} * @implements {Application} */ class ApplicationImpl extends common_1.FPEventEmitterInstance { constructor(app, opt) { var _a; super(); this.appId = app.id; this.slug = app.slug; this.app = app; this.setMaxListeners(20); // init configs this.configs = (0, config_1.initAppConfig)(opt.configs); this.hooks = opt.hooks; this.resourceMap = opt.resourceMap; this.reporter = (0, reporter_1.getReporter)(); // init source managers this.fileManager = new file_1.FileManagerImpl(this); this.pageManager = new page_1.PageManagerImpl(this); this.packageManager = new package_1.PackageManagerImpl(this); this.variableManager = new variable_1.VariableManagerImpl(this); this.materialManager = new material_1.MaterialManagerImpl(this); this.conditionManager = new condition_1.ConditionManagerImpl(this); this.templateManager = new template_1.TemplateManagerImpl(this); this.functionManager = new function_1.FunctionManagerImpl(this); this.tagManager = new tag_1.TagManagerImpl(this); this.libraryManager = new library_1.LibraryManagerImpl(this); this.csrPluginManager = new plugin_1.CSRPluginManagerImpl(this); this.mockManager = new mock_1.MockManagerImpl(this); this.routeManager = new router_1.RouterImpl(this); this.blockManager = new block_1.BlockManagerImpl(this); this.securityManager = new security_1.SecurityManagerImpl(this); //ssr plugins this.pluginManager = new plugin_1.PluginManagerImpl({ plugins: opt.plugins, baseDir: opt.pluginDir || '', api: {}, appId: this.appId, }); //logger this.logger = (0, common_1.createLogger)('Application'); // listen push this.initEvents(); if (this.enableSchedule()) { // instance resource update schedule this.schedule = createSourceUpdateSchedule(this); // listen schedule error (_a = this.schedule) === null || _a === void 0 ? void 0 : _a.on('ERROR', error => { this.logger.warn('schedule error:', error); }); } } /** * application prepare * fresh templates and packages */ async prepare() { var _a, _b, _c, _d, _e, _f; const pkgLoadStrategy = ((_a = this.configs.package) === null || _a === void 0 ? void 0 : _a.loadStrategy) || 'all'; const componentCost = (_b = this.reporter) === null || _b === void 0 ? void 0 : _b.cost('componentLoadCost'); await this.packageManager.freshPackages({ strategy: pkgLoadStrategy }); const componentCostTime = componentCost === null || componentCost === void 0 ? void 0 : componentCost(); (_c = this.reporter) === null || _c === void 0 ? void 0 : _c.appReporter(this.appId, 'componentLoadCost', componentCostTime); await this.libraryManager.freshLibraries({ strategy: pkgLoadStrategy }); await this.csrPluginManager.freshPlugins({ strategy: pkgLoadStrategy }); const pluginCost = (_d = this.reporter) === null || _d === void 0 ? void 0 : _d.cost('pluginLoadCost'); this.pluginManager.loadPlugins(); const pluginCostTime = pluginCost === null || pluginCost === void 0 ? void 0 : pluginCost(); (_e = this.reporter) === null || _e === void 0 ? void 0 : _e.appReporter(this.appId, 'pluginLoadCost', pluginCostTime); const hooks = this.pluginManager.getHooks(foxpage_plugin_1.Mode.DISTRIBUTION); const { registerRouter } = hooks || {}; if (typeof registerRouter === 'function') { const routes = (await registerRouter()); if (Array.isArray(routes)) { this.routeManager.register(routes); } else { this.routeManager.register([routes]); } } // schedule if (this.enableSchedule()) { this.logger.info('start process schedule'); this.onScheduled(); (_f = this.schedule) === null || _f === void 0 ? void 0 : _f.start(); } } /** * listen schedule * */ onScheduled() { var _a; const listener = (value) => { var _a; this.logger.info('receive data'); this.logger.debug('receive data:', JSON.stringify(value)); if (value) { if (typeof ((_a = this.hooks) === null || _a === void 0 ? void 0 : _a.sourceUpdateHook) === 'function') { this.hooks.sourceUpdateHook(value); } this.refresh(value); } }; (_a = this.schedule) === null || _a === void 0 ? void 0 : _a.on('DATA_RECEIVE', listener); } /** * get schedule status * * @return {boolean} */ enableSchedule() { return !!this.configs['schedule.enable']; } /** * refresh data * * @param {ResourceUpdateInfo} updateInfos */ async refresh(updateInfos) { if (updateInfos.appId === this.appId) { this.logger.info('refresh source'); this.emit('DATA_PULL', updateInfos.contents); } } /** * get content relation data * contain the deps of variable,condition,functions * @template T * @param {ContentDetail<T>} content * @return {*} {(Promise<RelationInfo | null>)} */ async getContentRelationInfo(content, opt) { const relations = { templates: [], variables: [], materials: [], sysVariables: [], conditions: [], functions: [], blocks: [], libraries: [], plugins: [], }; return await this.getRelations(content, relations, opt); } async getRelations(content, relations, options) { var _a, _b, _c, _d, _e, _f, _g, _h; this.ComposeSysVariable(content, relations); const getter = this.relationGetter(content, relations); const list = [ await getter(foxpage_shared_1.ContentType.TEMPLATE, async (value) => this.templateManager.getTemplates(value)), await getter(foxpage_shared_1.ContentType.VARIABLE, async (value) => this.variableManager.getVariables(value)), await getter(foxpage_shared_1.ContentType.CONDITION, async (value) => this.conditionManager.getConditions(value)), await getter(foxpage_shared_1.ContentType.FUNCTION, async (value) => this.functionManager.getFunctions(value)), await getter(foxpage_shared_1.ContentType.BLOCK, async (value) => this.blockManager.getBlocks(value)), await getter(foxpage_shared_1.PackageType.LIBRARY, async (value) => this.libraryManager.getLibrariesById(value)), await getter(foxpage_shared_1.PackageType.PLUGIN, async (value) => this.csrPluginManager.getPluginsById(value)), ]; if (!(options === null || options === void 0 ? void 0 : options.isBase)) { await getter(foxpage_shared_1.ContentType.MATERIAL, async (value, opt) => this.materialManager.getMaterials(value, opt)); } const result = await Promise.all(list); const collections = {}; result.forEach(item => { item === null || item === void 0 ? void 0 : item.forEach((cont) => { const filter = this.relationFilter(cont, relations, collections); filter(foxpage_shared_1.ContentType.TEMPLATE); filter(foxpage_shared_1.ContentType.VARIABLE); filter(foxpage_shared_1.ContentType.MATERIAL); filter(foxpage_shared_1.ContentType.CONDITION); filter(foxpage_shared_1.ContentType.FUNCTION); filter(foxpage_shared_1.ContentType.BLOCK); filter(foxpage_shared_1.PackageType.LIBRARY); filter(foxpage_shared_1.PackageType.PLUGIN); }); }); if (((_a = collections.templates) === null || _a === void 0 ? void 0 : _a.length) || ((_b = collections.variables) === null || _b === void 0 ? void 0 : _b.length) || ((_c = collections.materials) === null || _c === void 0 ? void 0 : _c.length) || ((_d = collections.conditions) === null || _d === void 0 ? void 0 : _d.length) || ((_e = collections.functions) === null || _e === void 0 ? void 0 : _e.length) || ((_f = collections.blocks) === null || _f === void 0 ? void 0 : _f.length) || ((_g = collections.libraries) === null || _g === void 0 ? void 0 : _g.length) || ((_h = collections.plugins) === null || _h === void 0 ? void 0 : _h.length)) { await this.getRelations(collections, relations); } return relations; } ComposeSysVariable(content, relations) { const list = relations[foxpage_shared_1.ContentType.SYS_VARIABLE] || []; const relationList = content[foxpage_shared_1.ContentType.SYS_VARIABLE]; if (!relationList || relationList.length === 0) { return; } relations[foxpage_shared_1.ContentType.SYS_VARIABLE] = lodash_1.default.union(list, relationList); } relationGetter(content, relations) { return async (key, getter) => { const relationList = relations[key]; const opt = { locale: content.locale, }; const list = content[key]; // dep source id array if (!list || list.length === 0) { return []; } const filtered = list.filter(item => !this.checkRelationIn(relationList, item)); if (filtered.length === 0) { return []; } const result = ((await getter(filtered, opt)) || []); result === null || result === void 0 ? void 0 : result.forEach((item) => { this.ComposeSysVariable(item, relations); if (!this.checkRelationIn(relationList, item.id)) { relationList.push(item); } }); return result; }; } relationFilter(content, relations, collections) { return (key) => { const keyStr = key; const relationList = relations[keyStr]; const list = content[keyStr]; // dep source id array if (!list || list.length === 0) { return []; } if (!collections[keyStr]) { collections[keyStr] = []; } list.forEach(item => { var _a, _b; if (!this.checkRelationIn(relationList, item) && ((_a = collections[keyStr]) === null || _a === void 0 ? void 0 : _a.indexOf(item)) === -1) { (_b = collections[keyStr]) === null || _b === void 0 ? void 0 : _b.push(item); } }); }; } checkRelationIn(list, value) { return list.findIndex(cont => cont.id === value) > -1; } initEvents() { this.tagManager.on('DATA_PUSH', (data) => { this.emit('DATA_STASH', data); }); this.pageManager.on('DATA_PUSH', (data) => { this.emit('DATA_STASH', data); }); } /** * destroy */ destroy() { var _a; this.fileManager.destroy(); this.blockManager.destroy(); this.conditionManager.destroy(); this.functionManager.destroy(); this.packageManager.destroy(); this.pageManager.destroy(); this.tagManager.destroy(); this.templateManager.destroy(); this.variableManager.destroy(); this.materialManager.destroy(); this.pluginManager.destroy(); this.libraryManager.destroy(); this.csrPluginManager.destroy(); this.routeManager.destroy(); (_a = this.schedule) === null || _a === void 0 ? void 0 : _a.stop(); } } exports.ApplicationImpl = ApplicationImpl;