O Pusher é uma plataforma fácil e confiável com bons recursos baseados no protocolo WebSocket: mensageria pub/sub flexível, listas de usuários ao vivo (presence), autenticação...
A versão da API WebSocket do Pusher é 7.
Os dados são enviados bidirecionalmente sobre um WebSocket como dados de texto contendo JSON codificado em UTF8 (frames WebSocket binários não são suportados).
Você pode chamar o método Ping para testar a conexão com o servidor. Essencialmente, quaisquer mensagens recebidas da outra parte são consideradas como indicação de que a conexão está ativa. Na ausência de qualquer mensagem, qualquer uma das partes pode verificar se o outro lado está respondendo enviando uma mensagem de ping, à qual a outra parte deve responder com um pong.
Antes de conectar, você deve preencher os seguintes campos:
Pusher.Cluster := 'eu'; // cluster where your pusher account is located
Pusher.Key := '9c3b7ef25qe97a00116c'; // your pusher api key
Pusher.Name := 'js'; // optional, name of your application
Pusher.Version := '4.1'; // optional, version of your application
Pusher.TLS := True; // if encrypted, set to True
Pusher.Secret := '2dc792e1916ac49e6b3f'; // pusher secret string (needed for private and presence channels)
Importante
O Pusher exige que o cliente websocket conecte a uma URL usando os campos anteriores (key, cluster...), esses campos são usados para construir a url e isso é feito quando você atribui o cliente no componente pusher. Portanto, para ter certeza de que a URL é construída corretamente, defina o cliente depois de ter preenchido os campos de configuração do pusher. Veja abaixo o pseudocódigo:
// configure pusher fields
pusher.cluster = ...
pusher.key = ...
// set client
pusher.client = websocket client
// start connection
websocket client.Active = true;
Após uma conexão bem-sucedida, o evento OnPusherConnect é gerado e você obtém os seguintes campos:
Socket ID: Um identificador único para o cliente conectado.
Timeout: O número de segundos de inatividade do servidor após os quais o cliente deve iniciar uma mensagem de ping (isso é tratado automaticamente pelo componente).
Em caso de erro, OnPusherError será gerado e informações sobre o erro serão fornecidas. Um erro pode ser enviado pelo Pusher em resposta a autenticação inválida, um comando inválido, etc.
4000-4099
Indica um erro que resulta no fechamento da conexão pelo Pusher, e que tentar reconectar com os mesmos parâmetros não terá sucesso.
4000: O aplicativo aceita apenas conexões SSL, reconecte usando wss://
4001: A aplicação não existe
4003: Aplicação desabilitada
4004: A aplicação excedeu a cota de conexão
4005: Caminho não encontrado
4006: Formato de string de versão inválido
4007: Unsupported protocol version
4008: Nenhuma versão de protocolo fornecida
4100-4199
Indica um erro que resulta no fechamento da conexão pelo Pusher, e que o cliente pode reconectar após 1s ou mais.
4100: Capacidade excedida
4200-4299
Indica um erro que resulta no fechamento da conexão pelo Pusher, e que o cliente pode reconectar imediatamente.
4200: Reconexão genérica imediata
4201: Resposta Pong não recebida: o ping foi enviado ao cliente, mas nenhuma resposta foi recebida - veja as mensagens ping e pong
4202: Fechado após inatividade: O cliente esteve inativo por um longo período (atualmente 24 horas) e o cliente não suporta ping. Atualize para um rascunho WebSocket mais recente ou implemente a versão 5 ou superior deste protocolo.
4300-4399
Qualquer outro tipo de erro.
4301: Evento de cliente rejeitado devido ao rate limit
Os canais são um conceito fundamental no Pusher. Cada aplicação tem uma série de canais, e cada cliente pode escolher em quais canais se inscreve.
Os canais fornecem:
Uma forma de filtrar dados. Por exemplo, em uma aplicação de chat, pode haver um canal para pessoas que querem discutir 'cachorros'
Uma forma de controlar o acesso a diferentes streams de informação. Por exemplo, uma aplicação de gerenciamento de projetos quereria autorizar pessoas a receber atualizações sobre o 'projectX'
É altamente recomendável que os canais sejam usados para filtrar seus dados e que isso não seja feito usando eventos. Isso ocorre porque todos os eventos publicados em um canal são enviados a todos os assinantes, independentemente de seu vínculo de evento.
Os canais não precisam ser criados explicitamente e são instanciados sob demanda do cliente. Isso significa que criar um canal é fácil. Basta instruir um cliente a assiná-lo.
Os seguintes tipos de canais são suportados:
Canais públicos podem ser assinados por qualquer pessoa que conheça seus nomes
Canais privados introduzem um mecanismo que permite que seu servidor controle o acesso aos dados que você está transmitindo
Os canais de presença são uma extensão dos canais privados. Eles permitem que você registre informações do usuário na assinatura e deixe que outros membros do canal saibam quem está online
Cache channels lembram o último evento disparado e o enviam como o primeiro evento aos novos assinantes (variantes public, private e presence)
Os canais Private-Encrypted fornecem criptografia de ponta a ponta utilizando NaCl secretbox, garantindo que nem mesmo o Pusher possa ler os dados da mensagem
Canais públicos devem ser utilizados para dados acessíveis publicamente, pois não exigem nenhuma forma de autorização para serem assinados.
Você pode assinar e cancelar a assinatura de canais a qualquer momento. Não há necessidade de esperar o Pusher terminar de conectar primeiro.
Exemplo: assinar o canal "my-channel".
Delphi
APIPusher.Subscribe('my-channel');
Se você assinar com sucesso, o evento OnPusherSubscribe será gerado; se houver um erro, você receberá uma mensagem no evento OnPusherError.
Todas as mensagens do canal assinado serão recebidas no evento OnPusherEvent.
Quando o método Publish é chamado e o canal é Público, o componente, em vez de utilizar o protocolo WebSocket, utiliza o protocolo HTTP e chama o método TriggerEvent (a publicação não é permitida utilizando o protocolo websocket).
Requer Indy 10.5.7 ou posterior
Canais privados devem ser utilizados quando o acesso ao canal precisa ser restrito de alguma forma. Para que um usuário possa assinar um canal privado, a permissão deve ser autorizada.
Exemplo: assina o canal "my-private-channel".
Delphi
APIPusher.Subscribe('my-private-channel', pscPrivateChannel);
Se você assinar com sucesso, o evento OnPusherSubscribe será gerado; se houver um erro, você receberá uma mensagem no evento OnPusherError.
Todas as mensagens do canal assinado serão recebidas no evento OnPusherEvent.
Requer Indy 10.5.7 ou posterior
Os canais Presence se baseiam na segurança dos canais Private e expõem o recurso adicional de ter ciência de quem está inscrito naquele canal. Isso torna extremamente fácil construir funcionalidades de sala de chat e do tipo "quem está online" na sua aplicação. Pense em salas de chat, colaboradores em um documento, pessoas vendo a mesma página web, competidores em um jogo, esse tipo de coisa.
Os canais de presença são assinados a partir da API do cliente da mesma forma que os canais privados, mas o nome do canal deve ser prefixado com presence-. Assim como nos canais privados, uma requisição HTTP é feita a uma URL de autenticação configurável para determinar se o usuário atual tem permissões para acessar o canal.
As informações sobre os usuários que se inscrevem e cancelam a inscrição em um canal podem então ser acessadas vinculando-se a eventos no presence channel, e o estado atual dos usuários inscritos no canal está disponível por meio da propriedade channel.members.
Example: assina o canal "my-presence-channel".
APIPusher.Subscribe('my-presence-channel', pscPresenceChannel,
'{"user_id":"John_Smith","user_info":{"name":"John Smith"}}')
Se você assinar com sucesso, o evento OnPusherSubscribe será gerado; se houver um erro, você receberá uma mensagem no evento OnPusherError.
Todas as mensagens do canal assinado serão recebidas no evento OnPusherEvent.
Um canal de cache lembra o último evento disparado e o envia como o primeiro evento a novos assinantes.
Quando um evento é acionado em um canal de cache, o Pusher Channels armazena esse evento em cache e, quando um cliente assina um canal de cache, se existir um valor em cache, este é enviado ao cliente como o primeiro evento naquele canal. Esse comportamento ajuda os desenvolvedores a fornecer o estado inicial sem adicionar lógica adicional para buscá-lo em outro lugar.
Os seguintes Cache Channels são suportados:
Exemplo: assinar o canal de cache público "my-cache-channel".
APIPusher.Subscribe('my-cache-channel', pscCacheChannel);
Se você assinar com sucesso, o evento OnPusherSubscribe será gerado; se houver um erro, você receberá uma mensagem no evento OnPusherError.
Todas as mensagens do canal assinado serão recebidas no evento OnPusherEvent.
Se não houver evento em cache ao assinar um canal de cache, o evento OnPusherCacheMiss será gerado, fornecendo o nome do canal. Isso permite que sua aplicação trate o caso em que nenhum dado em cache está disponível.
Os canais Private-Encrypted fornecem criptografia de ponta a ponta para as mensagens. Como os canais privados, eles exigem autenticação, mas, adicionalmente, todas as cargas úteis de dados são criptografadas usando NaCl secretbox, de modo que apenas assinantes autorizados possam ler o conteúdo. Nem mesmo a própria Pusher consegue descriptografar as mensagens.
Para utilizar canais privados-criptografados, você deve fornecer um SharedSecret durante a autenticação. O segredo compartilhado é utilizado para criptografar e descriptografar os dados da mensagem.
Exemplo: inscreva-se em um canal privado criptografado "my-encrypted-channel".
APIPusher.Subscribe('my-encrypted-channel', pscPrivateEncryptedChannel);
Também está disponível uma variante private-encrypted-cache, combinando criptografia com o comportamento de canal de cache:
APIPusher.Subscribe('my-encrypted-cache-channel', pscPrivateEncryptedCacheChannel);
Ao usar o evento OnPusherAuthentication com canais private-encrypted, você pode definir a propriedade SharedSecret no objeto de resposta para fornecer a chave de criptografia:
procedure OnPusherAuthenticationEvent(Sender: TObject;
AuthRequest: TsgcWSPusherRequestAuthentication;
AuthResponse: TsgcWSPusherResponseAuthentication);
begin
AuthResponse.SharedSecret := 'your-shared-secret-key';
end;
Os canais Presence fornecem eventos adicionais que notificam sua aplicação quando os usuários entram ou saem de um canal, e permitem que você rastreie as contagens de assinaturas.
Gerado quando um novo membro se inscreve em um presence channel. Fornece o nome do canal, o ID do usuário e as informações do usuário do membro que ingressou.
procedure PUSHERPusherMemberAdded(Sender: TObject;
Channel, UserId, UserInfo: string);
begin
Log('Member joined: ' + UserId + ' on ' + Channel);
end;
Gerado quando um membro cancela a assinatura de um presence channel. Fornece o nome do canal, o user ID e as informações do usuário do membro que saiu.
procedure PUSHERPusherMemberRemoved(Sender: TObject;
Channel, UserId, UserInfo: string);
begin
Log('Member left: ' + UserId + ' on ' + Channel);
end;
Gerado quando a contagem de inscrições muda em um canal. Fornece o nome do canal e o número atual de assinantes. Este evento deve estar habilitado no seu painel do Pusher.
procedure PUSHERPusherSubscriptionCount(Sender: TObject;
Channel: string; SubscriptionCount: Integer);
begin
Log(Channel + ' has ' + IntToStr(SubscriptionCount) + ' subscribers');
end;
Gerado ao assinar um canal de cache que não tem nenhum evento em cache. Fornece o nome do canal. Isso permite que a sua aplicação trate o caso em que nenhum dado em cache está disponível, por exemplo, buscando os dados de outra fonte.
procedure PUSHERPusherCacheMiss(Sender: TObject; Channel: string);
begin
Log('Cache miss on: ' + Channel);
end;
Você não apenas pode receber mensagens dos canais assinados, mas também pode enviar mensagens a outros usuários assinados.
Chame o método Publish para enviar uma mensagem a todos os usuários assinados do canal.
Exemplo: enviar um evento a todos os usuários inscritos de "my-channel"
APIPusher.Publish('my-event', 'my-channel');
Publique no máximo 10 mensagens por segundo por cliente (conexão). Quaisquer eventos disparados acima desse limite de taxa serão rejeitados pela Pusher API. Isso não é um problema de sistema, é um problema do cliente. 100 clientes em um canal enviando mensagens nessa taxa teriam, cada um, que processar também 1.000 mensagens por segundo! Embora alguns navegadores modernos possam ser capazes de lidar com isso, muito provavelmente não é uma boa ideia.
A API está hospedada em http://api-CLUSTER.pusher.com , onde CLUSTER é substituído pelo cluster de seus próprios apps (por exemplo, eu).
Códigos de status HTTP são usados para indicar o sucesso ou não das requisições. Os seguintes status são comuns:
200 Requisição bem-sucedida. O corpo conterá um hash JSON de dados de resposta
400 Erro: detalhes no corpo da resposta
401 Erro de autenticação: o corpo da resposta conterá uma explicação
403 Forbidden: app desabilitado ou acima da cota de mensagens
As seguintes funções da REST API foram implementadas.
| Function | Descrição |
| TriggerEvent | Dispara um novo evento no canal especificado. Suporta os parâmetros opcionais SocketId (para excluir um cliente) e Info. |
| TriggerBatchEvents | Dispara múltiplos eventos em uma única requisição HTTP. Aceita um array JSON de objetos de evento. |
| GetChannels | Fornece uma lista de todos os canais ativos. Suporta os parâmetros opcionais FilterByPrefix e Info. |
| GetChannel | Fornece informações sobre um canal específico. Suporta um parâmetro Info opcional. |
| GetUsers | Fornece uma lista de todos os usuários conectados a um canal. |
| TerminateUserConnections | Encerra todas as conexões de um determinado usuário pelo seu user ID. |
Dispara um evento em um ou mais canais. Requer o nome do evento, o nome do canal e o payload de dados.
| Parameter | Descrição |
| aEventName | O nome do evento a disparar. |
| aChannel | O nome do canal no qual disparar o evento. |
| aData | Os dados do evento (string JSON). |
| aSocketId (opcional) | Um socket ID a excluir do recebimento do evento. Útil para impedir que o remetente receba sua própria mensagem. |
| aInfo (opcional) | Uma lista de atributos separados por vírgula a incluir na resposta (por exemplo, "subscription_count"). |
// trigger event on a channel
APIPusher.TriggerEvent('my-event', 'my-channel', 'Hello World');
// trigger event excluding the sender
APIPusher.TriggerEvent('my-event', 'my-channel', 'Hello World', '123.456');
// trigger event requesting subscription_count in the response
APIPusher.TriggerEvent('my-event', 'my-channel', 'Hello World', '', 'subscription_count');
Dispara múltiplos eventos em uma única chamada de API, o que é mais eficiente do que fazer requisições separadas para cada evento. O parâmetro batch deve ser uma string JSON contendo um array de objetos de evento, onde cada objeto tem os campos "channel", "name" e "data".
APIPusher.TriggerBatchEvents(
'[{"channel":"my-channel","name":"my-event","data":"hello"},' +
'{"channel":"my-channel-2","name":"my-event","data":"world"}]');
Retorna uma lista de canais ativos. Suporta parâmetros opcionais para filtrar os resultados e solicitar informações adicionais.
| Parameter | Descrição |
| aFilterByPrefix (opcional) | Filtra os canais por um prefixo de nome (por exemplo, "presence-" para listar apenas canais de presença). |
| aInfo (opcional) | Uma lista de atributos separados por vírgula a incluir na resposta (por exemplo, "user_count"). |
// get all channels
APIPusher.GetChannels;
// get only presence channels with user count
APIPusher.GetChannels('presence-', 'user_count');
Retorna informações sobre um canal específico.
| Parameter | Descrição |
| aChannel | O nome do canal sobre o qual obter informações. |
| aInfo (opcional) | Uma lista separada por vírgulas de atributos a incluir (por exemplo, "user_count,subscription_count"). |
// get channel info
APIPusher.GetChannel('presence-my-channel');
// get channel info with user count
APIPusher.GetChannel('presence-my-channel', 'user_count,subscription_count');
Retorna uma lista de usuários conectados a um canal de presence. O nome do canal deve incluir o prefixo completo (por exemplo, "presence-my-channel").
APIPusher.GetUsers('presence-my-channel');
Encerra todas as conexões estabelecidas por um determinado usuário. Isso pode ser utilizado para forçar um usuário específico a se desconectar de todos os canais. O ID do usuário deve corresponder ao "user_id" utilizado quando o usuário assinou um canal de presence.
APIPusher.TerminateUserConnections('1234');
A Pusher só permite assinar canais privados ou de presença; se a conexão fornecer um token de autenticação, isso permite que você restrinja o acesso.
Você pode construir seu próprio fluxo de Autenticação, utilizando o evento OnPusherAuthentication; este evento é chamado antes de a mensagem de assinatura ser assinada com a chave secreta fornecida pelo Pusher. Este evento possui 2 parâmetros: uma requisição de autenticação com campos como SocketId, nome do canal... que podem ser utilizados pelo seu próprio servidor de autenticação para autenticar ou não a requisição. Encontre abaixo uma captura de tela que mostra o fluxo de autenticação do pusher

Quando um cliente se conecta ao servidor pusher, ele envia a Key fornecida pelo pusher e o servidor retorna um id de identificação (socket_id).
Quando um cliente assina um canal privado (ou de presence), o cliente sgcWebSockets usa a Secret Key fornecida pelo pusher para criar uma assinatura que é incluída na mensagem de assinatura. Usando o evento OnPusherAutentication, você pode capturar os campos necessários para assinar a mensagem, implementar seus próprios métodos de autenticação e, se bem-sucedido, retornar a assinatura, e essa assinatura será incluída na mensagem de assinatura e enviada ao servidor.
Exemplo:
oClient := TsgcWebSocketClient.Create(nil);
oPusher := TsgcWSAPI_Pusher.Create(nil);
oPusher.Client := oClient;
oPusher.Cluster := 'eu';
Pusher.Name := 'js';
Pusher.Version := '4.1';
Pusher.TLS := True;
Pusher.Key := '9c3b7ef25qe97a00116c';
Pusher.Secret := ''; // the secret key is not known by the client, only by the authentication module
oPusher.OnPusherAuthentication := OnPusherAuthenticationEvent;
procedure OnPusherAuthenticationEvent(Sender: TObject; AuthRequest: TsgcWSPusherRequestAuthentication;
AuthResponse: TsgcWSPusherResponseAuthentication);
begin
// if the authentication request is successful return the signature
if CustomAuthentication(AuthRequest.Channel, AuthRequest.SocketID) then
AuthResponse.Signature := GetCustomAuthenticationSignature;
end;
O formato da assinatura é:
Canais privados: key:HMAC256(SocketID, ChannelName)
Canais de presença: key: HMAC256(SocketID, ChannelName, Data)
O objeto TsgcWSPusherResponseAuthentication fornece as seguintes propriedades:
| Property | Descrição |
| Secret | A chave secreta da Pusher utilizada para computar a assinatura HMAC. Pré-preenchida com Pusher.Secret se configurada. |
| Assinatura | A assinatura de autenticação computada. Se deixada vazia, o componente a calculará automaticamente utilizando o Secret. |
| SharedSecret | A chave secreta compartilhada para canais privados criptografados. Necessária ao se inscrever em pscPrivateEncryptedChannel ou pscPrivateEncryptedCacheChannel. Usada para criptografia de ponta a ponta dos dados da mensagem. |