@foxpage/foxpage-manager
Version:
foxpage resource manager
405 lines (404 loc) • 13.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LibraryManagerImpl = void 0;
const foxpage_shared_1 = require("@foxpage/foxpage-shared");
const common_1 = require("../common");
const data_service_1 = require("../data-service");
const library_1 = require("./library");
/**
* library manager
* library
*
* @export
* @class PackageManager
*/
class LibraryManagerImpl extends common_1.ManagerBaseImpl {
constructor(app) {
super(app, { type: 'library', diskCache: { enable: true }, lruCache: { cloned: false } });
/**
* cache library name & versions
* key: library name, value: version list
* @private
*/
this.libraryVersionsMap = new Map();
/**
* library id map
* key: library id, value: library name
*
* @private
*/
this.libraryIdMap = new Map();
this.generateKey = (name, version) => {
return foxpage_shared_1.packager.generateKey(name, version);
};
this.splitKey = (key) => {
return foxpage_shared_1.packager.splitKey(key);
};
this.resourceConfig = app.resourceMap;
this.config = app.configs.package || {};
}
/**
* add library to manager
*
* @param {PrePackage} pkg
*/
addLibrary(pkg) {
const { id, name, version } = pkg;
this.logger.info(`add library ${name}@${version}`);
if (!version) {
this.logger.warn('library version is invalid');
return null;
}
const newPkg = this.newLibrary(pkg);
this.addOne(newPkg.key, pkg, newPkg);
this.updateLibraryVersionsMap(pkg);
this.updateLibraryLiveVersion(pkg);
this.libraryIdMap.set(id, name);
return newPkg;
}
/**
* remove library from manager via library names
*
* @param {string[]} names library names
*/
removeLibraries(names) {
const versionInfo = this.getLibraryVersionsByNames(names);
Object.keys(versionInfo).forEach(name => {
var _a;
const versions = versionInfo[name];
if (versions) {
this.remove(versions.map(item => this.generateKey(name, item)));
}
const libraryId = (_a = this.libraryVersionsMap.get(name)) === null || _a === void 0 ? void 0 : _a.id;
if (libraryId) {
this.libraryIdMap.delete(libraryId);
}
this.libraryVersionsMap.delete(name);
});
}
/**
* get library by library name
* will return the live versions
* @param {string} type
* @return {*} {PrePackage | undefined}
*/
async getLibrary(name) {
return (await this.getLibraries([name]))[0];
}
/**
* get all libraries by library names
* will return the live versions
* @param {string[]} names
* @return {*} {Promise<PrePackage[]>}
*/
async getLibraries(names) {
const keys = names.map(name => {
const liveVersion = this.getLibraryLiveVersion(name);
return this.generateKey(name, liveVersion || '');
});
return await this.find(keys);
}
/**
* get libraries by id
* @param ids library ids
* @returns
*/
async getLibrariesById(ids) {
const keys = ids
.map(id => {
const name = this.libraryIdMap.get(id);
if (name) {
const liveVersion = this.getLibraryLiveVersion(name);
return this.generateKey(name, liveVersion || '');
}
})
.filter(foxpage_shared_1.isNotNill);
return await this.find(keys);
}
/**
* select one version
*
* @param {string} name library name
* @return {*}
*/
getLibraryLiveVersion(name) {
var _a;
return (_a = this.libraryVersionsMap.get(name)) === null || _a === void 0 ? void 0 : _a.liveVersion;
}
/**
* update library live version
*
* @param {string} pkg library content
*/
updateLibraryLiveVersion(pkg) {
if (pkg.isLive) {
const pkgInfo = this.libraryVersionsMap.get(pkg.name);
if (pkgInfo) {
pkgInfo.liveVersion = pkg.version;
}
}
}
/**
* get library sync from hot
* @param name library name
* @param version library version
* @returns pkg
*/
getLibrarySync(name, version) {
const versions = this.getLibraryVersionsByNames([name])[name];
if (!versions) {
return null;
}
if (version && versions.indexOf(version) === -1) {
this.logger.warn(`get local library: ${name}@${version} is empty.`);
return null;
}
// !version use live version, or use appoint version
let curVersion = this.getLibraryLiveVersion(name);
if (version && version !== curVersion) {
this.logger.info(`library ${name} local live version is: ${curVersion}, appoint version is: ${version}`);
curVersion = version;
}
if (!curVersion) {
this.logger.warn(`library ${name} version is invalid`);
return null;
}
const key = this.generateKey(name, curVersion);
const pkg = this.findOne(key);
if (!pkg || pkg.version !== curVersion) {
this.logger.warn(`get local library: ${key} is empty.`);
return null;
}
// this.logger.info(`get local library: ${key} succeed.`);
return pkg;
}
/**
* get local library
*
* @param {string} name library name
* @param {string} version library version
* @return {*} {(PrePackage | null)}
*/
async getLocalLibrary(name, version) {
const versions = this.getLibraryVersionsByNames([name])[name];
if (!versions) {
return null;
}
if (version && versions.indexOf(version) === -1) {
this.logger.warn(`get local library: ${name}@${version} is empty.`);
return null;
}
// !version use live version, or use appoint version
let curVersion = this.getLibraryLiveVersion(name);
if (version && version !== curVersion) {
this.logger.info(`library ${name} local live version is: ${curVersion}, appoint version is: ${version}`);
curVersion = version;
}
if (!curVersion) {
this.logger.warn(`library ${name} version is invalid`);
return null;
}
const key = this.generateKey(name, curVersion);
const pkg = await this.findOneFromLocal(key);
if (!pkg || pkg.version !== curVersion) {
this.logger.warn(`get local library: ${key} is empty.`);
return null;
}
// this.logger.info(`get local library: ${key} succeed.`);
return pkg;
}
/**
* fetch libraries, instance libraries and install libraries then add to local
* note: return contains library dependencies contents
* @param {PackageFreshOption} [params]
* @return {*}
*/
async freshLibraries(params) {
const libraries = (params === null || params === void 0 ? void 0 : params.namedVersions)
? this.resolveLibrary(await this.fetchLibrariesByNamedVersions(params.namedVersions))
: await this.fetchLibraries(params === null || params === void 0 ? void 0 : params.packageIds, { strategy: params === null || params === void 0 ? void 0 : params.strategy });
return await this.install(libraries, { cache: true });
}
/**
* install libraries
*
* @param {FPPackage[]} libraries
* @param {{ cache: boolean; ignoreLocal:boolean }} [opt] {cache: will add libraries instance to manager}
* @return {*}
*/
async install(libraries, opt) {
const installs = await this.initInstalls(libraries, opt);
return installs;
}
/**
* fetch libraries from server
*
* @param {string[]} [libraryIds]
* @return {*}
*/
async fetchLibraries(packageIds, opt = {}) {
var _a;
return await data_service_1.foxpageDataService.fetchLibraries(this.appId, Object.assign(Object.assign({ packageIds }, opt), { semver: (_a = this.config) === null || _a === void 0 ? void 0 : _a.version }));
}
/**
* fetch libraries with name and version from server
*
* @param {PackageNamedVersion[]} nameVersions
* @param {PackageFreshOption} opt {isCanary,...}
* @return {Promise<FPPackageResponse[]>}
*/
async fetchLibrariesByNamedVersions(nameVersions, opt) {
var _a;
return await data_service_1.foxpageDataService.fetchLibrariesByNamedVersions(this.appId, {
nameVersions,
isCanary: opt === null || opt === void 0 ? void 0 : opt.isCanary,
semver: (_a = this.config) === null || _a === void 0 ? void 0 : _a.version,
});
}
/**
* listen the "ON_PULL" event
* updates & removes is the library content id list
* @protected
* @param {ResourceUpdateInfo} data
* @return {*} {Promise<void>}
*/
async onPull(data) {
const { updates, removes } = data.library || {};
if (updates && updates.length > 0) {
// this.markNeedUpdates(updates);
await this.freshLibraries({ packageIds: updates });
}
if (removes && removes.length > 0) {
this.removeLibraries(removes.map(item => this.libraryIdMap.get(item)).filter(foxpage_shared_1.isNotNill));
}
}
/**
* on stash
* @param data
*/
onStash(data) {
var _a;
(_a = data.libraries) === null || _a === void 0 ? void 0 : _a.map(item => {
this.addLibrary(item);
});
}
/**
* on fetch
* list: the manager keys
* @protected
* @param {string[]} list
* @return {*} {Promise<PackageImpl[]>}
*/
async onFetch(list) {
return await this.freshLibraries({
namedVersions: list.map(item => {
const [name, version] = this.splitKey(item);
return { name, version };
}),
});
}
async createInstance(data) {
const instance = this.newLibrary(data);
// await instance.install();
return instance;
}
newLibrary(data) {
return new library_1.LibraryInstance(data, {
appId: this.appId,
appSlug: this.appSlug,
resource: this.resourceConfig,
logger: this.logger,
});
}
resolveLibrary(libraryInfos) {
return libraryInfos.map(item => item.package);
}
/**
* init need install libraries instances
*
* @private
* @param {FPPackage[]} libraries
* @param {{ cache: boolean, ignoreLocal:boolean }} [opt]
* @return {*}
*/
async initInstalls(libraries, opt) {
var _a;
const installMap = new Map();
const { cache = false, ignoreLocal = false } = opt || {};
const create = async (list, { initDependencies } = { initDependencies: false }) => {
for (const pkg of list) {
const { name, version, components } = pkg;
const key = this.generateKey(name, version);
const localPkg = !ignoreLocal ? await this.getLocalLibrary(name, version) : null;
// will install it
if (!localPkg && !installMap.has(key)) {
let newPkg;
if (cache) {
newPkg = await this.addLibrary(pkg);
}
else {
newPkg = this.newLibrary(pkg);
}
if (newPkg) {
installMap.set(key, newPkg);
}
}
else {
if (cache) {
this.updateLibraryLiveVersion(pkg);
}
}
// init components
// components: the dependencies contents
if (initDependencies && (components === null || components === void 0 ? void 0 : components.length)) {
await create(components);
}
}
};
try {
await create(libraries, { initDependencies: true });
}
catch (e) {
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`install libraries failed: `, e);
}
return Array.from(installMap.values());
}
/**
* get library versions
*
* @private
* @param {string[]} names library names
* @return {*} {[key]: library name, [value]: versions}
*/
getLibraryVersionsByNames(names) {
const versionInfo = {};
names.forEach(name => {
const { versions } = this.libraryVersionsMap.get(name) || {};
if (!versions) {
// this.logger.warn(`not exist the library@${name} in libraryMap`);
versionInfo[name] = null;
}
else {
versionInfo[name] = versions;
}
});
return versionInfo;
}
updateLibraryVersionsMap(pkg) {
const { id, name, version } = pkg;
const { versions } = this.libraryVersionsMap.get(name) || {};
if (versions) {
versions.push(version);
}
else {
this.libraryVersionsMap.set(name, { id, liveVersion: '', versions: [version] });
this.updateLibraryLiveVersion(pkg);
}
}
destroy() {
super.destroy();
this.libraryIdMap.clear();
this.libraryVersionsMap.clear();
}
}
exports.LibraryManagerImpl = LibraryManagerImpl;