@neo-one/server
Version:
NEO•ONE Server that NEO•ONE CLI and other clients connect to.
640 lines (639 loc) • 98.4 kB
JavaScript
"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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