kukuy 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.ctagsd/ctagsd.json +954 -0
  2. package/.ctagsd/file_list.txt +100 -0
  3. package/.ctagsd/tags.db +0 -0
  4. package/CHANGELOG.md +101 -0
  5. package/LICENSE +680 -0
  6. package/README.md +251 -0
  7. package/captura.png +0 -0
  8. package/kukuy.js +23 -0
  9. package/kukuy.workspace +11 -0
  10. package/package.json +26 -0
  11. package/restart-balancer.sh +10 -0
  12. package/routes.json +14 -0
  13. package/scripts/load_test.py +151 -0
  14. package/servers.json +19 -0
  15. package/servers_real.json +19 -0
  16. package/src/algorithms/AlgorithmManager.js +85 -0
  17. package/src/algorithms/IPHashAlgorithm.js +131 -0
  18. package/src/algorithms/LoadBalancingAlgorithm.js +23 -0
  19. package/src/algorithms/RoundRobinAlgorithm.js +67 -0
  20. package/src/config/ConfigManager.js +37 -0
  21. package/src/config/RouteLoader.js +36 -0
  22. package/src/core/Balancer.js +353 -0
  23. package/src/core/RoundRobinAlgorithm.js +60 -0
  24. package/src/core/ServerPool.js +77 -0
  25. package/src/dashboard/WebDashboard.js +150 -0
  26. package/src/dashboard/WebSocketServer.js +114 -0
  27. package/src/extensibility/CachingFilter.js +134 -0
  28. package/src/extensibility/FilterChain.js +93 -0
  29. package/src/extensibility/HookManager.js +48 -0
  30. package/src/protocol/HttpBalancer.js +37 -0
  31. package/src/protocol/HttpsBalancer.js +47 -0
  32. package/src/utils/BalancerLogger.js +102 -0
  33. package/src/utils/HealthChecker.js +51 -0
  34. package/src/utils/Logger.js +39 -0
  35. package/src/utils/MetricsCollector.js +82 -0
  36. package/src/utils/ProfessionalMetrics.js +501 -0
  37. package/start-iphash.sh +5 -0
  38. package/start-roundrobin.sh +5 -0
  39. package/stress-test.js +190 -0
  40. package/webpage/README.md +17 -0
  41. package/webpage/index.html +549 -0
package/README.md ADDED
@@ -0,0 +1,251 @@
1
+ # KUKUY
2
+
3
+ Un balanceador de carga desarrollado en Node.js que distribuye solicitudes entre múltiples servidores backend usando el algoritmo RoundRobin.
4
+
5
+ ## Características
6
+
7
+ - Distribución de carga usando algoritmo RoundRobin
8
+ - Soporte para HTTP y HTTPS
9
+ - Configuración mediante variables de entorno
10
+ - Arquitectura modular con soporte para hooks y filtros
11
+ - Verificación de salud de servidores backend
12
+ - Enrutamiento basado en patrones
13
+ - Sistema de logging detallado para servidores online/offline
14
+ - Caching de respuestas para mejorar el rendimiento
15
+ - Panel de control web para monitoreo
16
+
17
+ ## Instalación
18
+
19
+ ```bash
20
+ npm install
21
+ ```
22
+
23
+ ## Configuración
24
+
25
+ El balanceador se configura mediante variables de entorno:
26
+
27
+ - `BALANCER_HTTP_PORT`: Puerto para conexiones HTTP (por defecto: 8080)
28
+ - `BALANCER_HTTPS_PORT`: Puerto para conexiones HTTPS (opcional)
29
+ - `CONFIG_FILE_PATH`: Ruta al archivo de configuración de servidores (por defecto: ./servers.json)
30
+ - `ROUTES_FILE_PATH`: Ruta al archivo de configuración de rutas (por defecto: ./routes.json)
31
+ - `LOAD_BALANCING_ALGORITHM`: Algoritmo de balanceo a usar ('roundrobin' o 'iphash') (por defecto: 'roundrobin')
32
+ - `SSL_CERT_PATH`: Ruta al certificado SSL (requerido para HTTPS)
33
+ - `SSL_KEY_PATH`: Ruta a la llave privada SSL (requerido para HTTPS)
34
+ - `HEALTH_CHECK_INTERVAL`: Intervalo para verificación de salud en ms (por defecto: 30000)
35
+ - `LOG_LEVEL`: Nivel de logging (info, warn, error, debug) (por defecto: info)
36
+ - `LOG_FILE_PATH`: Ruta al archivo de logs (por defecto: ./balancer.log)
37
+
38
+ ## Archivos de Configuración
39
+
40
+ ### servers.json
41
+ Define los servidores backend:
42
+
43
+ ```json
44
+ {
45
+ "servers": [
46
+ {
47
+ "url": "http://localhost:3001",
48
+ "weight": 1,
49
+ "tags": ["api"],
50
+ "active": true
51
+ },
52
+ {
53
+ "url": "http://localhost:3002",
54
+ "weight": 1,
55
+ "tags": ["api"],
56
+ "active": true
57
+ }
58
+ ]
59
+ }
60
+ ```
61
+
62
+ ### routes.json
63
+ Define las reglas de enrutamiento para dirigir solicitudes específicas a grupos particulares de servidores backend basados en patrones de URL:
64
+
65
+ ```json
66
+ {
67
+ "routes": [
68
+ {
69
+ "path": "/api/*",
70
+ "methods": ["GET", "POST", "PUT", "DELETE"],
71
+ "target": "api"
72
+ },
73
+ {
74
+ "path": "/*",
75
+ "methods": ["*"],
76
+ "target": "web"
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ Las rutas permiten una distribución selectiva del tráfico:
83
+ - Las rutas definen patrones de URL (usando comodín `*`) y métodos HTTP permitidos
84
+ - El campo `target` especifica la etiqueta de servidores backend a los que se dirigirá la solicitud
85
+ - Por ejemplo, todas las solicitudes que empiezan con `/api/` se enviarán solo a servidores que tengan la etiqueta "api"
86
+ - Las solicitudes que no coincidan con ninguna ruta específica se distribuirán entre todos los servidores disponibles
87
+
88
+ ## Uso
89
+
90
+ ### Iniciar en modo producción:
91
+ ```bash
92
+ npm start
93
+ ```
94
+
95
+ ### Iniciar en modo desarrollo:
96
+ ```bash
97
+ npm run dev
98
+ ```
99
+
100
+ ### Con variables de entorno personalizadas:
101
+ ```bash
102
+ BALANCER_HTTP_PORT=9090 BALANCER_HTTPS_PORT=9443 CONFIG_FILE_PATH=./my-servers.json npm start
103
+ ```
104
+
105
+ ### Con algoritmo de balanceo específico:
106
+ ```bash
107
+ # Usar algoritmo RoundRobin (predeterminado)
108
+ LOAD_BALANCING_ALGORITHM=roundrobin npm start
109
+
110
+ # Usar algoritmo IPHash
111
+ LOAD_BALANCING_ALGORITHM=iphash npm start
112
+ ```
113
+
114
+ ### Scripts de inicio predefinidos:
115
+
116
+ #### Iniciar con algoritmo RoundRobin:
117
+ ```bash
118
+ ./start-roundrobin.sh
119
+ ```
120
+
121
+ #### Iniciar con algoritmo IPHash:
122
+ ```bash
123
+ ./start-iphash.sh
124
+ ```
125
+
126
+ Los scripts utilizan la configuración por defecto y el puerto 8080. Puedes modificarlos según tus necesidades.
127
+
128
+ ### API del Panel Web
129
+
130
+ El balanceador incluye una API REST para monitoreo en tiempo real:
131
+
132
+ #### Endpoints disponibles:
133
+ - `GET /api/status` - Estado general del balanceador
134
+ - `GET /api/metrics` - Métricas generales de rendimiento
135
+ - `GET /api/servers` - Estado de los servidores backend
136
+ - `GET /api/server-stats` - Estadísticas detalladas por servidor
137
+
138
+ #### Ejemplo de respuesta de estadísticas por servidor:
139
+ ```json
140
+ {
141
+ "serverStats": {
142
+ "1": {
143
+ "id": 1,
144
+ "totalRequests": 10,
145
+ "successfulRequests": 10,
146
+ "failedRequests": 0,
147
+ "totalResponseTime": 1250,
148
+ "minResponseTime": 5,
149
+ "maxResponseTime": 346,
150
+ "avgResponseTime": 125,
151
+ "responseCodes": {"200": 10},
152
+ "lastActive": 1769298297602,
153
+ "responseTimes": [346, 7, 7, 12, 45, 67, 89, 102, 115, 120]
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ ## Hooks Disponibles
160
+
161
+ - `onRequestReceived`: Se ejecuta cuando se recibe una solicitud
162
+ - `onServerSelected`: Se ejecuta después de seleccionar un servidor backend
163
+ - `onResponseSent`: Se ejecuta cuando se envía la respuesta al cliente
164
+ - `onServerError`: Se ejecuta cuando ocurre un error con un servidor backend
165
+
166
+ ## Filtros Disponibles
167
+
168
+ - `AuthenticationFilter`: Verificación de autenticación
169
+ - `RateLimitFilter`: Control de límite de peticiones
170
+ - `LoggingFilter`: Registro de solicitudes
171
+ - `CachingFilter`: Caché de respuestas
172
+
173
+ ## Componentes Implementados
174
+
175
+ ### Core
176
+ - `Balancer.js`: Punto de entrada principal del sistema
177
+ - `ServerPool.js`: Gestión del conjunto de servidores backend
178
+ - `RequestHandler.js`: Manejo de solicitudes entrantes (integrado en Balancer.js)
179
+
180
+ ### Algoritmos
181
+ - `LoadBalancingAlgorithm.js`: Interfaz base para algoritmos de balanceo
182
+ - `RoundRobinAlgorithm.js`: Implementación del algoritmo RoundRobin como plugin
183
+ - `IPHashAlgorithm.js`: Implementación del algoritmo IPHash como plugin con asociación persistente IP-servidor
184
+ - `AlgorithmManager.js`: Gestor de algoritmos de balanceo con selección dinámica
185
+
186
+ ### Configuración
187
+ - `ConfigManager.js`: Lee y procesa variables de entorno
188
+ - `RouteLoader.js`: Carga rutas y paths desde archivos de configuración
189
+
190
+ ### Protocolos
191
+ - `HttpBalancer.js`: Manejo de conexiones HTTP
192
+ - `HttpsBalancer.js`: Manejo de conexiones HTTPS
193
+
194
+ ### Extensibilidad
195
+ - `HookManager.js`: Integración con `jerk-hooked-lib`
196
+ - `FilterChain.js`: Aplicación de filters a las solicitudes
197
+
198
+ ### Utilidades
199
+ - `Logger.js`: Sistema de logging
200
+ - `BalancerLogger.js`: Sistema de logging detallado para servidores online/offline
201
+ - `HealthChecker.js`: Verificación de estado de servidores backend
202
+ - `MetricsCollector.js`: Recolección de métricas de rendimiento
203
+
204
+ ## Componentes No Implementados (Mejoras Futuras)
205
+
206
+ ### Funcionalidades Avanzadas
207
+ - **Hot Reload de Configuración**: Actualización de configuración sin reinicio (requiere implementación de listeners de cambio de archivos)
208
+ - **API REST para Gestión de Servidores**: Endpoint para añadir/eliminar servidores dinámicamente
209
+ - **Sistema de Alertas**: Notificaciones cuando servidores caen o se recuperan
210
+ - **Soporte para WebSocket**: Balanceo de conexiones WebSocket
211
+ - **Compresión de Respuestas**: Soporte para Gzip/Brotli
212
+ - **Persistencia de Sesión**: Sticky sessions basadas en cookies o IP
213
+
214
+ ### Algoritmos de Balanceo Adicionales
215
+ - **Weighted Round Robin**: Balanceo con pesos por servidor
216
+ - **Least Connections**: Enviar a servidor con menos conexiones
217
+ - **IP Hash**: Distribución basada en dirección IP del cliente
218
+
219
+ ## Pruebas
220
+
221
+ ### Prueba de Estrés
222
+ El proyecto incluye un script de prueba de estrés:
223
+ ```bash
224
+ DURATION_SECONDS=30 CONCURRENT_REQUESTS=20 node stress-test.js
225
+ ```
226
+
227
+ ## Issues Conocidos
228
+
229
+ ### Actualización de Estado de Servidores
230
+ El dashboard no refleja en tiempo real cuando servidores se vuelven offline o se levantan después de iniciar el balanceador. La información de estado de los servidores puede no actualizar inmediatamente cuando un servidor backend cambia de estado.
231
+
232
+ Para más detalles, véase el archivo [ISSUES.md](./ISSUES.md).
233
+
234
+ ## Licencia
235
+
236
+ Este proyecto está licenciado bajo la Licencia Pública General GNU (GPL) versión 3 o posterior.
237
+
238
+ Copyright (C) 2026 Desarrollador
239
+
240
+ Este programa es software libre: usted puede redistribuirlo y/o modificarlo
241
+ bajo los términos de la Licencia Pública General GNU publicada por la
242
+ Free Software Foundation, ya sea la versión 3 de la Licencia, o
243
+ (a su elección) cualquier versión posterior.
244
+
245
+ Este programa se distribuye con la esperanza de que sea útil, pero
246
+ SIN NINGUNA GARANTÍA; ni siquiera la garantía implícita de
247
+ COMERCIABILIDAD o IDONEIDAD PARA UN PROPÓSITO PARTICULAR.
248
+ Consulte la Licencia Pública General GNU para obtener más detalles.
249
+
250
+ Debería haber recibido una copia de la Licencia Pública General GNU
251
+ junto con este programa. Si no, consulte <https://www.gnu.org/licenses/>.
package/captura.png ADDED
Binary file
package/kukuy.js ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Balancer } = require('./src/core/Balancer');
4
+
5
+ // Iniciar el balanceador
6
+ const balancer = new Balancer();
7
+ balancer.start();
8
+
9
+ console.log('Balanceador RoundRobin iniciado');
10
+ console.log(`Panel web disponible en: http://localhost:${process.env.DASHBOARD_PORT || 8082}`);
11
+
12
+ // Manejar señales de interrupción
13
+ process.on('SIGINT', () => {
14
+ console.log('\nCerrando balanceador...');
15
+ balancer.stop();
16
+ process.exit(0);
17
+ });
18
+
19
+ process.on('SIGTERM', () => {
20
+ console.log('Recibida señal SIGTERM, cerrando...');
21
+ balancer.stop();
22
+ process.exit(0);
23
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "NodeJS": {
3
+ "metadata": {
4
+ "version": "1.0",
5
+ "ide": "CodeLite",
6
+ "type": "NodeJS"
7
+ },
8
+ "folders": ["."],
9
+ "m_showHiddenFiles": false
10
+ }
11
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "kukuy",
3
+ "version": "1.4.0",
4
+ "description": "Balanceador de carga Backend",
5
+ "main": "kukuy.js",
6
+ "scripts": {
7
+ "start": "node kukuy.js",
8
+ "dev": "BALANCER_HTTP_PORT=8080 node kukuy.js",
9
+ "test": "echo \"Error: no test specified\" && exit 1"
10
+ },
11
+ "keywords": [
12
+ "load-balancer",
13
+ "round-robin",
14
+ "ip-hash",
15
+ "proxy",
16
+ "http",
17
+ "https"
18
+ ],
19
+ "author": "Benjamín Sánchez Cárdenas",
20
+ "license": "GPL-3.0-or-later",
21
+ "dependencies": {
22
+ "jerk-hooked-lib": "^2.0.0",
23
+ "ws": "^8.19.0"
24
+ },
25
+ "type": "commonjs"
26
+ }
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+ # Script para matar e iniciar KUKUY con estadísticas por servidor y WebSocket
3
+
4
+ echo "Matando procesos existentes de KUKUY..."
5
+ pkill -f "node kukuy.js" 2>/dev/null || true
6
+
7
+ sleep 2
8
+
9
+ echo "Iniciando KUKUY con estadísticas por servidor y WebSocket..."
10
+ LOAD_BALANCING_ALGORITHM=roundrobin CONFIG_FILE_PATH=./servers_real.json BALANCER_HTTP_PORT=8088 DASHBOARD_PORT=8082 WEBSOCKET_PORT=8084 node kukuy.js
package/routes.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "routes": [
3
+ {
4
+ "path": "/api/*",
5
+ "methods": ["GET", "POST", "PUT", "DELETE"],
6
+ "target": "api"
7
+ },
8
+ {
9
+ "path": "/*",
10
+ "methods": ["*"],
11
+ "target": "web"
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Script de prueba de carga concurrente para el balanceador
4
+ """
5
+
6
+ import threading
7
+ import time
8
+ import requests
9
+ import sys
10
+ from datetime import datetime
11
+
12
+ # Configuración
13
+ BASE_URL = "http://localhost:8081"
14
+ ENDPOINT = "/api/endpoints"
15
+ NUM_THREADS = 100 # Número de hilos concurrentes para alta carga
16
+ REQUESTS_PER_THREAD = 6000 # Solicitudes por hilo (100 hilos * 60 solicitudes = 6000 solicitudes totales por segundo)
17
+ DURATION_SECONDS = 120 # Duración de la prueba en segundos (2 minutos)
18
+ TARGET_RPS = 5000 # Objetivo de solicitudes por segundo
19
+
20
+ # Variables globales para métricas
21
+ total_requests = 0
22
+ successful_requests = 0
23
+ failed_requests = 0
24
+ lock = threading.Lock()
25
+
26
+ def make_requests_continuous(thread_id, end_time_target):
27
+ """Función que realiza solicitudes HTTP continuas hasta alcanzar la duración objetivo"""
28
+ global total_requests, successful_requests, failed_requests
29
+
30
+ thread_start_time = time.time()
31
+ thread_successful = 0
32
+ thread_failed = 0
33
+
34
+ # Calcular el intervalo entre solicitudes para alcanzar el objetivo RPS
35
+ interval = 1.0 / (TARGET_RPS / NUM_THREADS) if NUM_THREADS > 0 else 0.001 # Evitar división por cero
36
+
37
+ while time.time() < end_time_target:
38
+ try:
39
+ response = requests.get(f"{BASE_URL}{ENDPOINT}", timeout=10)
40
+ with lock:
41
+ total_requests += 1
42
+ if response.status_code == 200:
43
+ successful_requests += 1
44
+ thread_successful += 1
45
+ else:
46
+ failed_requests += 1
47
+ thread_failed += 1
48
+ except requests.exceptions.RequestException as e:
49
+ with lock:
50
+ total_requests += 1
51
+ failed_requests += 1
52
+ thread_failed += 1
53
+ if thread_id == 0: # Solo imprimir errores para el primer hilo
54
+ print(f"[Thread-{thread_id}] Error en solicitud: {e}")
55
+
56
+ # Esperar el intervalo calculado para alcanzar el objetivo RPS
57
+ time.sleep(interval)
58
+
59
+ thread_end_time = time.time()
60
+ thread_duration = thread_end_time - thread_start_time
61
+
62
+ print(f"[Thread-{thread_id}] Completado: {thread_successful} exitosas, {thread_failed} fallidas en {thread_duration:.2f}s")
63
+
64
+
65
+ def make_requests(thread_id):
66
+ """Función original que realiza solicitudes HTTP en un hilo (mantenida por compatibilidad)"""
67
+ global total_requests, successful_requests, failed_requests
68
+
69
+ thread_start_time = time.time()
70
+ thread_successful = 0
71
+ thread_failed = 0
72
+
73
+ for i in range(REQUESTS_PER_THREAD):
74
+ try:
75
+ response = requests.get(f"{BASE_URL}{ENDPOINT}", timeout=10)
76
+ with lock:
77
+ total_requests += 1
78
+ if response.status_code == 200:
79
+ successful_requests += 1
80
+ thread_successful += 1
81
+ else:
82
+ failed_requests += 1
83
+ thread_failed += 1
84
+ except requests.exceptions.RequestException as e:
85
+ with lock:
86
+ total_requests += 1
87
+ failed_requests += 1
88
+ thread_failed += 1
89
+ if thread_id == 0: # Solo imprimir errores para el primer hilo
90
+ print(f"[Thread-{thread_id}] Error en solicitud {i+1}: {e}")
91
+
92
+ thread_end_time = time.time()
93
+ thread_duration = thread_end_time - thread_start_time
94
+
95
+ print(f"[Thread-{thread_id}] Completado: {thread_successful} exitosas, {thread_failed} fallidas en {thread_duration:.2f}s")
96
+
97
+ def run_load_test():
98
+ """Función principal que ejecuta la prueba de carga"""
99
+ global total_requests, successful_requests, failed_requests
100
+
101
+ print(f"Iniciando prueba de carga...")
102
+ print(f"- URL base: {BASE_URL}")
103
+ print(f"- Endpoint: {ENDPOINT}")
104
+ print(f"- Hilos concurrentes: {NUM_THREADS}")
105
+ print(f"- Solicitudes por hilo: {REQUESTS_PER_THREAD}")
106
+ print(f"- Duración: {DURATION_SECONDS} segundos")
107
+ print(f"- Objetivo RPS: {TARGET_RPS}")
108
+ print("-" * 50)
109
+
110
+ start_time = time.time()
111
+ end_time_target = start_time + DURATION_SECONDS
112
+
113
+ # Crear y arrancar hilos
114
+ threads = []
115
+ for i in range(NUM_THREADS):
116
+ thread = threading.Thread(target=make_requests_continuous, args=(i, end_time_target))
117
+ threads.append(thread)
118
+ thread.start()
119
+
120
+ # Pequeño retraso entre la creación de hilos para evitar congestión
121
+ time.sleep(0.001)
122
+
123
+ # Esperar a que todos los hilos terminen
124
+ for thread in threads:
125
+ thread.join()
126
+
127
+ actual_duration = time.time() - start_time
128
+
129
+ # Mostrar resultados
130
+ print("-" * 50)
131
+ print("RESULTADOS DE LA PRUEBA DE CARGA:")
132
+ print(f"Tiempo total: {actual_duration:.2f} segundos")
133
+ print(f"Solicitudes totales: {total_requests}")
134
+ print(f"Solicitudes exitosas: {successful_requests}")
135
+ print(f"Solicitudes fallidas: {failed_requests}")
136
+ print(f"Tasa de éxito: {(successful_requests/total_requests*100) if total_requests > 0 else 0:.2f}%")
137
+ print(f"RPS Real (Solicitudes por segundo): {total_requests/actual_duration if actual_duration > 0 else 0:.2f}")
138
+ print(f"RPS Objetivo: {TARGET_RPS}")
139
+
140
+ if successful_requests > 0:
141
+ print(f"RPS Exitoso (Solicitudes exitosas por segundo): {successful_requests/actual_duration if actual_duration > 0 else 0:.2f}")
142
+
143
+ if __name__ == "__main__":
144
+ try:
145
+ run_load_test()
146
+ except KeyboardInterrupt:
147
+ print("\nPrueba interrumpida por el usuario.")
148
+ print(f"Resultados parciales:")
149
+ print(f"- Solicitudes totales: {total_requests}")
150
+ print(f"- Solicitudes exitosas: {successful_requests}")
151
+ print(f"- Solicitudes fallidas: {failed_requests}")
package/servers.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "servers": [
3
+ {
4
+ "url": "http://localhost:3001",
5
+ "weight": 1,
6
+ "tags": ["api"]
7
+ },
8
+ {
9
+ "url": "http://localhost:3002",
10
+ "weight": 1,
11
+ "tags": ["api"]
12
+ },
13
+ {
14
+ "url": "http://localhost:3003",
15
+ "weight": 1,
16
+ "tags": ["web"]
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "servers": [
3
+ {
4
+ "url": "http://localhost:3434",
5
+ "weight": 1,
6
+ "tags": ["backend"]
7
+ },
8
+ {
9
+ "url": "http://localhost:8765",
10
+ "weight": 1,
11
+ "tags": ["backend"]
12
+ },
13
+ {
14
+ "url": "http://localhost:5445",
15
+ "weight": 1,
16
+ "tags": ["backend"]
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,85 @@
1
+ const { RoundRobinAlgorithm } = require('./RoundRobinAlgorithm');
2
+ const { IPHashAlgorithm } = require('./IPHashAlgorithm');
3
+
4
+ /**
5
+ * Gestor de algoritmos de balanceo de carga
6
+ */
7
+ class AlgorithmManager {
8
+ constructor() {
9
+ this.algorithms = new Map();
10
+ this.currentAlgorithm = null;
11
+ this.defaultAlgorithm = 'roundrobin';
12
+
13
+ // Registrar algoritmos por defecto
14
+ this.registerAlgorithm(new RoundRobinAlgorithm());
15
+ this.registerAlgorithm(new IPHashAlgorithm());
16
+ }
17
+
18
+ /**
19
+ * Registra un nuevo algoritmo
20
+ * @param {LoadBalancingAlgorithm} algorithm - Instancia del algoritmo
21
+ */
22
+ registerAlgorithm(algorithm) {
23
+ this.algorithms.set(algorithm.getName(), algorithm);
24
+ }
25
+
26
+ /**
27
+ * Obtiene un algoritmo por su nombre
28
+ * @param {string} name - Nombre del algoritmo
29
+ * @returns {LoadBalancingAlgorithm|null} Algoritmo o null si no existe
30
+ */
31
+ getAlgorithm(name) {
32
+ return this.algorithms.get(name) || null;
33
+ }
34
+
35
+ /**
36
+ * Establece el algoritmo actual a usar
37
+ * @param {string} name - Nombre del algoritmo
38
+ * @returns {boolean} True si el algoritmo existe y se estableció
39
+ */
40
+ setCurrentAlgorithm(name) {
41
+ const algorithm = this.getAlgorithm(name);
42
+ if (algorithm) {
43
+ this.currentAlgorithm = algorithm;
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+
49
+ /**
50
+ * Obtiene el algoritmo actual
51
+ * @returns {LoadBalancingAlgorithm|null} Algoritmo actual o null si no está establecido
52
+ */
53
+ getCurrentAlgorithm() {
54
+ return this.currentAlgorithm;
55
+ }
56
+
57
+ /**
58
+ * Selecciona un servidor usando el algoritmo actual
59
+ * @param {Array} servers - Lista de servidores disponibles
60
+ * @param {Object} requestContext - Contexto de la solicitud
61
+ * @returns {Object|null} Servidor seleccionado o null si no hay disponibles
62
+ */
63
+ selectServer(servers, requestContext = {}) {
64
+ if (!this.currentAlgorithm) {
65
+ // Si no hay algoritmo actual, usar el predeterminado
66
+ this.setCurrentAlgorithm(this.defaultAlgorithm);
67
+ }
68
+
69
+ if (this.currentAlgorithm) {
70
+ return this.currentAlgorithm.selectServer(servers, requestContext);
71
+ }
72
+
73
+ return null;
74
+ }
75
+
76
+ /**
77
+ * Obtiene la lista de nombres de algoritmos disponibles
78
+ * @returns {Array<string>} Lista de nombres de algoritmos
79
+ */
80
+ getAvailableAlgorithms() {
81
+ return Array.from(this.algorithms.keys());
82
+ }
83
+ }
84
+
85
+ module.exports = { AlgorithmManager };