O componente TsgcWS_API_Pusher foi atualizado para se alinhar com a mais recente
especificação do protocolo Pusher Channels.
Esta versão introduz suporte a canais privados criptografados, quatro novos eventos de canal de presença e cache,
dois novos endpoints REST API, parâmetros de consulta aprimorados para endpoints existentes e várias correções de bugs.
Todas as alterações são retrocompatíveis — o código existente continua funcionando sem modificações.
Sumário
- Suporte a Canais Privados Criptografados
- Novos Eventos WebSocket
- Novos Métodos REST API
- Métodos REST API Atualizados
- Correções de Bugs
- Resumo
1. Suporte a Canais Privados Criptografados
O Pusher Channels suporta canais privados criptografados que fornecem criptografia de ponta a ponta dos dados de eventos
usando NaCl Secretbox (XSalsa20-Poly1305). Os servidores Pusher nunca veem o texto simples — apenas os clientes em comunicação
podem descriptografar as mensagens. Dois novos tipos de canal foram adicionados à enumeração
TsgcWSPusherChannels:
| Valor do Enum | Prefixo do Canal | Descrição |
|---|---|---|
pscPrivateEncryptedChannel |
private-encrypted- |
Canal privado criptografado de ponta a ponta. Os payloads de dados são criptografados com um segredo compartilhado por canal. |
pscPrivateEncryptedCacheChannel |
private-encrypted-cache- |
Igual ao anterior, mais comportamento de canal cache — o último evento é entregue a novos assinantes. |
A classe TsgcWSPusherResponseAuthentication agora inclui uma propriedade
SharedSecret. Ao assinar um canal
private-encrypted-, seu endpoint de autorização deve retornar
o segredo compartilhado por canal codificado em base64. Defina esse valor no manipulador de evento
OnPusherAuthentication:
procedure TForm1.sgcPusherAuthentication(Sender: TObject;
AuthRequest: TsgcWSPusherRequestAuthentication;
AuthResponse: TsgcWSPusherResponseAuthentication);
begin
// For private-encrypted channels, set the shared secret
// returned by your authorization server
AuthResponse.Secret := 'your-app-secret';
AuthResponse.SharedSecret := 'base64-encoded-per-channel-key';
end;
Assinando um Canal Criptografado
// Subscribe to a private-encrypted channel
sgcPusher.Subscribe('my-secret-channel', pscPrivateEncryptedChannel);
// Subscribe to a private-encrypted cache channel
sgcPusher.Subscribe('my-secret-cache', pscPrivateEncryptedCacheChannel);
Publicando em um Canal Criptografado
// Client events work on private-encrypted channels just like private channels
sgcPusher.Publish('my-event', 'my-secret-channel',
pscPrivateEncryptedChannel, '{"message":"Hello encrypted!"}');
2. Novos Eventos WebSocket
Quatro novos eventos foram adicionados para tratar mensagens de protocolo interno do Pusher que antes não eram tratadas.
Esses eventos são disparados automaticamente quando as mensagens
pusher_internal: correspondentes chegam pela conexão WebSocket.
| Propriedade do Evento | Mensagem do Protocolo | Descrição |
|---|---|---|
OnPusherMemberAdded |
pusher_internal:member_added |
Disparado quando um novo usuário entra em um canal de presença. Fornece o nome do canal, ID do usuário e informações do usuário. |
OnPusherMemberRemoved |
pusher_internal:member_removed |
Disparado quando um usuário sai de um canal de presença. Fornece o nome do canal, ID do usuário e informações do usuário. |
OnPusherSubscriptionCount |
pusher_internal:subscription_count |
Disparado quando o número de assinantes de um canal muda. Deve ser habilitado no painel do Pusher. |
OnPusherCacheMiss |
pusher_internal:cache_miss |
Disparado ao assinar um canal cache que não possui evento em cache disponível. |
OnPusherMemberAdded / OnPusherMemberRemoved
Esses eventos usam o novo tipo de callback TsgcWSPusherMemberEvent,
que fornece o nome do canal, ID do usuário e informações do usuário como parâmetros separados:
TsgcWSPusherMemberEvent = procedure(Sender: TObject;
Channel, UserId, UserInfo: String) of object;
procedure TForm1.sgcPusherMemberAdded(Sender: TObject;
Channel, UserId, UserInfo: String);
begin
Memo1.Lines.Add('User joined: ' + UserId + ' on ' + Channel);
if UserInfo '' then
Memo1.Lines.Add(' Info: ' + UserInfo);
end;
procedure TForm1.sgcPusherMemberRemoved(Sender: TObject;
Channel, UserId, UserInfo: String);
begin
Memo1.Lines.Add('User left: ' + UserId + ' from ' + Channel);
end;
OnPusherSubscriptionCount
Usa o novo tipo de callback TsgcWSPusherSubscriptionCountEvent.
Este evento requer que o recurso Subscription Count esteja habilitado nas configurações do painel do Pusher.
TsgcWSPusherSubscriptionCountEvent = procedure(Sender: TObject;
Channel: String; SubscriptionCount: Integer) of object;
procedure TForm1.sgcPusherSubscriptionCount(Sender: TObject;
Channel: String; SubscriptionCount: Integer);
begin
Memo1.Lines.Add(Channel + ' now has ' + IntToStr(SubscriptionCount) +
' subscribers');
end;
OnPusherCacheMiss
Usa o novo tipo de callback TsgcWSPusherCacheMissEvent.
Este evento é disparado quando você assina um canal cache (cache-,
private-cache-,
private-encrypted-cache- ou
presence-cache-) e nenhum evento em cache está disponível.
TsgcWSPusherCacheMissEvent = procedure(Sender: TObject;
Channel: String) of object;
procedure TForm1.sgcPusherCacheMiss(Sender: TObject; Channel: String);
begin
Memo1.Lines.Add('No cached event for channel: ' + Channel);
end;
3. Novos Métodos REST API
Dois novos métodos REST API do lado do servidor foram adicionados ao componente
TsgcWS_API_Pusher, cobrindo
o endpoint de eventos em lote e o encerramento de conexões de usuário.
| Método | Pusher Endpoint | Descrição |
|---|---|---|
TriggerBatchEvents |
POST /apps/{app_id}/batch_events |
Disparar até 10 eventos em uma única requisição HTTP. Cada evento pode ter como alvo um canal diferente. |
TerminateUserConnections |
POST /apps/{app_id}/users/{user_id}/terminate_connections |
Encerrar todas as conexões WebSocket de um usuário autenticado específico. |
TriggerBatchEvents
function TriggerBatchEvents(const aBatch: String): String;
O parâmetro aBatch é uma string JSON contendo um array
batch de objetos de evento. Cada objeto deve incluir
channel,
name e
data. Máximo de 10 eventos por lote.
var
vBatch, vResult: string;
begin
vBatch :=
'{"batch": [' +
' {"channel": "my-channel-1", "name": "my-event", "data": "{\"msg\":\"hello\"}"}' + ',' +
' {"channel": "my-channel-2", "name": "my-event", "data": "{\"msg\":\"world\"}"}' +
']}';
vResult := sgcPusher.TriggerBatchEvents(vBatch);
Memo1.Lines.Add(vResult);
end;
TerminateUserConnections
function TerminateUserConnections(const aUserId: String): String;
Encerra forçadamente todas as conexões WebSocket ativas de um determinado usuário. Isso é útil para deslogar um usuário em todos os seus dispositivos ou revogar o acesso após uma mudança de permissão. Requer que a Autenticação de Usuário do Pusher esteja configurada.
var
vResult: string;
begin
// Disconnect user "user-123" from all sessions
vResult := sgcPusher.TerminateUserConnections('user-123');
Memo1.Lines.Add(vResult);
end;
4. Métodos REST API Atualizados
Três métodos REST API existentes foram aprimorados com parâmetros opcionais adicionais. Como os novos parâmetros todos têm valores padrão, o código existente é totalmente retrocompatível.
TriggerEvent
Assinatura Anterior
function TriggerEvent(const aEventName, aChannel, aData: String): String;
Nova Assinatura
function TriggerEvent(const aEventName, aChannel, aData: String;
const aSocketId: String = '';
const aInfo: String = ''): String;
| Parâmetro | Descrição |
|---|---|
aSocketId |
Excluir este socket ID de receber o evento. Útil para evitar que o remetente receba sua própria transmissão. |
aInfo |
Lista de atributos separados por vírgula para retornar. Valores válidos: subscription_count, user_count. |
var
vResult: string;
begin
// Trigger event, exclude the sender, and request subscription count
vResult := sgcPusher.TriggerEvent('my-event', 'my-channel',
'{"msg":"hello"}', sgcPusher.FSocket_id, 'subscription_count');
Memo1.Lines.Add(vResult);
// Response: {"channels":{"my-channel":{"subscription_count":5}}}
end;
GetChannels
Assinatura Anterior
function GetChannels: String;
Nova Assinatura
function GetChannels(
const aFilterByPrefix: String = '';
const aInfo: String = ''): String;
| Parâmetro | Descrição |
|---|---|
aFilterByPrefix |
Filtrar os canais retornados por prefixo de nome. Exemplo: presence- retorna apenas canais de presença. |
aInfo |
Atributos separados por vírgula. Valores válidos: user_count (somente presença), subscription_count. |
var
vResult: string;
begin
// List all presence channels with user counts
vResult := sgcPusher.GetChannels('presence-', 'user_count');
Memo1.Lines.Add(vResult);
// Response: {"channels":{"presence-room":{"user_count":3}}}
// List all channels (no filter) - backward-compatible call
vResult := sgcPusher.GetChannels;
Memo1.Lines.Add(vResult);
end;
GetChannel
Assinatura Anterior
function GetChannel(const aChannel: String): String;
Nova Assinatura
function GetChannel(const aChannel: String;
const aInfo: String = ''): String;
| Parâmetro | Descrição |
|---|---|
aInfo |
Atributos separados por vírgula. Valores válidos: subscription_count, user_count, cache. |
var
vResult: string;
begin
// Get channel info with subscription count and user count
vResult := sgcPusher.GetChannel('presence-room',
'subscription_count,user_count');
Memo1.Lines.Add(vResult);
// Response: {"occupied":true,"subscription_count":5,"user_count":3}
// Get basic channel info - backward-compatible call
vResult := sgcPusher.GetChannel('my-channel');
Memo1.Lines.Add(vResult);
end;
5. Correções de Bugs
Vários bugs foram identificados e corrigidos nesta versão:
| Bug | Impacto | Correção |
|---|---|---|
Typo in DoReadEvent: 'puserh:ping' |
Crítico Os pings do servidor nunca eram reconhecidos, fazendo o cliente perder as requisições de heartbeat. Isso poderia levar o servidor a desconectar o cliente por inatividade. | Corrigido para 'pusher:ping'. |
DoSendPong acesso nulo |
Alto Acessar JSON.Node['data'].Value sem verificação de nulo poderia causar uma violação de acesso se a mensagem ping não tivesse campo de dados. |
Adicionada verificação de nulo; padrão para {} quando os dados estão ausentes. |
GetUsers prefixo fixo |
Alto O método sempre adicionava presence- ao nome do canal, duplicando o prefixo se o usuário já passasse o nome completo do canal (ex.: presence-presence-room). |
Prefixo fixo removido. Os usuários agora devem passar o nome completo do canal incluindo o prefixo presence-. |
GetUsers ponto e vírgula duplo |
Baixo Um ponto e vírgula duplo ;; estava presente no final do método. |
O ponto e vírgula extra foi removido. |
Mudança incompatível em GetUsers: O método GetUsers não adiciona mais
presence- automaticamente. Se o seu código passa apenas o nome do canal
sem o prefixo (ex.: GetUsers('my-room')), você deve atualizá-lo para
incluir o nome completo: GetUsers('presence-my-room').
6. Resumo
| Categoria | Quantidade | Detalhes |
|---|---|---|
| Novos Tipos de Canal | 2 | pscPrivateEncryptedChannel, pscPrivateEncryptedCacheChannel |
| Novos Eventos WebSocket | 4 | OnPusherMemberAdded, OnPusherMemberRemoved, OnPusherSubscriptionCount, OnPusherCacheMiss |
| Novos Métodos REST | 2 | TriggerBatchEvents, TerminateUserConnections |
| Métodos REST Atualizados | 3 | TriggerEvent (+socket_id, +info), GetChannels (+filter, +info), GetChannel (+info) |
| Novas Propriedades | 1 | SharedSecret em TsgcWSPusherResponseAuthentication |
| Correções de Bugs | 4 | Typo no ping, acesso nulo no pong, prefixo GetUsers, ponto e vírgula duplo |
Todas as alterações são retrocompatíveis. Os novos parâmetros de método usam valores padrão e as novas propriedades de evento
são opcionais. A única mudança comportamental está em
GetUsers, que não adiciona mais o prefixo
presence- automaticamente.
