Relay
O módulo wippy/relay fornece infraestrutura de relay WebSocket com uma arquitetura de hub de duas camadas. Um hub central gerencia hubs por usuário, que por sua vez gerenciam conexões de clientes WebSocket e roteiam mensagens para plugins.
Arquitetura
Seção intitulada “Arquitetura”Central Hub├── User Hub (alice)│ ├── Plugin: session_│ ├── Plugin: ai_│ ├── WebSocket Client 1│ └── WebSocket Client 2├── User Hub (bob)│ ├── Plugin: session_│ └── WebSocket Client 1└── ...O hub central executa como um serviço. Quando um cliente WebSocket se conecta, o hub central busca ou cria um hub de usuário para aquele usuário. O hub de usuário gerencia o tempo de vida do cliente e roteia mensagens para plugins com base em prefixos de comando.
Configuração
Seção intitulada “Configuração”Adicione o módulo ao seu projeto:
wippy add wippy/relaywippy installDeclare a dependência com os parâmetros obrigatórios:
version: "1.0"namespace: app
entries: - name: os_env kind: env.storage.os
- name: processes kind: process.host lifecycle: auto_start: true
- name: dep.relay kind: ns.dependency component: wippy/relay version: "*" parameters: - name: application_host value: app:processes - name: env_storage value: app:os_env - name: user_security_scope value: app.security:user_scopeParâmetros de Configuração
Seção intitulada “Parâmetros de Configuração”| Parâmetro | Obrigatório | Padrão | Descrição |
|---|---|---|---|
application_host | sim | — | Host de processos para os processos do relay |
env_storage | não | interno | Armazenamento de variáveis de ambiente |
user_security_scope | sim | — | Escopo de segurança para hubs de usuário |
max_connections_per_user | não | 5 | Conexões WebSocket por usuário |
queue_multiplier | não | 100 | Fila de mensagens = conexões × multiplicador |
user_hub_inactivity_timeout | não | 7200s | Tempo ocioso antes da limpeza do hub |
Fluxo de Conexão do Cliente
Seção intitulada “Fluxo de Conexão do Cliente”- O cliente WebSocket conecta com
user_idnos metadados - O hub central valida a conexão e verifica os limites por usuário
- O hub central cria ou reutiliza um hub de usuário para o usuário
- O hub de usuário envia uma mensagem
welcomeao cliente:
{ "user_id": "alice", "client_count": 1, "plugins": [ { "prefix": "session_", "process_id": "...", "status": "running" }, { "prefix": "ai_", "process_id": "...", "status": "pending" } ]}O status do plugin e um dos seguintes: "not_started" (registrado, nunca iniciado), "pending" (inicializacao em andamento), "running", "failed" ou "stopped".
Roteamento de Mensagens
Seção intitulada “Roteamento de Mensagens”Clientes enviam mensagens JSON com um campo type. O hub de usuário compara o prefixo do tipo com os plugins registrados e roteia a mensagem:
{ "type": "session_get_state", "data": { "key": "value" } }O prefixo session_ corresponde ao plugin de sessão. O hub remove o prefixo e envia a mensagem para o processo do plugin com o tipo sem prefixo como o tópico:
-- process topic: "get_state"-- payload:{ conn_pid = client_pid, type = "session_get_state", -- tipo completo original preservado data = { key = "value" }, request_id = "...", session_id = "..."}Plugins respondem enviando mensagens de volta para conn_pid.
Plugins
Seção intitulada “Plugins”Plugins são entradas process.lua com meta.type: relay.plugin:
entries: - name: session_plugin kind: process.lua meta: type: relay.plugin command_prefix: session_ auto_start: true source: file://session_plugin.lua modules: [json, time, logger] method: runMetadados do Plugin
Seção intitulada “Metadados do Plugin”| Campo | Tipo | Descrição |
|---|---|---|
meta.type | string | Deve ser relay.plugin |
meta.command_prefix | string | Prefixo de tipo de mensagem que este plugin trata |
meta.auto_start | boolean | Iniciar quando o hub de usuário inicializar |
meta.default_host | string | Sobrescreve o host de processos |
Ciclo de Vida do Plugin
Seção intitulada “Ciclo de Vida do Plugin”Plugins são gerados pelo hub de usuário. Na inicialização, o plugin recebe:
function run(args) local user_id = args.user_id local user_metadata = args.user_metadata local user_hub_pid = args.user_hub_pid local config = args.configendO plugin session_ recebe mensagens de ciclo de vida:
| Mensagem | Quando |
|---|---|
"resume" | Primeiro cliente se conecta ao hub de usuário |
"shutdown" | Último cliente se desconecta do hub de usuário |
Plugins recebem 1 reinício automático em caso de crash. Após um segundo crash, o plugin é marcado como "failed" e não é reiniciado.
Implementação do Plugin
Seção intitulada “Implementação do Plugin”Plugins recebem mensagens em sua caixa de entrada de processo. Cada mensagem tem um tópico (o prefixo de comando removido) e um payload contendo os dados originais da mensagem junto com conn_pid para enviar respostas de volta ao cliente.
local json = require("json")
local function handle_message(topic, payload) if topic == "get_state" then process.send(payload.conn_pid, "ws.message", json.encode({ type = "session_state", data = { status = "active" } })) endend
local function run(args) local user_id = args.user_id local inbox = process.inbox() local events = process.events()
while true do local result = channel.select({ inbox:case_receive(), events:case_receive() }) if not result.ok then break end
if result.channel == inbox then local msg = result.value local topic = msg:topic() local payload = msg:payload():data()
if topic == "resume" then -- primeiro cliente conectado elseif topic == "shutdown" then -- último cliente desconectado else handle_message(topic, payload) end elseif result.channel == events then local event = result.value if event.kind == process.event.CANCEL then break end end endend
return { run = run }Tratamento de Erros
Seção intitulada “Tratamento de Erros”O relay envia mensagens de erro estruturadas aos clientes:
| Código de Erro | Descrição |
|---|---|
max_connections_reached | Usuário no limite de conexões |
missing_user_id | Sem user_id nos metadados da conexão |
hub_creation_failed | Falha ao gerar o hub de usuário |
invalid_json | Erro de decodificação da mensagem |
unknown_command | Mensagem sem campo type |
plugin_not_found | Nenhum plugin corresponde ao prefixo de comando |
plugin_failed | Plugin indisponível ou com crash |
Ciclo de Vida do Hub
Seção intitulada “Ciclo de Vida do Hub”Criação do Hub de Usuário
Seção intitulada “Criação do Hub de Usuário”Hubs de usuário são criados sob demanda quando o primeiro cliente para um usuário se conecta. O hub é gerado com o ator e escopo de segurança do usuário.
Coleta de Lixo
Seção intitulada “Coleta de Lixo”O hub central verifica periodicamente hubs de usuário inativos. Um hub sem clientes conectados por mais tempo que user_hub_inactivity_timeout (padrão 2 horas) é encerrado graciosamente com um timeout de cancelamento de 10 segundos.
O intervalo de verificação do GC é derivado automaticamente: inactivity_timeout / 2.5.
Segurança
Seção intitulada “Segurança”O hub central executa sob seu próprio grupo de segurança (wippy.relay.security:root) com acesso total. Cada hub de usuário é gerado com o user_security_scope configurado, isolando operações a nível de usuário.
Tópicos Internos
Seção intitulada “Tópicos Internos”| Tópico | Direção | Descrição |
|---|---|---|
ws.join | Cliente → Central/User Hub | Solicitação de conexão |
ws.leave | Cliente → Central/User Hub | Desconexão |
ws.message | Cliente → User Hub | Mensagem WebSocket |
ws.cancel | Central → User Hub | Encerramento gracioso |
ws.control | Central → User Hub | Controle de roteamento |
hub.activity_update | User Hub → Central | Atualização de contagem de clientes |
Veja Também
Seção intitulada “Veja Também”- WebSocket Relay - Configuração de endpoint WebSocket HTTP
- Modelo de Processos - Ciclo de vida e mensageria de processos
- Segurança - Atores e escopos de segurança
- Visão Geral do Framework - Uso do módulo do framework