jerkjs 2.5.8 → 2.6.1

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 (36) hide show
  1. package/CHANGELOG.md +162 -99
  2. package/README.md +113 -190
  3. package/RESULTADOS_WAF.md +63 -0
  4. package/doc-2.5/MANUAL_MODULOS_ADMIN.md +287 -0
  5. package/doc-2.5/QUEUE_CLI_MODULE_MANUAL.md +289 -0
  6. package/doc-2.5/QUEUE_SYSTEM_MANUAL.md +320 -0
  7. package/doc-2.5/ROUTE_CACHE_MODULE_MANUAL.md +205 -0
  8. package/doc-2.5/WAF_MODULE_MANUAL.md +229 -0
  9. package/index.js +12 -3
  10. package/jerk-admin-client/README.md +69 -0
  11. package/jerk-admin-client/package.json +23 -0
  12. package/jerk-admin-client.js +257 -0
  13. package/lib/admin/AdminExtension.js +74 -19
  14. package/lib/admin/modules/ControllerGeneratorModule.js +414 -0
  15. package/lib/admin/modules/QueueManagementModule.js +265 -0
  16. package/lib/admin/modules/RouteCacheModule.js +227 -0
  17. package/lib/admin/modules/RouteManagerModule.js +468 -0
  18. package/lib/admin/modules/STATS_MODULE_README.md +15 -0
  19. package/lib/admin/modules/ViewCacheStatsModule.js +92 -0
  20. package/lib/admin/modules/WAFModule.js +737 -0
  21. package/lib/core/server.js +72 -69
  22. package/lib/middleware/firewall.js +112 -17
  23. package/lib/mvc/viewEngine.js +69 -10
  24. package/lib/queue/GlobalQueueStorage.js +38 -0
  25. package/lib/queue/QueueSystem.js +451 -0
  26. package/lib/queue/admin_example.js +114 -0
  27. package/lib/queue/example.js +268 -0
  28. package/lib/queue/integration.js +109 -0
  29. package/lib/utils/globalViewCacheInfo.js +16 -0
  30. package/lib/utils/globalWAFStats.js +54 -0
  31. package/package.json +2 -2
  32. package/test-colors.js +46 -0
  33. package/test-help-alias.js +31 -0
  34. package/ESTADISTICAS_RENDIMIENTO.md +0 -106
  35. package/debug_hook.js +0 -11
  36. package/docs/CACHE_SYSTEM_MAP.md +0 -206
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Almacenamiento Global de Colas para el Framework JERK
3
+ * Implementación del componente queue/GlobalQueueStorage.js
4
+ * Sistema de almacenamiento compartido globalmente para las colas
5
+ */
6
+
7
+ // Crear espacio de almacenamiento global para las colas si no existe
8
+ if (!global.jerkQueues) {
9
+ global.jerkQueues = new Map();
10
+ }
11
+
12
+ if (!global.jerkQueueSystems) {
13
+ global.jerkQueueSystems = new Map();
14
+ }
15
+
16
+ if (!global.jerkQueueSystem) {
17
+ // Importar dinámicamente para evitar dependencias circulares
18
+ const QueueSystem = require('./QueueSystem');
19
+ const HookSystem = require('../core/hooks');
20
+
21
+ // Obtener hooks globales del framework si están disponibles
22
+ let globalHooks = null;
23
+ try {
24
+ const framework = require('../../index.js');
25
+ globalHooks = framework.hooks;
26
+ } catch (error) {
27
+ // Si no están disponibles, crear instancia local
28
+ globalHooks = new HookSystem();
29
+ }
30
+
31
+ global.jerkQueueSystem = new QueueSystem({ hooks: globalHooks });
32
+ }
33
+
34
+ module.exports = {
35
+ queues: global.jerkQueues,
36
+ queueSystems: global.jerkQueueSystems,
37
+ queueSystem: global.jerkQueueSystem
38
+ };
@@ -0,0 +1,451 @@
1
+ /**
2
+ * Sistema de Colas para el framework JERK
3
+ * Implementación del componente queue/QueueSystem.js
4
+ * Sistema de colas con soporte para N colas, hooks personalizados y manejo de fallback
5
+ */
6
+
7
+ class QueueSystem {
8
+ /**
9
+ * Constructor del sistema de colas
10
+ * @param {Object} options - Opciones de configuración
11
+ */
12
+ constructor(options = {}) {
13
+ // Almacenar las colas
14
+ this.queues = new Map();
15
+
16
+ // Almacenar tareas pendientes por cola
17
+ this.pendingTasks = new Map();
18
+
19
+ // Almacenar tareas en proceso por cola
20
+ this.runningTasks = new Map();
21
+
22
+ // Almacenar tareas fallidas por cola
23
+ this.failedTasks = new Map();
24
+
25
+ // Almacenar hooks del sistema
26
+ this.globalHooks = options.hooks || null;
27
+
28
+ // Configuración por defecto
29
+ this.defaultConcurrency = options.concurrency || 1;
30
+ this.defaultRetryAttempts = options.retryAttempts || 3;
31
+ this.defaultRetryDelay = options.retryDelay || 1000; // milisegundos
32
+
33
+ // Estado del sistema
34
+ this.isRunning = false;
35
+ }
36
+
37
+ /**
38
+ * Obtiene o crea una cola específica
39
+ * @param {string} queueName - Nombre de la cola
40
+ * @param {Object} options - Opciones específicas para la cola
41
+ * @returns {Object} - Objeto de la cola
42
+ */
43
+ getOrCreateQueue(queueName, options = {}) {
44
+ if (!this.queues.has(queueName)) {
45
+ const queue = {
46
+ name: queueName,
47
+ concurrency: options.concurrency || this.defaultConcurrency,
48
+ retryAttempts: options.retryAttempts || this.defaultRetryAttempts,
49
+ retryDelay: options.retryDelay || this.defaultRetryDelay,
50
+ tasks: [],
51
+ processing: false,
52
+ workers: 0,
53
+ maxWorkers: options.concurrency || this.defaultConcurrency,
54
+ hooks: options.hooks || null // Hooks específicos para esta cola
55
+ };
56
+
57
+ this.queues.set(queueName, queue);
58
+
59
+ // Inicializar estructuras de datos para esta cola
60
+ this.pendingTasks.set(queueName, []);
61
+ this.runningTasks.set(queueName, new Set());
62
+ this.failedTasks.set(queueName, []);
63
+ }
64
+
65
+ return this.queues.get(queueName);
66
+ }
67
+
68
+ /**
69
+ * Agrega una tarea a una cola
70
+ * @param {string} queueName - Nombre de la cola
71
+ * @param {Function} task - Función que representa la tarea
72
+ * @param {Object} data - Datos para la tarea
73
+ * @param {number} priority - Prioridad de la tarea (menor número = mayor prioridad)
74
+ * @returns {string} - ID único de la tarea
75
+ */
76
+ addTask(queueName, task, data = {}, priority = 0) {
77
+ const taskId = this.generateTaskId();
78
+
79
+ const queue = this.getOrCreateQueue(queueName);
80
+
81
+ const taskObj = {
82
+ id: taskId,
83
+ task: task,
84
+ data: data,
85
+ priority: priority,
86
+ createdAt: Date.now(),
87
+ attempts: 0,
88
+ maxAttempts: queue.retryAttempts
89
+ };
90
+
91
+ // Agregar a la cola de tareas pendientes
92
+ const pendingQueue = this.pendingTasks.get(queueName);
93
+ pendingQueue.push(taskObj);
94
+
95
+ // Mantener la cola ordenada por prioridad
96
+ pendingQueue.sort((a, b) => a.priority - b.priority);
97
+
98
+ // Disparar hook cuando se agrega una tarea (primero global, luego específico de cola)
99
+ if (this.globalHooks) {
100
+ this.globalHooks.doAction('queue_task_added', queueName, taskObj);
101
+ }
102
+
103
+ // Disparar hook específico de la cola
104
+ if (queue.hooks) {
105
+ queue.hooks.doAction('queue_task_added', queueName, taskObj);
106
+ }
107
+
108
+ // Si el sistema está corriendo, intentar procesar la tarea
109
+ if (this.isRunning) {
110
+ setImmediate(() => {
111
+ this.processQueue(queueName);
112
+ });
113
+ }
114
+
115
+ return taskId;
116
+ }
117
+
118
+ /**
119
+ * Genera un ID único para una tarea
120
+ * @returns {string} - ID único de la tarea
121
+ */
122
+ generateTaskId() {
123
+ return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
124
+ }
125
+
126
+ /**
127
+ * Inicia la ejecución de tareas en todas las colas
128
+ */
129
+ start() {
130
+ if (this.isRunning) {
131
+ return;
132
+ }
133
+
134
+ this.isRunning = true;
135
+
136
+ // Disparar hook cuando se inicia el sistema de colas (global)
137
+ if (this.globalHooks) {
138
+ this.globalHooks.doAction('queue_system_started');
139
+ }
140
+
141
+ // Iniciar procesamiento para cada cola
142
+ for (const [queueName, queue] of this.queues.entries()) {
143
+ // Disparar hook cuando se inicia el sistema de colas (específico de cola)
144
+ if (queue.hooks) {
145
+ queue.hooks.doAction('queue_system_started', queueName);
146
+ }
147
+ this.processQueue(queueName);
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Detiene la ejecución de tareas en todas las colas
153
+ */
154
+ stop() {
155
+ this.isRunning = false;
156
+
157
+ // Disparar hook cuando se detiene el sistema de colas (global)
158
+ if (this.globalHooks) {
159
+ this.globalHooks.doAction('queue_system_stopped');
160
+ }
161
+
162
+ // Disparar hook cuando se detiene el sistema de colas (específico de cada cola)
163
+ for (const [queueName, queue] of this.queues) {
164
+ if (queue.hooks) {
165
+ queue.hooks.doAction('queue_system_stopped', queueName);
166
+ }
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Procesa tareas en una cola específica
172
+ * @param {string} queueName - Nombre de la cola
173
+ */
174
+ async processQueue(queueName) {
175
+ if (!this.isRunning) {
176
+ return;
177
+ }
178
+
179
+ const queue = this.queues.get(queueName);
180
+ if (!queue || queue.processing || queue.paused) {
181
+ // Ya se está procesando esta cola o está pausada, salir para evitar condiciones de carrera
182
+ return;
183
+ }
184
+
185
+ // Marcar la cola como en proceso para evitar condiciones de carrera
186
+ queue.processing = true;
187
+
188
+ try {
189
+ // Procesar tareas mientras haya tareas pendientes y capacidad de trabajo
190
+ while (
191
+ this.isRunning &&
192
+ !queue.paused && // Asegurarse de que la cola no esté pausada
193
+ queue.workers < queue.maxWorkers &&
194
+ this.pendingTasks.get(queueName).length > 0
195
+ ) {
196
+ const task = this.pendingTasks.get(queueName).shift();
197
+
198
+ if (task) {
199
+ // Marcar la tarea como en proceso
200
+ this.runningTasks.get(queueName).add(task.id);
201
+
202
+ // Incrementar contador de workers
203
+ queue.workers++;
204
+
205
+ // Procesar la tarea en segundo plano
206
+ this.executeTask(queueName, task).finally(() => {
207
+ // Decrementar contador de workers
208
+ queue.workers--;
209
+
210
+ // Remover la tarea de las tareas en proceso
211
+ this.runningTasks.get(queueName).delete(task.id);
212
+
213
+ // Continuar procesando si el sistema sigue corriendo
214
+ if (this.isRunning && !queue.paused) {
215
+ setImmediate(() => {
216
+ this.processQueue(queueName);
217
+ });
218
+ }
219
+ });
220
+ }
221
+ }
222
+ } finally {
223
+ // Marcar la cola como no en proceso
224
+ queue.processing = false;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Ejecuta una tarea específica
230
+ * @param {string} queueName - Nombre de la cola
231
+ * @param {Object} task - Objeto de la tarea
232
+ */
233
+ async executeTask(queueName, task) {
234
+ const queue = this.queues.get(queueName);
235
+
236
+ try {
237
+ // Disparar hook antes de ejecutar la tarea (primero global, luego específico de cola)
238
+ let processedTask = task.task;
239
+
240
+ // Aplicar filtro global si existe
241
+ if (this.globalHooks) {
242
+ processedTask = this.globalHooks.applyFilters('queue_execute_task', processedTask, queueName, task);
243
+ }
244
+
245
+ // Aplicar filtro específico de la cola si existe
246
+ if (queue.hooks) {
247
+ processedTask = queue.hooks.applyFilters('queue_execute_task', processedTask, queueName, task);
248
+ }
249
+
250
+ await processedTask(task.data, task);
251
+
252
+ // Disparar hook cuando la tarea se completa exitosamente (global y específico)
253
+ if (this.globalHooks) {
254
+ this.globalHooks.doAction('queue_task_completed', queueName, task);
255
+ }
256
+
257
+ if (queue.hooks) {
258
+ queue.hooks.doAction('queue_task_completed', queueName, task);
259
+ }
260
+ } catch (error) {
261
+ // Incrementar intentos
262
+ task.attempts++;
263
+
264
+ // Disparar hook cuando la tarea falla (global y específico)
265
+ if (this.globalHooks) {
266
+ this.globalHooks.doAction('queue_task_failed', queueName, task, error);
267
+ }
268
+
269
+ if (queue.hooks) {
270
+ queue.hooks.doAction('queue_task_failed', queueName, task, error);
271
+ }
272
+
273
+ // Verificar si hay más intentos disponibles
274
+ if (task.attempts < task.maxAttempts) {
275
+ // Agregar de nuevo a la cola con retraso
276
+ setTimeout(() => {
277
+ const pendingQueue = this.pendingTasks.get(queueName);
278
+ pendingQueue.push(task);
279
+ pendingQueue.sort((a, b) => a.priority - b.priority);
280
+
281
+ // Disparar hook cuando se reintenta una tarea (global y específico)
282
+ if (this.globalHooks) {
283
+ this.globalHooks.doAction('queue_task_retry', queueName, task);
284
+ }
285
+
286
+ if (queue.hooks) {
287
+ queue.hooks.doAction('queue_task_retry', queueName, task);
288
+ }
289
+
290
+ if (this.isRunning) {
291
+ this.processQueue(queueName);
292
+ }
293
+ }, this.queues.get(queueName).retryDelay);
294
+ } else {
295
+ // Agregar a la cola de tareas fallidas
296
+ const failedQueue = this.failedTasks.get(queueName);
297
+ failedQueue.push(task);
298
+
299
+ // Disparar hook de fallback para tareas que han fallado definitivamente (global y específico)
300
+ if (this.globalHooks) {
301
+ // Permitir que los hooks manejen la lógica de fallback
302
+ this.globalHooks.doAction('queue_task_fallback', queueName, task, error);
303
+ }
304
+
305
+ if (queue.hooks) {
306
+ // Permitir que los hooks específicos de la cola manejen la lógica de fallback
307
+ queue.hooks.doAction('queue_task_fallback', queueName, task, error);
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Obtiene el estado actual del sistema de colas
315
+ * @returns {Object} - Estado del sistema de colas
316
+ */
317
+ getStatus() {
318
+ const status = {};
319
+
320
+ for (const [queueName, queue] of this.queues.entries()) {
321
+ status[queueName] = {
322
+ name: queueName,
323
+ pendingTasks: this.pendingTasks.get(queueName).length,
324
+ runningTasks: this.runningTasks.get(queueName).size,
325
+ failedTasks: this.failedTasks.get(queueName).length,
326
+ workers: queue.workers,
327
+ maxWorkers: queue.maxWorkers,
328
+ processing: queue.processing,
329
+ paused: queue.paused || false
330
+ };
331
+ }
332
+
333
+ return status;
334
+ }
335
+
336
+ /**
337
+ * Pausa una cola específica
338
+ * @param {string} queueName - Nombre de la cola a pausar
339
+ * @returns {boolean} - True si la cola fue pausada exitosamente
340
+ */
341
+ pauseQueue(queueName) {
342
+ const queue = this.queues.get(queueName);
343
+ if (!queue) {
344
+ return false;
345
+ }
346
+
347
+ queue.paused = true;
348
+
349
+ // Disparar hook cuando se pausa una cola
350
+ if (this.globalHooks) {
351
+ this.globalHooks.doAction('queue_paused', queueName);
352
+ }
353
+
354
+ return true;
355
+ }
356
+
357
+ /**
358
+ * Reanuda una cola específica
359
+ * @param {string} queueName - Nombre de la cola a reanudar
360
+ * @returns {boolean} - True si la cola fue reanudada exitosamente
361
+ */
362
+ resumeQueue(queueName) {
363
+ const queue = this.queues.get(queueName);
364
+ if (!queue) {
365
+ return false;
366
+ }
367
+
368
+ queue.paused = false;
369
+
370
+ // Disparar hook cuando se reanuda una cola
371
+ if (this.globalHooks) {
372
+ this.globalHooks.doAction('queue_resumed', queueName);
373
+ }
374
+
375
+ // Si el sistema está corriendo, iniciar procesamiento
376
+ if (this.isRunning) {
377
+ setImmediate(() => {
378
+ this.processQueue(queueName);
379
+ });
380
+ }
381
+
382
+ return true;
383
+ }
384
+
385
+ /**
386
+ * Limpia las tareas pendientes de una cola específica
387
+ * @param {string} queueName - Nombre de la cola a limpiar
388
+ * @returns {boolean} - True si la cola fue limpiada exitosamente
389
+ */
390
+ clearQueue(queueName) {
391
+ const queue = this.queues.get(queueName);
392
+ if (!queue) {
393
+ return false;
394
+ }
395
+
396
+ // Limpiar tareas pendientes
397
+ const pendingQueue = this.pendingTasks.get(queueName);
398
+ if (pendingQueue) {
399
+ pendingQueue.length = 0;
400
+ }
401
+
402
+ // Disparar hook cuando se limpia una cola
403
+ if (this.globalHooks) {
404
+ this.globalHooks.doAction('queue_cleared', queueName);
405
+ }
406
+
407
+ return true;
408
+ }
409
+
410
+ /**
411
+ * Limpia las tareas fallidas de una cola específica
412
+ * @param {string} queueName - Nombre de la cola
413
+ */
414
+ clearFailedTasks(queueName) {
415
+ if (this.failedTasks.has(queueName)) {
416
+ this.failedTasks.get(queueName).length = 0;
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Reintenta todas las tareas fallidas en una cola específica
422
+ * @param {string} queueName - Nombre de la cola
423
+ */
424
+ retryFailedTasks(queueName) {
425
+ if (!this.failedTasks.has(queueName)) {
426
+ return;
427
+ }
428
+
429
+ const failedQueue = this.failedTasks.get(queueName);
430
+ const pendingQueue = this.pendingTasks.get(queueName);
431
+
432
+ // Resetear intentos para todas las tareas fallidas
433
+ for (const task of failedQueue) {
434
+ task.attempts = 0;
435
+ pendingQueue.push(task);
436
+ }
437
+
438
+ // Vaciar la cola de tareas fallidas
439
+ failedQueue.length = 0;
440
+
441
+ // Reordenar la cola de pendientes
442
+ pendingQueue.sort((a, b) => a.priority - b.priority);
443
+
444
+ // Procesar la cola si el sistema está corriendo
445
+ if (this.isRunning) {
446
+ this.processQueue(queueName);
447
+ }
448
+ }
449
+ }
450
+
451
+ module.exports = QueueSystem;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Ejemplo de uso del sistema de colas con módulo de administración
3
+ * Archivo de ejemplo: queue/admin_example.js
4
+ */
5
+
6
+ const { APIServer, QueueIntegration } = require('../../index.js');
7
+
8
+ // Crear servidor
9
+ const server = new APIServer({ port: 3000 });
10
+
11
+ // Crear instancia de la integración de colas
12
+ const queueIntegration = new QueueIntegration();
13
+ const queueSystem = queueIntegration.getQueueSystem();
14
+
15
+ // Ejemplo de tarea simple
16
+ function ejemploTarea(datos, taskObj) {
17
+ return new Promise((resolve, reject) => {
18
+ console.log(`Procesando tarea con datos:`, datos);
19
+
20
+ // Simular un proceso que podría fallar
21
+ if (Math.random() < 0.3) { // 30% de probabilidad de fallo
22
+ console.error(`Falló la tarea con ID: ${taskObj.id}`);
23
+ reject(new Error(`Tarea fallida intencionalmente`));
24
+ } else {
25
+ console.log(`Tarea completada exitosamente con ID: ${taskObj.id}`);
26
+ resolve(`Resultado de la tarea con ID: ${taskObj.id}`);
27
+ }
28
+
29
+ // Simular tiempo de procesamiento
30
+ setTimeout(() => {
31
+ if (Math.random() < 0.3) {
32
+ reject(new Error(`Tarea fallida después de procesamiento`));
33
+ } else {
34
+ resolve(`Tarea completada con éxito`);
35
+ }
36
+ }, 1000);
37
+ });
38
+ }
39
+
40
+ // Crear algunas colas de ejemplo
41
+ queueIntegration.createQueue('imagenes', {
42
+ concurrency: 3,
43
+ retryAttempts: 2,
44
+ retryDelay: 1000
45
+ });
46
+
47
+ queueIntegration.createQueue('correos', {
48
+ concurrency: 2,
49
+ retryAttempts: 3,
50
+ retryDelay: 2000
51
+ });
52
+
53
+ queueIntegration.createQueue('pagos', {
54
+ concurrency: 1,
55
+ retryAttempts: 5,
56
+ retryDelay: 3000
57
+ });
58
+
59
+ // Agregar algunas tareas a las colas
60
+ console.log("Agregando tareas a las colas...");
61
+
62
+ // Tareas para cola de imágenes
63
+ for (let i = 0; i < 3; i++) {
64
+ queueIntegration.addTask('imagenes', ejemploTarea, {
65
+ id: i,
66
+ tipo: 'imagen',
67
+ nombre: `imagen_${i}.jpg`
68
+ }, i);
69
+ }
70
+
71
+ // Tareas para cola de correos
72
+ for (let i = 0; i < 3; i++) {
73
+ queueIntegration.addTask('correos', ejemploTarea, {
74
+ id: i,
75
+ tipo: 'correo',
76
+ destinatario: `usuario${i}@ejemplo.com`
77
+ }, i);
78
+ }
79
+
80
+ // Tareas para cola de pagos
81
+ for (let i = 0; i < 3; i++) {
82
+ queueIntegration.addTask('pagos', ejemploTarea, {
83
+ id: i,
84
+ tipo: 'pago',
85
+ monto: 100 + i * 50
86
+ }, i);
87
+ }
88
+
89
+ // Iniciar el sistema de colas
90
+ console.log("Iniciando el sistema de colas...");
91
+ queueIntegration.start();
92
+
93
+ // Iniciar el servidor y la extensión de administración
94
+ server.start();
95
+
96
+ // Inicializar la extensión de administración en el puerto 9999
97
+ server.initializeAdminExtension({
98
+ port: 9999,
99
+ host: '127.0.0.1'
100
+ });
101
+
102
+ console.log("Servidor iniciado en http://localhost:3000");
103
+ console.log("Extensión de administración disponible en telnet localhost 9999");
104
+ console.log("Comandos disponibles para colas: queues, queue-info, queue-pause, queue-resume, queue-clear, queue-retry-failed");
105
+
106
+ // Mostrar estado periódicamente
107
+ setInterval(() => {
108
+ console.log('\n--- Estado del sistema de colas ---');
109
+ const status = queueIntegration.getStatus();
110
+ for (const [queueName, queueStatus] of Object.entries(status)) {
111
+ console.log(`${queueName}: Pendientes=${queueStatus.pendingTasks}, En proceso=${queueStatus.runningTasks}, Fallidas=${queueStatus.failedTasks}, Pausada=${queueStatus.paused}`);
112
+ }
113
+ console.log('------------------------------------\n');
114
+ }, 10000);