Documentación oficial

WebSockets

Referencia técnica de WebSockets — Joss language and Joss Red ecosystem.

WebSockets

Índice · Antes: HTTP, closures · Después: concurrencia

Un WebSocket mantiene abierta una conexión para intercambiar mensajes en ambas direcciones. Úsalo para chat o actualizaciones continuas; una consulta puntual puede resolverse con HTTP. Los ejemplos son fragmentos para el servidor integrado.

Las rutas aceptan parámetros dinámicos. El primer argumento del handler es la conexión y después se inyectan los parámetros en orden.

Router::ws("/rooms/{room}/users/{id}", "ChatController@connect")

public class ChatController {
    public func connect(WebSocket $ws, string $room, string $id) {
        $ws->onMessage(func(string $message) {
            $ws->send($message)
        })
    }
}

Los callbacks registrados con onMessage capturan el entorno léxico del handler. $ws, los parámetros de ruta y las variables locales siguen disponibles después de que el handler termina. El estado capturado se conserva entre mensajes y sus invocaciones se serializan:

public func connect(WebSocket $ws) {
    $count = 0
    $ws->onMessage(func(string $message) {
        $count = $count + 1
        $ws->send("Mensaje " . $count . ": " . $message)
    })
}

Cada closure conserva su propia captura. No asumas que onClose ve las reasignaciones locales realizadas por otra closure onMessage.

Cada conexión se ejecuta sobre su propio Runtime.Fork(), por lo que el contexto capturado no se comparte con otras conexiones.

La conexión expone:

  • send($message): envía un mensaje y retorna si la escritura tuvo éxito.
  • onMessage($callback): registra el callback de mensajes.
  • onClose($callback): registra limpieza que siempre se ejecuta al terminar.
  • subscribe($channel) / unsubscribe($channel): administra canales locales.
  • publish($channel, $message): publica a los demás miembros del canal.
  • WebSocket::subscriberCount($channel): devuelve el número de conexiones activas suscritas al canal.
  • close(): cierra realmente el socket.

WebSocket::publish($channel, $message) publica a todos los miembros y puede invocarse desde handlers HTTP. Las suscripciones se eliminan automáticamente al cerrar la conexión. WebSocket::broadcast() conserva el hub global histórico.

Los canales son locales al proceso. Un despliegue con varias réplicas necesita sticky sessions y un backplane pub/sub externo, o debe mantener una sola réplica para funciones de sala.

El servidor aplica keepalive y límites configurables:

WS_MAX_MESSAGE_BYTES="8388608"
WS_IDLE_TIMEOUT_SECONDS="120"
WS_PING_INTERVAL_SECONDS="30"

El upgrade ocurre antes del middleware HTTP normal. Para autenticación dentro del socket, valida el JWT con Auth::validateToken($token); el runtime repuebla la sesión usada por Auth::user().

Con TLS_CERT_FILE y TLS_KEY_FILE, el servidor integrado ofrece wss. Un proxy inverso sigue siendo válido y debe reenviar Upgrade y Connection.