API SignalRCore

SignalRCore

 

O ASP.NET Core SignalR é uma biblioteca de código aberto que simplifica a adição de funcionalidades web em tempo real a aplicações. A funcionalidade web em tempo real permite que o código do lado do servidor envie conteúdo aos clientes instantaneamente.

 

Bons candidatos para o SignalR:

 

 

O componente sgcWebSockets SignalRCore utiliza WebSocket como transporte para se conectar a um servidor SignalRCore; se este transporte não for suportado, um erro será gerado.

 

Hubs

SignalRCore utiliza hubs para comunicação entre clientes e servidores. SignalRCore fornece 2 protocolos de hub: protocolo de texto baseado em JSON e protocolo binário baseado em MessagePack. O componente sgcWebSockets implementa apenas o protocolo de texto JSON para comunicação com servidores SignalRCore.

Para configurar qual Hub o cliente utilizará, basta definir o nome do Hub na propriedade SignalRCore/Hub antes de o cliente se conectar ao servidor.

 

Conexão

Quando um cliente abre uma nova conexão com o servidor, envia uma mensagem de requisição que contém o protocolo de formato e a versão. O sgcWebSockets sempre envia o protocolo de formato como JSON. O servidor responderá com um erro se o protocolo não for suportado por ele; este erro pode ser tratado utilizando o evento OnSignalRCoreError, e se a conexão for bem-sucedida, o evento OnSignalRCoreConnect será chamado.

 

Quando um cliente se conecta a um servidor SignalRCore, ele pode enviar um ConnectionId que identifica o cliente entre sessões, de modo que, se você tiver uma desconexão, o cliente possa reconectar ao servidor passando o mesmo connection id anterior. Para obter um novo connection id, basta conectar normalmente ao servidor e você pode saber o ConnectionId utilizando OnBeforeConnectEvent. Se você quiser reconectar ao servidor e passar um connection id anterior, utilize o método ReConnect e passe ConnectionId como parâmetro.

 

 

Protocolo SignalRCore

O Protocolo SignalR é um protocolo para RPC bidirecional sobre qualquer transporte baseado em mensagens. Qualquer uma das partes na conexão pode invocar procedimentos na outra parte, e os procedimentos podem retornar zero ou mais resultados ou um erro. Exemplo: o cliente pode solicitar um método do servidor e o servidor pode solicitar um método do cliente. As seguintes mensagens são trocadas entre o servidor e os clientes:

 

 

 

SignalRCore Encoding

 

O SignalRCore permite que você use as seguintes codificações:

 

 

Atualmente, apenas JSON é suportado, embora MessagePack possa ser utilizado codificando as mensagens enviadas por meio de uma biblioteca messagepack externa. Veja a seção MessagePack abaixo para mais informações.

 

A configuração do Protocolo de Codificação é definida na propriedade SignalRCore.Protocol. Por padrão, o valor é srcpJSON.

 

Autorização

A autenticação pode ser habilitada para associar um usuário a cada conexão e filtrar quais usuários podem acessar recursos. A autenticação é implementada utilizando Bearer Tokens: o cliente fornece um access token e o servidor valida este token e o utiliza para identificar o usuário.

Em Web APIs padrão, os bearer tokens são enviados em um Cabeçalho HTTP, mas ao usar websockets, o token é transmitido como um parâmetro de query string.

Os seguintes métodos são suportados:

 

srcaRequestToken

 

Se a Autenticação estiver habilitada, o fluxo é:

 

1. Primeiro tenta obter um token válido do servidor. Abre uma conexão HTTP contra Authentication.RequestToken.URL e faz um POST utilizando os dados de User e Password.

2. Se a anterior for bem-sucedida, um token é retornado. Caso contrário, um erro é retornado.

3. Se um token for retornado, então abre uma nova conexão HTTP para negociar uma nova conexão. Aqui, o token é passado como um Cabeçalho HTTP.

4. Se o anterior for bem-sucedido, abre uma conexão websocket e passa o token como parâmetro de query string.

 

 

srcaSetToken

 

Aqui, você passa o token diretamente para o servidor SignalRCore (porque o token foi obtido de outro servidor).

 

 

 

O Access token pode ser enviado como parâmetro de query (esta é a opção padrão) ou enviado como cabeçalho HTTP como um Bearer Token. Use a propriedade Authentication.TokenParam para configurar este comportamento.

 

 

 

srcaBasic

 

Esta opção usa Basic Authentication, este método de autenticação requer a configuração do componente SignalRCore e do TsgcWebSocketClient.

 

Exemplo: se o servidor exige basic authentication e o nome de usuário é "user" e a senha é "secret", configure os componentes conforme mostrado abaixo.

 


// websocket client
WSClient := TsgcWebSocketClient.Create(nil);
WSClient.Authentication.Enabled := True;
WSClient.Authentication.Basic.Enabled := True;
WSClient.Authentication.URL.Enabled := False;
WSClient.Authentication.Session.Enabled := False;
WSClient.Authentication.Token.Enabled := False;
WSClient.Authentication.User := 'user';
WSClient.Authentication.Password := 'secret';
// signalrcore
Signal := TsgcWSAPI_SignalRCore.Create(nil);
Signal.SignalRCore.Authentication.Enabled := True;
Signal.SignalRCore.Authentication.Authentication := srcaBasic;
Signal.SignalRCore.Authentication.Username := 'user';
Signal.SignalRCore.Authentication.Password := 'secret';
Signal.Client := WSClient;

 

Comunicação entre Cliente e Servidor

Há três tipos de interações entre servidor e clientes:

 

Invocations

O Caller envia uma mensagem ao Callee e espera uma mensagem indicando que a invocação foi concluída e, opcionalmente, um resultado da invocação

Exemplo: o cliente invoca o método SendMessage e passa como parâmetros o nome de usuário e a mensagem de texto. Envia um Invocation Id para
obter uma mensagem de resultado do servidor.


SignalRCore.Invoke('SendMessage', ['John', 'Hello All.'], 'id-000001');
 
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
  if Completion.Error <> '' then
    ShowMessage('Something goes wrong.')
  else
    ShowMessage('Invocation Successful!');
end;

Invocações Não Bloqueantes

O Caller envia uma mensagem ao Callee e não espera mais nenhuma mensagem para esta invocação. As invocações podem ser enviadas sem um valor de Invocation ID. Isto indica que a invocação é "non-blocking".

Exemplo: o cliente invoca o método SendMessage e passa como parâmetros o nome do usuário e a mensagem de texto. O cliente não espera nenhuma resposta do servidor sobre o resultado da invocação.

 


SignalRCore.Invoke('SendMessage', ['John', 'Hello All.']);

Streaming Invocations

O Caller envia uma mensagem ao Callee e espera um ou mais resultados retornados pelo Callee, seguidos por uma mensagem indicando o fim da invocação.

Exemplo: o cliente invoca o método Counter e solicita 10 números com um intervalo de 500 milissegundos.


SignalRCore.InvokeStream('Counter', [10, 500], 'id-000002');
 
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
  DoLog('#stream item: ' + StreamItem.Item);
end;
 
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
  if Completion.Error  '' then
    ShowMessage('Something goes wrong.')
  else
    ShowMessage('Invocation Successful!');
end;

Invocations

Para realizar uma única invocação, o Caller segue o seguinte fluxo básico:


procedure Invoke(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String = '');
procedure InvokeStream(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String);

Aloque um valor único de Invocation ID (string arbitrária, escolhida pelo Caller) para representar a invocação. Chame o método Invoke ou InvokeStream contendo o Target sendo invocado, Arguments e InvocationId (se você não enviar InvocationId, não obterá o resultado de conclusão).

 

Se a Invocation estiver marcada como não-bloqueante (consulte "Non-Blocking Invocations" abaixo), pare aqui e retorne imediatamente o controle à aplicação. Trate a mensagem StreamItem ou Completion com um Invocation ID correspondente.


SignalRCore.InvokeStream('Counter', [10, 500], 'id-000002');
 
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
  if StreamItem.InvocationId = 'id-000002' then
    DoLog('#stream item: ' + StreamItem.Item);
end;
 
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
  if StreamItem.InvocationId = 'id-000002' then
  begin
    if Completion.Error  '' then
      ShowMessage('Something goes wrong.')
    else
      ShowMessage('Invocation Successful!');
  end;
end;

Você pode realizar uma única invocação e aguardar a conclusão.

 


function InvokeAndWait(const aTarget: String; aArguments: Array of Const; aInvocationId: String; out Completion: TSignalRCore_Completion; 
  const aTimeout: Integer = 10000): Boolean;
function InvokeStreamAndWait(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String; 
  out Completion: TSignalRCore_Completion; const aTimeout: Integer = 10000): Boolean;

Aloque um valor de Invocation ID único (string arbitrária, escolhida pelo Caller) para representar a invocação. Chame o método InvokeAndWait ou InvokeStreamAndWait contendo o Target sendo invocado, os Arguments e o InvocationId. O programa aguardará até que o evento de conclusão seja chamado ou o Time out seja excedido.


var
  oCompletion: TSignalRCore_Completion;
begin
  if SignalRCore.InvokeStreamAndWait('Counter', [10, 500], 'id-000002', oCompletion) then
    DoLog('#invoke stream ok: ' + oCompletion.Result)
  else
    DoLog('#invocke stream error: ' + oCompletion.Error);
  
 
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
  if StreamItem.InvocationId = 'id-000002' then
    DoLog('#stream item: ' + StreamItem.Item);
end;

Cancel Invocation

Se o cliente quiser parar de receber mensagens StreamItem antes que o Servidor envie uma mensagem Completion, o cliente pode enviar uma mensagem CancelInvocation com o mesmo InvocationId utilizado na mensagem StreamInvocation que iniciou o stream.


procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: SignalRCore_StreamItem; var Cancel: Boolean);
begin
  if StreamItem.InvocationId = 'id-000002' then
    Cancel := True;
end;

Resultados do Cliente

 

Uma Invocation só é considerada concluída quando a mensagem Completion é recebida. Se o cliente receber uma Invocation do servidor, o evento OnSignalRCoreInvocation será chamado.


procedure OnSignalRCoreInvocation(Sender: TObject; Invocation: TSignalRCore_Invocation);
begin
  if Invocation.Target = 'SendMessage' then
    ... your code here ...
end;
// Once invocation is completed, call Completion method to inform server invocation is finished.
// If result is successful, then call CompletionResult method:
SignalRCore.CompletionResult('id-000002', 'ok');
 
// If not, then call CompletionError method:
SignalRCore.CompletionError('id-000002', 'Error processing invocation.');

Close Connection

 

Enviado pelo cliente quando uma conexão é fechada. Contém um motivo de erro se a conexão foi fechada por causa de um erro.


SignalRCore.Close('Unexpected message').
  
// If the server close connection by any reason, OnSignalRCoreClose event will be called. 
procedure OnSignalRCoreClose(Sender: TObject; Close: TSignalRCore_Close);
begin
  DoLog('#closed: ' + Close.Error);
end;

Ping

O protocolo SignalR Hub suporta mensagens "Keep Alive" utilizadas para garantir que a conexão de transporte subjacente permaneça ativa. Essas mensagens ajudam a garantir:

Que proxies não fechem a conexão subjacente durante períodos ociosos (quando poucas mensagens estão sendo enviadas). Se a conexão subjacente for derrubada sem ser encerrada graciosamente, a aplicação é informada o mais rápido possível.

O comportamento keep alive é obtido chamando o método Ping ou habilitando o HeartBeat no cliente WebSocket. Se o servidor enviar um ping ao cliente, o cliente enviará automaticamente uma resposta e o evento OnSignalRCoreKeepAlive será chamado.


procedure OnSignalRCoreKeepAlive(Sender: TObject);
begin
  DoLog('#keepalive');
end;

MessagePack

Na Codificação MsgPack do Protocolo SignalR, cada Mensagem é representada como um único array MsgPack contendo itens que correspondem às propriedades da mensagem do hub protocol fornecido. Os itens do array podem ser valores primitivos, arrays (por exemplo, argumentos de método) ou objetos (por exemplo, valor de argumento). O primeiro item do array é o tipo da mensagem.

 

Consulte a documentação do MessagePack para ver como codificar as mensagens enviadas.

 

Toda vez que uma nova mensagem é recebida, ela é despachada no evento OnSignalRCoreMessagePack. A mensagem pode ser acessada lendo o parâmetro Data Stream. O parâmetro JSON está vazio por padrão; se você converter a mensagem MessagePack em JSON, o componente processará a mensagem JSON como se a codificação estivesse utilizando JSON (de modo que os eventos OnSignalRCoreCompletion, OnSignalRCoreInvocation... serão despachados).