> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.rhombus.community/llms.txt
> Use this file to discover all available pages before exploring further.

# Referencia del protocolo STOMP

> Referencia del protocolo de mensajería STOMP 1.2 usado por Rhombus WebSocket: estructura de frames, headers, CONNECT, SUBSCRIBE, MESSAGE y ERROR.

<Note>
  Esta página fue traducida automáticamente. Si encuentra errores o tiene sugerencias, [contáctenos](mailto:support@rhombus.com).
</Note>

Rhombus utiliza **STOMP 1.2** (Streaming Text Oriented Messaging Protocol) sobre WebSocket para la entrega de eventos en tiempo real. Esta página es una referencia del protocolo para desarrolladores que necesitan entender o implementar el framing de STOMP a bajo nivel.

## ¿Qué es STOMP?

STOMP es un protocolo de mensajería simple y basado en texto que proporciona un formato de cable interoperable para los brokers de mensajes. Define un pequeño conjunto de comandos (frames) para conectar, suscribirse, enviar y desconectar. Rhombus usa STOMP porque proporciona mensajería pub/sub estructurada sobre un transporte WebSocket estándar.

## Formato del frame

Cada frame STOMP sigue esta estructura:

```text theme={null}
COMMAND\n
header-key:header-value\n
header-key:header-value\n
\n
body (optional)
\x00
```

* **COMMAND**: Una sola palabra que identifica el tipo de frame (por ejemplo, `CONNECT`, `MESSAGE`)
* **Headers**: Cero o más pares `key:value`, uno por línea
* **Línea vacía**: Separa los headers del cuerpo
* **Cuerpo**: Carga útil opcional (típicamente JSON para frames MESSAGE)
* **Byte nulo** (`\x00`): Termina cada frame

### Ejemplo: frame CONNECT sin procesar

```text theme={null}
CONNECT\n
accept-version:1.2\n
heart-beat:10000,10000\n
\n
\x00
```

## Frames del cliente al servidor

### CONNECT

Inicia la sesión STOMP después de que la conexión WebSocket esté abierta.

| Header           | Requerido | Valor         | Descripción                                                             |
| ---------------- | --------- | ------------- | ----------------------------------------------------------------------- |
| `accept-version` | Sí        | `1.2`         | Versión del protocolo STOMP                                             |
| `heart-beat`     | Sí        | `10000,10000` | Intervalo de envío del cliente y el intervalo deseado de recepción (ms) |

```text theme={null}
CONNECT
accept-version:1.2
heart-beat:10000,10000

\x00
```

### SUBSCRIBE

Se suscribe a un tópico de destino para recibir mensajes.

| Header        | Requerido | Valor                     | Descripción                                          |
| ------------- | --------- | ------------------------- | ---------------------------------------------------- |
| `id`          | Sí        | `sub-0`                   | Identificador de suscripción definido por el cliente |
| `destination` | Sí        | `/topic/change/{orgUuid}` | Ruta del tópico al cual suscribirse                  |

```text theme={null}
SUBSCRIBE
id:sub-0
destination:/topic/change/a1b2c3d4-e5f6-7890-abcd-ef1234567890

\x00
```

<Note>
  El `id` de la suscripción es definido por el cliente. Usa cualquier cadena única. Si creas múltiples suscripciones, cada una debe tener un `id` distinto.
</Note>

### DISCONNECT

Indica una desconexión limpia e intencional.

```text theme={null}
DISCONNECT

\x00
```

No se requieren headers ni cuerpo. Después de enviar DISCONNECT, cierra la conexión WebSocket subyacente.

## Frames del servidor al cliente

### CONNECTED

Enviado por el servidor en respuesta a un CONNECT exitoso.

| Header       | Valor         | Descripción                                             |
| ------------ | ------------- | ------------------------------------------------------- |
| `version`    | `1.2`         | Versión STOMP negociada                                 |
| `heart-beat` | `10000,10000` | Intervalos de heartbeat de envío/recepción del servidor |

```text theme={null}
CONNECTED
version:1.2
heart-beat:10000,10000

\x00
```

### MESSAGE

Entrega un evento desde un tópico suscrito.

| Header         | Valor                     | Descripción                             |
| -------------- | ------------------------- | --------------------------------------- |
| `destination`  | `/topic/change/{orgUuid}` | El tópico al que pertenece este mensaje |
| `message-id`   | Generado por el servidor  | Identificador único del mensaje         |
| `subscription` | `sub-0`                   | Coincide con el `id` de la suscripción  |

```text theme={null}
MESSAGE
destination:/topic/change/a1b2c3d4-e5f6-7890-abcd-ef1234567890
message-id:msg-001
subscription:sub-0

{"entity":"POLICY_ALERT","entityUuid":"x1y2z3","type":"CREATE"}
\x00
```

El cuerpo siempre es un objeto JSON que contiene la carga útil del evento.

## Heartbeats

Los heartbeats mantienen viva la conexión y detectan fallos. Se negocian durante el intercambio CONNECT/CONNECTED.

### Formato

Un heartbeat es un único carácter de salto de línea:

```text theme={null}
\n
```

Sin comando, sin headers, sin terminador nulo. Solo `\n`.

### Negociación

El header `heart-beat` usa el formato `cx,cy` donde:

* `cx` = intervalo mínimo (ms) al que el cliente puede enviar heartbeats
* `cy` = intervalo deseado (ms) al que el cliente quiere recibir heartbeats

El servidor de Rhombus usa `10000,10000` (10 segundos en ambas direcciones).

### Comportamiento

| Dirección           | Intervalo   | Qué ocurre en caso de falla                                     |
| ------------------- | ----------- | --------------------------------------------------------------- |
| Cliente al servidor | 10 segundos | El servidor puede cerrar la conexión                            |
| Servidor al cliente | 10 segundos | El cliente debe asumir que la conexión está muerta y reconectar |

### Implementación

```python theme={null}
# Sending heartbeats
import threading

def send_heartbeats(ws, stop_event, interval=10):
    while not stop_event.is_set():
        ws.send("\n")
        stop_event.wait(interval)

# Receiving heartbeats
def parse_frame(raw):
    raw = raw.strip("\n\r")
    if not raw or raw == "\x00":
        return None  # This is a heartbeat, safe to ignore
    # ... parse as normal STOMP frame
```

## Guía de análisis de frames

### Algoritmo de análisis paso a paso

```text theme={null}
1. Read WebSocket text message
2. Strip leading newlines/carriage returns
3. If empty or just \x00 → heartbeat, return null
4. Strip trailing \x00
5. Split on "\n\n" (first occurrence) → [header_block, body]
6. Split header_block on "\n" → [command, header1, header2, ...]
7. For each header line, split on first ":" → key, value
8. Return {command, headers, body}
```

### Casos especiales

| Entrada                          | Resultado                                 |
| -------------------------------- | ----------------------------------------- |
| `\n`                             | Heartbeat (nulo)                          |
| `\n\n\n`                         | Heartbeat (nulo)                          |
| `\x00`                           | Heartbeat (nulo)                          |
| Frame sin cuerpo                 | El cuerpo es una cadena vacía             |
| Valor de header que contiene `:` | Dividir solo en los *primeros* dos puntos |

## Intercambio completo de frames

Aquí está la secuencia completa de frames para una sesión típica:

```text theme={null}
Client                                Server
  │                                      │
  │  CONNECT                             │
  │  accept-version:1.2                  │
  │  heart-beat:10000,10000              │
  │  \x00                               │
  ├─────────────────────────────────────►│
  │                                      │
  │                          CONNECTED   │
  │                          version:1.2 │
  │              heart-beat:10000,10000 │
  │                                \x00  │
  │◄─────────────────────────────────────┤
  │                                      │
  │  SUBSCRIBE                           │
  │  id:sub-0                            │
  │  destination:/topic/change/{org}     │
  │  \x00                               │
  ├─────────────────────────────────────►│
  │                                      │
  │  \n  (heartbeat)                     │
  ├─────────────────────────────────────►│
  │                                      │
  │                     \n  (heartbeat)  │
  │◄─────────────────────────────────────┤
  │                                      │
  │                            MESSAGE   │
  │            destination:/topic/...    │
  │                                      │
  │                  {"entity":"..."}    │
  │                                \x00  │
  │◄─────────────────────────────────────┤
  │                                      │
  │  \n  (heartbeat)                     │
  ├─────────────────────────────────────►│
  │                                      │
  │  DISCONNECT                          │
  │  \x00                               │
  ├─────────────────────────────────────►│
  │                                      │
  │           [WebSocket close]          │
  │◄─────────────────────────────────────┤
```

## Diferencias respecto al STOMP 1.2 completo

La implementación de Rhombus utiliza un subconjunto de STOMP 1.2. Diferencias notables:

| Característica           | Spec STOMP 1.2 | Implementación de Rhombus              |
| ------------------------ | -------------- | -------------------------------------- |
| Comando `SEND`           | Soportado      | No se usa (solo push del servidor)     |
| `UNSUBSCRIBE`            | Soportado      | No es necesario (un solo tópico)       |
| `ACK`/`NACK`             | Soportado      | No se usa (auto-acknowledge)           |
| `RECEIPT`                | Soportado      | No se usa                              |
| Frame `ERROR`            | Soportado      | Puede enviarse en errores del servidor |
| Header `content-length`  | Opcional       | No requerido                           |
| Soporte de transacciones | Soportado      | No se usa                              |

Esto significa que **no** necesitas una librería completa de cliente STOMP. El subconjunto del protocolo es lo suficientemente simple como para implementarlo manualmente, como se muestra en los [Ejemplos de código](/es/websocket/code-examples).
