UNPKG

@neo-one/server

Version:

NEO•ONE Server that NEO•ONE CLI and other clients connect to.

640 lines (639 loc) 98.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const server_plugin_1 = require("@neo-one/server-plugin"); const utils_1 = require("@neo-one/utils"); const fs = tslib_1.__importStar(require("fs-extra")); const lodash_1 = tslib_1.__importDefault(require("lodash")); const path = tslib_1.__importStar(require("path")); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const errors_1 = require("./errors"); const Ready_1 = require("./Ready"); const RESOURCES_PATH = 'resources'; const RESOURCES_READY_PATH = 'ready'; const DIRECT_DEPENDENTS_PATH = 'dependents'; const DEPENDENCIES_PATH = 'dependencies'; class ResourcesManager { constructor({ monitor, dataPath, pluginManager, resourceType, masterResourceAdapter, portAllocator, }) { this.monitor = monitor.at('resources_manager').withLabels({ [utils_1.labels.PLUGIN_NAME]: resourceType.plugin.name, [utils_1.labels.RESOURCETYPE_NAME]: resourceType.name, }); this.pluginManager = pluginManager; this.resourceType = resourceType; this.masterResourceAdapter = masterResourceAdapter; this.portAllocator = portAllocator; this.plugin = this.resourceType.plugin; this.resourceAdapters$ = new rxjs_1.BehaviorSubject({}); this.mutableDirectResourceDependents = {}; this.mutableResourceDependents = {}; this.mutableCreateHooks = []; this.resourcesPath = path.resolve(dataPath, RESOURCES_PATH); this.resourcesReady = new Ready_1.Ready({ dir: path.resolve(dataPath, RESOURCES_READY_PATH), }); this.directDependentsPath = path.resolve(dataPath, DIRECT_DEPENDENTS_PATH); this.dependenciesPath = path.resolve(dataPath, DEPENDENCIES_PATH); this.mutableCreateTaskList = {}; this.mutableDeleteTaskList = {}; this.mutableStartTaskList = {}; this.mutableStopTaskList = {}; this.mutableResourceAdaptersStarted = {}; this.resources$ = this.resourceAdapters$.pipe(operators_1.switchMap((resourceAdapters) => { const adapters = Object.values(resourceAdapters); if (adapters.length === 0) { return rxjs_1.of([]); } return rxjs_1.combineLatest(adapters.map((adapter) => adapter.resource$)); }), operators_1.shareReplay(1)); } get resourceAdapters() { return this.resourceAdapters$.getValue(); } async reset() { await this.destroy(); } async destroy() { await this.monitor.captureLog(async () => { await Promise.all(Object.entries(this.resourceAdapters).map(async ([name, resourceAdapter]) => { await this.stop(name, {}) .toPromise() .catch(() => { }); await this.destroyName(name, resourceAdapter).catch(() => { }); })); }, { name: 'neo_resource_manager_destroy', message: `Destroyed resource manager for ${this.plugin.name} ${this.resourceType.name}`, }); } getResources$(options) { return this.resources$.pipe(operators_1.map((resources) => this.resourceType.filterResources(resources, options))); } getResource$({ name, options, }) { return this.getResources$(options).pipe(operators_1.map((resources) => resources.find((resource) => resource.name === name))); } async getResource({ name, options, }) { return this.getResource$({ name, options }) .pipe(operators_1.filter(utils_1.utils.notNull), operators_1.take(1), operators_1.timeout(500)) .toPromise(); } create(name, options) { const { create, start } = this.resourceType.getCRUD(); const taskList = this.mutableCreateTaskList[name]; const shouldSkip = taskList !== undefined; const resourceAdapter = this.resourceAdapters[name]; const skip = () => shouldSkip || resourceAdapter !== undefined; const mainSkip = () => { if (shouldSkip) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} is already being ${create.names.ed}.`; } if (resourceAdapter !== undefined) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} already exists.`; } return false; }; let startTask; if (create.startOnCreate && start !== undefined) { startTask = { title: `${start.names.upper} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip, enabled: () => create.startOnCreate, task: () => this.start(name, options), }; } let set = false; const setFromContext = (ctx) => { if (!set) { set = true; if (ctx.resourceAdapter != undefined) { this.resourceAdapters$.next(Object.assign({}, this.resourceAdapters, { [name]: ctx.resourceAdapter })); const dependencies = ctx.dependencies === undefined ? [] : ctx.dependencies; const dependents = ctx.dependents == undefined ? [] : ctx.dependents; this.mutableDirectResourceDependents[name] = dependents; this.addDependents({ name, dependencies }); } } }; const createTaskList = new server_plugin_1.TaskList({ freshContext: true, collapse: false, tasks: [ { title: `${create.names.upper} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip: mainSkip, task: () => this.masterResourceAdapter.createResourceAdapter({ name, dataPath: path.resolve(this.resourcesPath, name), }, options), }, { title: 'Execute final setup', skip, task: async (ctx) => { setFromContext(ctx); await this.getResource$({ name, options: {} }) .pipe(operators_1.filter((value) => value !== undefined), operators_1.take(1)) .toPromise(); const dependencies = ctx.dependencies === undefined ? [] : ctx.dependencies; const dependents = ctx.dependents === undefined ? [] : ctx.dependents; await Promise.all([ this.resourcesReady.write(name), fs.writeJSON(this.getDependenciesPath(name), dependencies), fs.writeJSON(this.getDirectDependentsPath(name), dependents), ]); }, }, startTask, { title: 'Execute plugin hooks', skip, enabled: () => this.mutableCreateHooks.length > 0, task: () => new server_plugin_1.TaskList({ tasks: this.mutableCreateHooks.map((hook) => hook({ name, options, pluginManager: this.pluginManager, })), concurrent: true, collapse: false, }), }, ].filter(utils_1.utils.notNull), onError: (_error, ctx) => { if (!shouldSkip) { setFromContext(ctx); } }, onDone: (failed) => { if (!shouldSkip) { delete this.mutableCreateTaskList[name]; if (failed) { this.delete(name, options) .toPromise() .catch(() => { }); } } }, }); if (!shouldSkip) { this.mutableCreateTaskList[name] = createTaskList; } return createTaskList; } delete(name, options) { const deleteTask = this.mutableDeleteTaskList[name]; const shouldSkip = deleteTask !== undefined; const { create, start, stop, delete: del } = this.resourceType.getCRUD(); const startTaskList = this.mutableStartTaskList[name]; const mutableStartStopTasks = []; if (start !== undefined) { mutableStartStopTasks.push({ title: `Abort ${start.names.ing} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, enabled: () => startTaskList !== undefined, task: async () => { if (startTaskList !== undefined) { await startTaskList.abort(); } }, }); } if (stop !== undefined) { mutableStartStopTasks.push({ title: `${stop.names.upper} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, enabled: () => this.mutableResourceAdaptersStarted[name], task: () => this.stop(name, options), }); } const createTaskList = this.mutableCreateTaskList[name]; const resourceAdapter = this.resourceAdapters[name]; const skip = () => shouldSkip || resourceAdapter === undefined; const mainSkip = () => { if (shouldSkip) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} is already being ${del.names.ed}.`; } if (resourceAdapter === undefined) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} does not exist.`; } return false; }; const resourceDependents = this.mutableResourceDependents[name]; const directResourceDependents = this.mutableDirectResourceDependents[name]; const dependents = this.uniqueDeps((resourceDependents === undefined ? [] : resourceDependents).concat(directResourceDependents === undefined ? [] : directResourceDependents)); const abortTasks = [ { title: `Abort ${create.names.ing} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, enabled: () => createTaskList !== undefined, task: async () => { if (createTaskList !== undefined) { await createTaskList.abort(); } }, }, ]; const deleteTaskList = new server_plugin_1.TaskList({ freshContext: true, collapse: false, tasks: abortTasks.concat(mutableStartStopTasks).concat([ { title: 'Delete dependent resources', enabled: () => dependents.length > 0, skip, task: () => this.deleteDeps(dependents), }, { title: `${del.names.upper} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip, task: () => { if (resourceAdapter !== undefined) { return resourceAdapter.delete(options); } return undefined; }, }, { title: 'Execute final cleanup', skip: mainSkip, task: async () => { await this.destroyName(name, resourceAdapter); this.portAllocator.releasePort({ plugin: this.plugin.name, resourceType: this.resourceType.name, resource: name, }); await Promise.all([ this.resourcesReady.delete(name), fs.remove(this.getDependenciesPath(name)), fs.remove(this.getDirectDependentsPath(name)), ]); delete this.mutableResourceDependents[name]; delete this.mutableDirectResourceDependents[name]; }, }, ]), onDone: () => { if (!shouldSkip) { delete this.mutableDeleteTaskList[name]; } }, }); if (!shouldSkip) { this.mutableDeleteTaskList[name] = deleteTaskList; } return deleteTaskList; } start(name, options) { const { create, start, stop } = this.resourceType.getCRUD(); if (start === undefined) { throw new errors_1.ResourceNoStartError({ plugin: this.plugin.name, resourceType: this.resourceType.names.lower, }); } if (stop === undefined) { throw new errors_1.ResourceNoStopError({ plugin: this.plugin.name, resourceType: this.resourceType.names.lower, }); } const startTaskListName = this.mutableStartTaskList[name]; const shouldSkip = startTaskListName !== undefined; const stopTaskList = this.mutableStopTaskList[name]; const resourceAdapter = this.resourceAdapters[name]; const started = this.mutableResourceAdaptersStarted[name]; const directDependents = this.getStartDeps(this.mutableDirectResourceDependents[name]); const startTaskList = new server_plugin_1.TaskList({ freshContext: true, collapse: false, tasks: [ { title: `Abort ${stop.names.ing} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip: () => shouldSkip, enabled: () => stopTaskList !== undefined, task: async () => { if (stopTaskList !== undefined) { await stopTaskList.abort(); } }, }, { title: 'Start created resources', enabled: () => directDependents.length > 0, skip: () => shouldSkip || resourceAdapter === undefined || started, task: () => this.startDeps(directDependents), }, { title: `${start.names.upper} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip: () => { if (shouldSkip) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} is already being ${start.names.ed}.`; } if (resourceAdapter === undefined) { return (`${this.resourceType.names.capital} ${this.getSimpleName(name)} does not exist. ` + `Try ${create.names.ing} it first. From the command line: ` + `${create.name} ${this.resourceType.name} <name>`); } if (started) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} has already been ${start.names.ed}`; } return false; }, task: () => { if (resourceAdapter !== undefined) { return resourceAdapter.start(options); } return undefined; }, }, ], onDone: (failed) => { if (!shouldSkip) { this.mutableResourceAdaptersStarted[name] = true; delete this.mutableStartTaskList[name]; if (failed) { this.stop(name, options) .toPromise() .catch(() => { }); } } }, }); if (!shouldSkip) { this.mutableStartTaskList[name] = startTaskList; } return startTaskList; } stop(name, options) { const { start, stop } = this.resourceType.getCRUD(); if (start === undefined) { throw new errors_1.ResourceNoStartError({ plugin: this.plugin.name, resourceType: this.resourceType.names.lower, }); } if (stop === undefined) { throw new errors_1.ResourceNoStopError({ plugin: this.plugin.name, resourceType: this.resourceType.names.lower, }); } const stopTaskListName = this.mutableStopTaskList[name]; const shouldSkip = stopTaskListName !== undefined; const startTaskList = this.mutableStartTaskList[name]; const resourceAdapter = this.resourceAdapters[name]; const skip = () => shouldSkip || resourceAdapter === undefined; const mainSkip = () => { if (shouldSkip) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} is already being ${stop.names.ed}.`; } if (resourceAdapter === undefined) { return `${this.resourceType.names.capital} ${this.getSimpleName(name)} does not exist.`; } return false; }; const dependents = this.getStopDeps(this.mutableResourceDependents[name]); const directDependents = this.getStopDeps(this.mutableDirectResourceDependents[name]); const stopTaskList = new server_plugin_1.TaskList({ freshContext: true, collapse: false, tasks: [ { title: `Abort ${start.names.ing} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip, enabled: () => startTaskList !== undefined, task: async () => { if (startTaskList !== undefined) { await startTaskList.abort(); } }, }, { title: 'Stop dependent resources', enabled: () => dependents.length > 0, skip: mainSkip, task: () => this.stopDeps(dependents), }, { title: `${stop.names.upper} ${this.resourceType.names.lower} ${this.getSimpleName(name)}`, skip, task: () => { if (resourceAdapter !== undefined) { return resourceAdapter.stop(options); } return undefined; }, }, { title: 'Stop created resources', enabled: () => directDependents.length > 0, skip, task: () => this.stopDeps(directDependents), }, ], onComplete: () => { this.mutableResourceAdaptersStarted[name] = false; }, onDone: () => { if (!shouldSkip) { delete this.mutableStopTaskList[name]; } }, }); if (!shouldSkip) { this.mutableStopTaskList[name] = stopTaskList; } return stopTaskList; } addDependent(name, dependent) { const resourceDependents = this.mutableResourceDependents[name]; if (resourceDependents === undefined) { this.mutableResourceDependents[name] = []; } this.mutableResourceDependents[name].push(dependent); } addCreateHook(hook) { this.mutableCreateHooks.push(hook); } getResourceAdapter(name) { const adapter = this.resourceAdapters[name]; if (adapter === undefined) { throw new Error(`${this.resourceType.names.capital} ${name} does not exist`); } return adapter; } getDebug() { return Object.entries(this.resourceAdapters).map(([name, adapter]) => [name, { type: 'describe', table: adapter.getDebug() }]); } async init() { return this.monitor.captureLog(async () => { await Promise.all([ fs.ensureDir(this.resourcesPath), fs.ensureDir(this.resourcesReady.dir), fs.ensureDir(this.directDependentsPath), fs.ensureDir(this.dependenciesPath), ]); const resources = await this.resourcesReady.getAll(); const foundResourceAdapters = new Set(); resources.forEach((name) => { if (foundResourceAdapters.has(name)) { throw new Error(`Something went wrong, found duplicate resource name: ${this.getSimpleName(name)}`); } foundResourceAdapters.add(name); }); this.resourceAdapters$.next({}); const results = await Promise.all(resources.map(async (name) => { try { const [dependencies, dependents] = await Promise.all([ this.readDeps(this.getDependenciesPath(name)), this.readDeps(this.getDirectDependentsPath(name)), this.initName(name), ]); this.mutableDirectResourceDependents[name] = [...dependents]; this.addDependents({ name, dependencies }); return undefined; } catch (error) { return { resourceType: this.resourceType.name, resource: name, error, }; } })); return results.filter(utils_1.utils.notNull); }, { name: 'neo_resource_manager_inititalize', message: 'Initializing resource manager.', error: 'Failed to initialize resource manager.', }); } async initName(name) { const resourceAdapter = await this.masterResourceAdapter.initResourceAdapter({ name, dataPath: path.resolve(this.resourcesPath, name), }); this.resourceAdapters$.next(Object.assign({}, this.resourceAdapters, { [name]: resourceAdapter })); } async readDeps(depsPath) { try { const deps = await fs.readJSON(depsPath); return deps; } catch (error) { if (error.code === 'ENOENT') { return []; } throw error; } } deleteDeps(deps) { return new server_plugin_1.TaskList({ tasks: deps.map(({ plugin, resourceType, name: dependentName }) => { const manager = this.pluginManager.getResourcesManager({ plugin, resourceType, }); const dependentResourceType = manager.resourceType; return { title: `${dependentResourceType.getCRUD().delete.names.upper} ${dependentResourceType.names.lower} ${this.getSimpleName(dependentName)}`, task: () => manager.delete(dependentName, {}), }; }), concurrent: true, }); } getStartDeps(deps) { return (deps === undefined ? [] : deps).filter(({ plugin, resourceType }) => this.pluginManager .getResourcesManager({ plugin, resourceType, }) .resourceType.getCRUD().start !== undefined); } startDeps(deps) { return new server_plugin_1.TaskList({ tasks: deps.map(({ plugin, resourceType, name: dependentName }) => { const manager = this.pluginManager.getResourcesManager({ plugin, resourceType, }); const dependentResourceType = manager.resourceType; const { start: depStart } = dependentResourceType.getCRUD(); if (depStart === undefined) { throw new Error('For Flow'); } return { title: `${depStart.names.upper} ${dependentResourceType.names.lower} ${this.getSimpleName(dependentName)}`, task: () => manager.start(dependentName, {}), }; }), concurrent: false, }); } getStopDeps(deps) { return (deps === undefined ? [] : deps).filter(({ plugin, resourceType }) => this.pluginManager .getResourcesManager({ plugin, resourceType, }) .resourceType.getCRUD().stop !== undefined); } stopDeps(deps) { return new server_plugin_1.TaskList({ tasks: deps.map(({ plugin, resourceType, name: dependentName }) => { const manager = this.pluginManager.getResourcesManager({ plugin, resourceType, }); const dependentResourceType = manager.resourceType; const { stop: depStop } = dependentResourceType.getCRUD(); if (depStop === undefined) { throw new Error('For Flow'); } return { title: `${depStop.names.upper} ${dependentResourceType.names.lower} ${this.getSimpleName(dependentName)}`, task: () => manager.stop(dependentName, {}), }; }), concurrent: true, }); } async destroyName(name, resourceAdapter) { const mutableResourceAdapters = Object.assign({}, this.resourceAdapters); delete mutableResourceAdapters[name]; this.resourceAdapters$.next(mutableResourceAdapters); await resourceAdapter.destroy(); } getSimpleName(nameIn) { return server_plugin_1.compoundName.extract(nameIn).name; } getDirectDependentsPath(name) { return path.resolve(this.directDependentsPath, `${name}.json`); } getDependenciesPath(name) { return path.resolve(this.dependenciesPath, `${name}.json`); } addDependents({ name: nameIn, dependencies, }) { dependencies.forEach(({ plugin, resourceType, name }) => { this.pluginManager .getResourcesManager({ plugin, resourceType, }) .addDependent(name, { plugin: this.plugin.name, resourceType: this.resourceType.name, name: nameIn, }); }); } uniqueDeps(deps) { return lodash_1.default.uniqBy(deps, ({ plugin, resourceType, name }) => `${plugin}:${resourceType}:${name}`); } } exports.ResourcesManager = ResourcesManager; //# sourceMappingURL=data:application/json;charset=utf8;base64,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