@foxpage/foxpage-manager
Version:
foxpage resource manager
341 lines (340 loc) • 14.7 kB
JavaScript
"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;