UNPKG

@iota-big3/sdk-gateway

Version:

Universal API Gateway with protocol translation, intelligent routing, rate limiting, health checking, and caching

161 lines 5.51 kB
"use strict"; /** * @iota-big3/sdk-gateway * Clean Routing Engine - Phase 2d Rebuild */ Object.defineProperty(exports, "__esModule", { value: true }); exports.RoutingEngine = void 0; const tslib_1 = require("tslib"); const crypto = tslib_1.__importStar(require("crypto")); const events_1 = require("events"); class RoutingEngine extends events_1.EventEmitter { constructor() { super(); this.routes = new Map(); this.endpointHealth = new Map(); this.roundRobinCounters = new Map(); this.isEnabled = true; this.currentIndex = 0; // Added for adaptive strategy } addRoute(route) { if (!this.isEnabled) { return; } this.routes.set(route.path, route); // Initialize health status for all endpoints route.endpoints.forEach(endpoint => { this.endpointHealth.set(endpoint.id, true); }); this.emit('route:added', { route, timestamp: Date.now() }); } removeRoute(path) { if (!this.isEnabled) { return; } const route = this.routes.get(path); if (route) { this.routes.delete(path); this.roundRobinCounters.delete(path); // Clean up endpoint health tracking route.endpoints.forEach(endpoint => { this.endpointHealth.delete(endpoint.id); }); this.emit('route:removed', { route, timestamp: Date.now() }); } } findRoute(request) { if (!this.isEnabled) { return null; } // Find exact match first let route = this.routes.get(request.path); // If no exact match, try pattern matching if (!route) { for (const [path, routeConfig] of Array.from(this.routes)) { if (this.matchesPattern(request.path, path)) { route = routeConfig; break; } } } if (!route) { return null; } // Get healthy endpoints const healthyEndpoints = route.endpoints.filter(endpoint => this.endpointHealth.get(endpoint.id) !== false); if (healthyEndpoints.length === 0) { return null; } // Select endpoint based on load balance strategy const endpoint = this.selectEndpoint(healthyEndpoints, route.loadBalance?.strategy || 'round-robin'); return { endpoint, route, reason: `Selected by ${route.loadBalance?.strategy || 'round-robin'} strategy` }; } matchesPattern(path, pattern) { // Simple pattern matching (supports * wildcard) if (pattern.includes('*')) { const regex = new RegExp('^' + pattern.replace('*', '.*') + '$'); return regex.test(path); } return path === pattern; } selectEndpoint(endpoints, strategy) { if (!endpoints || endpoints.length === 0) { throw new Error('No endpoints available'); } // Ensure we always have at least one endpoint const firstEndpoint = endpoints[0]; if (!firstEndpoint) { throw new Error('No valid endpoints available'); } // Use default strategy if not specified const activeStrategy = strategy || 'round-robin'; switch (activeStrategy) { case 'round-robin': { // Simple round-robin const index = this.currentIndex % endpoints.length; this.currentIndex++; return endpoints[index] || firstEndpoint; } case 'random': { const randomIndex = Math.floor(crypto.randomInt(0, Number.MAX_SAFE_INTEGER) / Number.MAX_SAFE_INTEGER * endpoints.length); return endpoints[randomIndex] || firstEndpoint; } case 'least-connections': // For now, just return first endpoint // In real implementation, would track active connections return firstEndpoint; case 'weighted': // For now, just return first endpoint // In real implementation, would use endpoint weights return firstEndpoint; default: return firstEndpoint; } } _selectAdaptiveEndpoint(endpoints) { // For now, simple implementation // In real implementation, would use metrics to select best endpoint return endpoints.length > 0 && endpoints[0] ? endpoints[0] : null; } updateEndpointHealth(endpointId, isHealthy) { this.endpointHealth.set(endpointId, isHealthy); this.emit('endpoint:health:updated', { endpointId, isHealthy, timestamp: Date.now() }); } getAllRoutes() { return Array.from(this.routes.values()); } /** * Get all routes (alias for getAllRoutes) */ getRoutes() { return this.getAllRoutes(); } /** * Remove route by ID */ removeRouteById(routeId) { for (const [path, route] of this.routes.entries()) { if (route.id === routeId) { this.removeRoute(path); return true; } } return false; } } exports.RoutingEngine = RoutingEngine; //# sourceMappingURL=routing-engine.js.map