skayn-trading-sdk
Version:
Professional Bitcoin trading strategy backtesting framework with institutional-grade architecture
192 lines (162 loc) • 4.89 kB
JavaScript
/**
* Plugin Registry System
* Central registry for all pluggable components in the trading framework
*/
class PluginRegistry {
constructor() {
this.plugins = new Map();
this.instances = new Map();
this.dependencies = new Map();
this.hooks = new Map();
}
/**
* Register a plugin type and its interface
*/
registerPluginType(type, interfaceClass, config = {}) {
this.plugins.set(type, {
interface: interfaceClass,
implementations: new Map(),
config: {
singleton: config.singleton || false,
required: config.required || false,
dependencies: config.dependencies || []
}
});
}
/**
* Register a plugin implementation
*/
registerPlugin(type, name, pluginClass, metadata = {}) {
if (!this.plugins.has(type)) {
throw new Error(`Plugin type '${type}' not registered. Register the type first.`);
}
const plugin = this.plugins.get(type);
// Validate plugin implements required interface
if (!this.validateInterface(pluginClass, plugin.interface)) {
throw new Error(`Plugin '${name}' does not implement required interface for type '${type}'`);
}
plugin.implementations.set(name, {
class: pluginClass,
metadata: {
name,
version: metadata.version || '1.0.0',
description: metadata.description || '',
author: metadata.author || 'Unknown',
dependencies: metadata.dependencies || [],
...metadata
}
});
console.log(`🔌 Registered plugin: ${type}/${name} v${metadata.version || '1.0.0'}`);
}
/**
* Get plugin instance (with dependency injection)
*/
getInstance(type, name, config = {}) {
const instanceKey = `${type}:${name}`;
// Return existing instance if singleton
const pluginType = this.plugins.get(type);
if (pluginType?.config.singleton && this.instances.has(instanceKey)) {
return this.instances.get(instanceKey);
}
if (!this.plugins.has(type)) {
throw new Error(`Plugin type '${type}' not registered`);
}
const plugin = this.plugins.get(type);
if (!plugin.implementations.has(name)) {
throw new Error(`Plugin '${name}' not found for type '${type}'`);
}
const implementation = plugin.implementations.get(name);
// Resolve dependencies
const dependencies = this.resolveDependencies(implementation.metadata.dependencies);
// Create instance with dependency injection
const instance = new implementation.class(config, dependencies);
// Cache if singleton
if (pluginType.config.singleton) {
this.instances.set(instanceKey, instance);
}
return instance;
}
/**
* List available plugins for a type
*/
listPlugins(type) {
if (!this.plugins.has(type)) {
return [];
}
const plugin = this.plugins.get(type);
return Array.from(plugin.implementations.entries()).map(([name, impl]) => ({
name,
...impl.metadata
}));
}
/**
* Check if plugin exists
*/
hasPlugin(type, name) {
return this.plugins.has(type) &&
this.plugins.get(type).implementations.has(name);
}
/**
* Validate plugin implements interface
*/
validateInterface(pluginClass, interfaceClass) {
const requiredMethods = Object.getOwnPropertyNames(interfaceClass.prototype)
.filter(method => method !== 'constructor');
const pluginMethods = Object.getOwnPropertyNames(pluginClass.prototype)
.filter(method => method !== 'constructor');
return requiredMethods.every(method => pluginMethods.includes(method));
}
/**
* Resolve plugin dependencies
*/
resolveDependencies(dependencies) {
const resolved = {};
for (const dep of dependencies) {
const [type, name] = dep.split(':');
resolved[dep] = this.getInstance(type, name);
}
return resolved;
}
/**
* Register hook for plugin events
*/
registerHook(event, callback) {
if (!this.hooks.has(event)) {
this.hooks.set(event, []);
}
this.hooks.get(event).push(callback);
}
/**
* Trigger hook event
*/
triggerHook(event, data = {}) {
if (this.hooks.has(event)) {
for (const callback of this.hooks.get(event)) {
try {
callback(data);
} catch (error) {
console.error(`Hook error for event '${event}':`, error);
}
}
}
}
/**
* Get registry stats
*/
getStats() {
const stats = {
pluginTypes: this.plugins.size,
totalPlugins: 0,
activeInstances: this.instances.size,
hooks: this.hooks.size,
types: {}
};
for (const [type, plugin] of this.plugins) {
const count = plugin.implementations.size;
stats.totalPlugins += count;
stats.types[type] = count;
}
return stats;
}
}
module.exports = PluginRegistry;