diff --git a/API_DOCUMENTATION.md b/API_DOCUMENTATION.md index 50988b4..0f8c0d4 100644 --- a/API_DOCUMENTATION.md +++ b/API_DOCUMENTATION.md @@ -13,10 +13,11 @@ Este endpoint es consumido por el cliente (tienda) para saber si tiene algún co - **Ruta**: `/commands` - **Parámetros (Query)**: - `store_id`: ID de la tienda (Requerido). + - `id_cliente`: ID del cliente (Opcional). **Ejemplo de Solicitud**: ```http -GET /v1/commands?store_id=44 +GET /v1/commands?store_id=44&id_cliente=1 ``` **Respuestas**: @@ -43,6 +44,7 @@ Permite a un administrador o sistema central poner en cola una instrucción SQL - `sql` (String): Sentencia SQL a ejecutar (Requerido). - `privilegio` (String): Nivel de permiso, por defecto "READ". Opcional. - `id_user` (Number): ID del usuario que solicita el comando. Opcional. + - `id_cliente` (Number): ID del cliente. Opcional. **Ejemplo de Solicitud**: ```json @@ -50,7 +52,8 @@ Permite a un administrador o sistema central poner en cola una instrucción SQL "store_id": 44, "sql": "SELECT count(*) FROM ventas", "privilegio": "READ", - "id_user": 1 + "id_user": 1, + "id_cliente": 1 } ``` @@ -151,7 +154,77 @@ GET /v1/commands/user/1?limit=5 "fecha_solicitud": "2026-01-13T18:55:00.000Z", "fecha_proceso": "2026-01-13T19:00:00.000Z", "json_response": [ { "count": 150 } ] - }, - ... + } ] ``` + +--- + +## 6. Estado de Tiendas (Heartbeat) +Devuelve el estado de conectividad de las tiendas basado en su último heartbeat. + +- **Método**: `GET` +- **Ruta**: `/stores/status` +- **Parámetros (Query)**: + - `filter` (String): Filtrar por estado de conectividad. Valores: `online`, `offline`, `all` (Default: `all`). + - `id_cliente` (Number): Filtrar por ID de cliente. Opcional. + +**Estados de Conectividad**: +- **ONLINE**: Último ping hace menos de 2 minutos (120 segundos) +- **DEGRADED**: Último ping entre 2 y 5 minutos (120-300 segundos) +- **OFFLINE**: Último ping hace más de 5 minutos (>300 segundos) + +**Ejemplo de Solicitud**: +```http +GET /v1/stores/status?filter=online +GET /v1/stores/status?filter=all&id_cliente=1 +``` + +**Respuesta Exitosa (200 OK)**: +```json +{ + "total": 2, + "filter_applied": "online", + "stores": [ + { + "store_id": 44, + "id_cliente": 1, + "instance_id": "sql_inyector", + "connectivity": "ONLINE", + "status": "alive", + "last_ping": "2026-02-09T18:15:30.000Z", + "seconds_since_ping": 45, + "extra_info": { + "message": "Consultando comandos", + "timestamp": "2026-02-09T18:15:30.000Z" + } + }, + { + "store_id": 370, + "id_cliente": 1, + "instance_id": "sql_inyector", + "connectivity": "OFFLINE", + "status": "alive", + "last_ping": "2026-02-09T17:50:00.000Z", + "seconds_since_ping": 1530, + "extra_info": null + } + ] +} +``` + +**Notas Importantes**: +- Si una tienda **nunca ha enviado un heartbeat**, NO aparecerá en la respuesta de este endpoint. +- Solo se muestran tiendas que tienen al menos un registro en `tb_store_process_heartbeat` con `process_name = 'sql_inyector'`. +- Para ver tiendas que nunca se han conectado, necesitarías tener una tabla maestra de tiendas y hacer un LEFT JOIN. + +--- + +## Códigos de Estado HTTP + +- **200 OK**: Solicitud exitosa +- **201 Created**: Recurso creado exitosamente +- **204 No Content**: Solicitud exitosa sin contenido +- **400 Bad Request**: Parámetros inválidos o faltantes +- **404 Not Found**: Recurso no encontrado +- **500 Internal Server Error**: Error del servidor diff --git a/node_modules/console-control-strings/README.md~ b/node_modules/console-control-strings/README.md~ deleted file mode 100644 index 6eb34e8..0000000 --- a/node_modules/console-control-strings/README.md~ +++ /dev/null @@ -1,140 +0,0 @@ -# Console Control Strings - -A library of cross-platform tested terminal/console command strings for -doing things like color and cursor positioning. This is a subset of both -ansi and vt100. All control codes included work on both Windows & Unix-like -OSes, except where noted. - -## Usage - -```js -var consoleControl = require('console-control-strings') - -console.log(consoleControl.color('blue','bgRed', 'bold') + 'hi there' + consoleControl.color('reset')) -process.stdout.write(consoleControl.goto(75, 10)) -``` - -## Why Another? - -There are tons of libraries similar to this one. I wanted one that was: - -1. Very clear about compatibility goals. -2. Could emit, for instance, a start color code without an end one. -3. Returned strings w/o writing to streams. -4. Was not weighed down with other unrelated baggage. - -## Functions - -### var code = consoleControl.up(_num = 1_) - -Returns the escape sequence to move _num_ lines up. - -### var code = consoleControl.down(_num = 1_) - -Returns the escape sequence to move _num_ lines down. - -### var code = consoleControl.forward(_num = 1_) - -Returns the escape sequence to move _num_ lines righ. - -### var code = consoleControl.back(_num = 1_) - -Returns the escape sequence to move _num_ lines left. - -### var code = consoleControl.nextLine(_num = 1_) - -Returns the escape sequence to move _num_ lines down and to the beginning of -the line. - -### var code = consoleControl.previousLine(_num = 1_) - -Returns the escape sequence to move _num_ lines up and to the beginning of -the line. - -### var code = consoleControl.eraseData() - -Returns the escape sequence to erase everything from the current cursor -position to the bottom right of the screen. This is line based, so it -erases the remainder of the current line and all following lines. - -### var code = consoleControl.eraseLine() - -Returns the escape sequence to erase to the end of the current line. - -### var code = consoleControl.goto(_x_, _y_) - -Returns the escape sequence to move the cursor to the designated position. -Note that the origin is _1, 1_ not _0, 0_. - -### var code = consoleControl.gotoSOL() - -Returns the escape sequence to move the cursor to the beginning of the -current line. (That is, it returns a carriage return, `\r`.) - -### var code = consoleControl.hideCursor() - -Returns the escape sequence to hide the cursor. - -### var code = consoleControl.showCursor() - -Returns the escape sequence to show the cursor. - -### var code = consoleControl.color(_colors = []_) - -### var code = consoleControl.color(_color1_, _color2_, _…_, _colorn_) - -Returns the escape sequence to set the current terminal display attributes -(mostly colors). Arguments can either be a list of attributes or an array -of attributes. The difference between passing in an array or list of colors -and calling `.color` separately for each one, is that in the former case a -single escape sequence will be produced where as in the latter each change -will have its own distinct escape sequence. Each attribute can be one of: - -* Reset: - * **reset** – Reset all attributes to the terminal default. -* Styles: - * **bold** – Display text as bold. In some terminals this means using a - bold font, in others this means changing the color. In some it means - both. - * **italic** – Display text as italic. This is not available in most Windows terminals. - * **underline** – Underline text. This is not available in most Windows Terminals. - * **inverse** – Invert the foreground and background colors. - * **stopBold** – Do not display text as bold. - * **stopItalic** – Do not display text as italic. - * **stopUnderline** – Do not underline text. - * **stopInverse** – Do not invert foreground and background. -* Colors: - * **white** - * **black** - * **blue** - * **cyan** - * **green** - * **magenta** - * **red** - * **yellow** - * **grey** / **brightBlack** - * **brightRed** - * **brightGreen** - * **brightYellow** - * **brightBlue** - * **brightMagenta** - * **brightCyan** - * **brightWhite** -* Background Colors: - * **bgWhite** - * **bgBlack** - * **bgBlue** - * **bgCyan** - * **bgGreen** - * **bgMagenta** - * **bgRed** - * **bgYellow** - * **bgGrey** / **bgBrightBlack** - * **bgBrightRed** - * **bgBrightGreen** - * **bgBrightYellow** - * **bgBrightBlue** - * **bgBrightMagenta** - * **bgBrightCyan** - * **bgBrightWhite** - diff --git a/src/controladores/sql/C_sql_inyec.js b/src/controladores/sql/C_sql_inyec.js index 524bb5c..64e00d8 100644 --- a/src/controladores/sql/C_sql_inyec.js +++ b/src/controladores/sql/C_sql_inyec.js @@ -248,24 +248,71 @@ async function get_commands_by_user(req, res, dbcentral) { async function get_online_stores(req, res, dbcentral) { try { + const filter = req.query.filter; // 'online', 'offline', 'all' (default: 'all') + const id_cliente = req.query.id_cliente; // Filtro opcional por cliente + + // Construir la consulta base + let whereClause = "WHERE h.process_name = 'sql_inyector'"; + const replacements = []; + + // Filtrar por cliente si se proporciona + if (id_cliente) { + whereClause += " AND h.id_cliente = ?"; + replacements.push(id_cliente); + } + // Obtenemos los locales y su último ping - // Consideramos "Online" si el ping fue hace menos de 2 minutos + // Consideramos "ONLINE" si el ping fue hace menos de 2 minutos const [results] = await dbcentral.query( `SELECT - h.store_id, + h.store_id, + h.id_cliente, + h.instance_id, h.last_ping, h.status, - IF(TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) <= 120, 'ONLINE', 'OFFLINE') as connectivity + h.extra_info, + TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) as seconds_since_ping, + CASE + WHEN TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) <= 120 THEN 'ONLINE' + WHEN TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) <= 300 THEN 'DEGRADED' + ELSE 'OFFLINE' + END as connectivity FROM tb_store_process_heartbeat h - WHERE h.process_name = 'sql_inyector' - ORDER BY h.last_ping DESC` + ${whereClause} + ORDER BY h.last_ping DESC`, + { replacements } ); - res.status(200).json(results); + // Aplicar filtro de conectividad si se especifica + let filteredResults = results; + if (filter === 'online') { + filteredResults = results.filter(r => r.connectivity === 'ONLINE'); + } else if (filter === 'offline') { + filteredResults = results.filter(r => r.connectivity === 'OFFLINE' || r.connectivity === 'DEGRADED'); + } + + // Formatear la respuesta + const formattedResults = filteredResults.map(store => ({ + store_id: store.store_id, + id_cliente: store.id_cliente, + instance_id: store.instance_id, + connectivity: store.connectivity, + status: store.status, + last_ping: store.last_ping, + seconds_since_ping: store.seconds_since_ping, + extra_info: store.extra_info + })); + + res.status(200).json({ + total: formattedResults.length, + filter_applied: filter || 'all', + stores: formattedResults + }); } catch (error) { console.error("❌ Error al obtener tiendas online:", error.message); res.status(500).json({ - error: "Error interno del servidor" + error: "Error interno del servidor", + message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno' }); } }