You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
4.0 KiB
TypeScript
109 lines
4.0 KiB
TypeScript
// Copyright (C) 2019-2022 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
(() => {
|
|
const { PluginError } = require('./exceptions');
|
|
|
|
const plugins = [];
|
|
class PluginRegistry {
|
|
static async apiWrapper(wrappedFunc, ...args) {
|
|
// I have to optimize the wrapper
|
|
const pluginList = await PluginRegistry.list();
|
|
for (const plugin of pluginList) {
|
|
const pluginDecorators = plugin.functions.filter((obj) => obj.callback === wrappedFunc)[0];
|
|
if (pluginDecorators && pluginDecorators.enter) {
|
|
try {
|
|
await pluginDecorators.enter.call(this, plugin, ...args);
|
|
} catch (exception) {
|
|
if (exception instanceof PluginError) {
|
|
throw exception;
|
|
} else {
|
|
throw new PluginError(`Exception in plugin ${plugin.name}: ${exception.toString()}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let result = await wrappedFunc.implementation.call(this, ...args);
|
|
|
|
for (const plugin of pluginList) {
|
|
const pluginDecorators = plugin.functions.filter((obj) => obj.callback === wrappedFunc)[0];
|
|
if (pluginDecorators && pluginDecorators.leave) {
|
|
try {
|
|
result = await pluginDecorators.leave.call(this, plugin, result, ...args);
|
|
} catch (exception) {
|
|
if (exception instanceof PluginError) {
|
|
throw exception;
|
|
} else {
|
|
throw new PluginError(`Exception in plugin ${plugin.name}: ${exception.toString()}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Called with cvat context
|
|
static async register(plug) {
|
|
const functions = [];
|
|
|
|
if (typeof plug !== 'object') {
|
|
throw new PluginError(`Plugin should be an object, but got "${typeof plug}"`);
|
|
}
|
|
|
|
if (!('name' in plug) || typeof plug.name !== 'string') {
|
|
throw new PluginError('Plugin must contain a "name" field and it must be a string');
|
|
}
|
|
|
|
if (!('description' in plug) || typeof plug.description !== 'string') {
|
|
throw new PluginError('Plugin must contain a "description" field and it must be a string');
|
|
}
|
|
|
|
if ('functions' in plug) {
|
|
throw new PluginError('Plugin must not contain a "functions" field');
|
|
}
|
|
|
|
function traverse(plugin, api) {
|
|
const decorator = {};
|
|
for (const key in plugin) {
|
|
if (Object.prototype.hasOwnProperty.call(plugin, key)) {
|
|
if (typeof plugin[key] === 'object') {
|
|
if (Object.prototype.hasOwnProperty.call(api, key)) {
|
|
traverse(plugin[key], api[key]);
|
|
}
|
|
} else if (
|
|
['enter', 'leave'].includes(key) &&
|
|
typeof api === 'function' &&
|
|
typeof (plugin[key] === 'function')
|
|
) {
|
|
decorator.callback = api;
|
|
decorator[key] = plugin[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Object.keys(decorator).length) {
|
|
functions.push(decorator);
|
|
}
|
|
}
|
|
|
|
traverse(plug, { cvat: this });
|
|
|
|
Object.defineProperty(plug, 'functions', {
|
|
value: functions,
|
|
writable: false,
|
|
});
|
|
|
|
plugins.push(plug);
|
|
}
|
|
|
|
static async list() {
|
|
return plugins;
|
|
}
|
|
}
|
|
|
|
module.exports = PluginRegistry;
|
|
})();
|