UNPKG

fortify2-js

Version:

MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.

379 lines (375 loc) 13.2 kB
'use strict'; var events = require('events'); var nehoid = require('nehoid'); var PluginTypes = require('./types/PluginTypes.js'); /** * Ultra-Fast Plugin Execution Engine * * High-performance plugin execution engine designed to achieve <1ms overhead * while maintaining security and comprehensive error handling. */ /** * Ultra-fast plugin execution engine with intelligent optimization */ class PluginEngine extends events.EventEmitter { constructor(registry, cache, cluster) { super(); this.executionPool = new Map(); this.warmupCache = new Map(); // Performance optimization: Object pooling for contexts this.contextPool = []; this.MAX_POOL_SIZE = 100; // Circuit breaker for failing plugins this.circuitBreakers = new Map(); this.registry = registry; this.cache = cache; this.cluster = cluster; // Listen to registry events this.setupRegistryEventHandlers(); } /** * Execute plugins for a specific type with ultra-fast performance */ async executePlugins(type, req, res, next) { const startTime = performance.now(); const executionId = nehoid.NehoID.generate({ prefix: "plug.exec", size: 8 }); try { // Get plugins for this type (pre-sorted by priority) const plugins = this.registry.getPluginsByType(type); if (plugins.length === 0) { return true; // Continue execution if no plugins } // Create or reuse execution context const context = this.createExecutionContext(req, res, next, executionId, startTime); // Execute plugins based on type strategy const success = await this.executePluginChain(plugins, context); // Update performance metrics const totalExecutionTime = performance.now() - startTime; this.updatePerformanceMetrics(type, totalExecutionTime, success); // Return context to pool this.returnContextToPool(context); return success; } catch (error) { const executionTime = performance.now() - startTime; this.handleExecutionError(type, executionId, error, executionTime); return false; } } /** * Execute a single plugin with comprehensive error handling */ async executePlugin(plugin, context) { const startTime = performance.now(); try { // Check circuit breaker if (this.isCircuitBreakerOpen(plugin.id)) { return { success: false, executionTime: 0, error: new Error(`Circuit breaker open for plugin ${plugin.id}`), shouldContinue: true, }; } // Warm up plugin if needed await this.warmupPlugin(plugin, context); // Execute plugin with timeout const result = await this.executeWithTimeout(plugin, context); const executionTime = performance.now() - startTime; result.executionTime = executionTime; // Update plugin statistics this.registry.updateStats(plugin.id, executionTime, result.success); // Reset circuit breaker on success if (result.success) { this.resetCircuitBreaker(plugin.id); } else { this.updateCircuitBreaker(plugin.id); } // Emit execution event this.emitPluginEvent(PluginTypes.PluginEventType.PLUGIN_EXECUTED, plugin.id, { executionTime, success: result.success, type: plugin.type, }); return result; } catch (error) { const executionTime = performance.now() - startTime; // Update circuit breaker this.updateCircuitBreaker(plugin.id); // Update error statistics this.registry.updateStats(plugin.id, executionTime, false); // Emit error event this.emitPluginEvent(PluginTypes.PluginEventType.PLUGIN_ERROR, plugin.id, { error: error.message, executionTime, type: plugin.type, }); return { success: false, executionTime, error, shouldContinue: true, }; } } /** * Execute plugin chain with intelligent optimization */ async executePluginChain(plugins, context) { // For critical performance plugins, execute in parallel if (plugins.length > 0 && plugins[0].type === PluginTypes.PluginType.PERFORMANCE) { return await this.executePluginsParallel(plugins, context); } // For security and cache plugins, execute sequentially return await this.executePluginsSequential(plugins, context); } /** * Execute plugins sequentially (for security, cache operations) */ async executePluginsSequential(plugins, context) { for (const plugin of plugins) { const result = await this.executePlugin(plugin, context); if (!result.success && plugin.type === PluginTypes.PluginType.SECURITY) { // Security plugins must succeed return false; } if (!result.shouldContinue) { // Plugin requested to stop execution return false; } // Store plugin result data if (result.data) { context.pluginData.set(plugin.id, result.data); } // Handle cache data if (result.cacheData) { await this.cache.set(result.cacheData.key, result.cacheData.value, { ttl: result.cacheData.ttl }); } } return true; } /** * Execute plugins in parallel (for performance monitoring) */ async executePluginsParallel(plugins, context) { const promises = plugins.map((plugin) => this.executePlugin(plugin, context)); const results = await Promise.allSettled(promises); let allSuccessful = true; results.forEach((result, index) => { if (result.status === "fulfilled") { const pluginResult = result.value; if (!pluginResult.success) { allSuccessful = false; } // Store plugin result data if (pluginResult.data) { context.pluginData.set(plugins[index].id, pluginResult.data); } } else { allSuccessful = false; } }); return allSuccessful; } /** * Execute plugin with timeout protection */ async executeWithTimeout(plugin, context) { const timeoutMs = plugin.maxExecutionTime; return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.emitPluginEvent(PluginTypes.PluginEventType.PLUGIN_TIMEOUT, plugin.id, { timeout: timeoutMs, type: plugin.type, }); reject(new Error(`Plugin ${plugin.id} timed out after ${timeoutMs}ms`)); }, timeoutMs); // Execute plugin const execution = plugin.isAsync ? plugin.execute(context) : Promise.resolve(plugin.execute(context)); execution .then((result) => { clearTimeout(timeout); resolve(result); }) .catch((error) => { clearTimeout(timeout); reject(error); }); }); } /** * Create optimized execution context with object pooling */ createExecutionContext(req, res, next, executionId, startTime) { // Try to reuse context from pool let context = this.contextPool.pop(); if (!context) { context = { req, res, next, startTime, executionId, cache: this.cache, cluster: this.cluster, pluginData: new Map(), security: { isAuthenticated: false, roles: [], permissions: [], }, metrics: { requestStartTime: startTime, pluginExecutionTimes: new Map(), cacheHits: 0, cacheMisses: 0, }, }; } else { // Reset reused context context.req = req; context.res = res; context.next = next; context.startTime = startTime; context.executionId = executionId; context.pluginData.clear(); context.metrics.pluginExecutionTimes.clear(); context.metrics.requestStartTime = startTime; context.metrics.cacheHits = 0; context.metrics.cacheMisses = 0; } return context; } /** * Return context to pool for reuse */ returnContextToPool(context) { if (this.contextPool.length < this.MAX_POOL_SIZE) { // Clear sensitive data before returning to pool context.pluginData.clear(); context.metrics.pluginExecutionTimes.clear(); this.contextPool.push(context); } } /** * Warm up plugin for optimal performance */ async warmupPlugin(plugin, context) { if (this.warmupCache.has(plugin.id)) { return; // Already warmed up } if (plugin.warmup) { try { await plugin.warmup(context); this.warmupCache.set(plugin.id, true); } catch (error) { // Warmup failure is not critical console.warn(`Plugin ${plugin.id} warmup failed:`, error); } } } /** * Circuit breaker management */ isCircuitBreakerOpen(pluginId) { const breaker = this.circuitBreakers.get(pluginId); if (!breaker) return false; // Reset circuit breaker after 60 seconds if (breaker.isOpen && Date.now() - breaker.lastFailure > 60000) { breaker.isOpen = false; breaker.failures = 0; } return breaker.isOpen; } updateCircuitBreaker(pluginId) { const breaker = this.circuitBreakers.get(pluginId) || { failures: 0, lastFailure: 0, isOpen: false, }; breaker.failures++; breaker.lastFailure = Date.now(); // Open circuit breaker after 5 failures if (breaker.failures >= 5) { breaker.isOpen = true; } this.circuitBreakers.set(pluginId, breaker); } resetCircuitBreaker(pluginId) { this.circuitBreakers.delete(pluginId); } /** * Setup registry event handlers */ setupRegistryEventHandlers() { this.registry.on(PluginTypes.PluginEventType.PLUGIN_UNREGISTERED, (event) => { // Clean up plugin-specific data this.circuitBreakers.delete(event.pluginId); this.warmupCache.delete(event.pluginId); }); } /** * Update performance metrics */ updatePerformanceMetrics(type, executionTime, success) { // Emit performance metrics for monitoring this.emit("performance", { type, executionTime, success, timestamp: Date.now(), }); } /** * Handle execution errors */ handleExecutionError(type, executionId, error, executionTime) { console.error(`Plugin execution error [${type}] [${executionId}]:`, error); this.emit("error", { type, executionId, error, executionTime, timestamp: Date.now(), }); } /** * Emit plugin event */ emitPluginEvent(type, pluginId, data) { const event = { type, pluginId, timestamp: new Date(), data, }; this.emit(type, event); } /** * Get engine statistics (ultra-fast optimized) */ getEngineStats() { // Ultra-fast: Count open circuit breakers without creating arrays let circuitBreakersOpen = 0; this.circuitBreakers.forEach((breaker) => { if (breaker.isOpen) circuitBreakersOpen++; }); return { contextPoolSize: this.contextPool.length, circuitBreakersOpen, warmedUpPlugins: this.warmupCache.size, activeExecutions: this.executionPool.size, }; } } exports.PluginEngine = PluginEngine; //# sourceMappingURL=PluginEngine.js.map