Atualização do Cliente Pusher para Delphi

· Recursos

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

  1. Suporte a Canais Privados Criptografados
  2. Novos Eventos WebSocket
  3. Novos Métodos REST API
  4. Métodos REST API Atualizados
  5. Correções de Bugs
  6. 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.