Tag Archive | phobos

JSON-RPC 2.0 sobre WebSockets com Tufão + Phobos-RPC (Qt)

Sou uma pessoa que simpatiza com jogos e, ultimamente, estive trabalhando em um jogo orientado a disputas multiplayer pertencente ao gênero Bomberman. Para implementar a arquitetura de jogo sugerida pelo time de desenvolvimento, desenvolvi algumas bibliotecas auxiliares. E nesse post vou documentar como combinar as duas bibliotecas para permitir chamadas de métodos remotas (RPC).

A primeira biblioteca que desenvolvi para o projeto foi batizada de Phobos e sua única função é implementar o protocolo JSON-RPC 2.0. Meu objetivo principal durante seu desenvolvimento foi auxiliar o desenvolvimento do BlowThemAll e, assim sendo, alguns fatores, como arquitetura e documentação, foram deixados de lado. O projeto não tem página própria na internet e as “releases” do mesmo encontram-se na página de downloads do BlowThemAll.

Há um segundo projeto que iniciei, batizado de Tufão. É uma biblioteca desenvolvida em cima do Qt que possui uma API similar ao Node.js que pode ser usada para criar aplicações web. Desenvolvi esse projeto de forma bem disciplinada, me dedicando bastante, seja ao projetar sua arquitetura, seja ao escrever sua documentação, seja durante os testes, empacotamento para diferentes plataformas, preparação de uma página decente, criação de exemplos e documentação por fora… Caso queira saber mais sobre o mesmo, visite a página do projeto.

Pré-requisitos

 Esse texto assume que você está utilizando (e tem um pouco de familiaridade com) o QtCreator para gerenciar seus projetos e tem uma boa noção de orientação a objetos. Além disso, esse texto assume que você já instalou o Tufão no seu sistema.

Preparando um novo projeto

A primeira coisa a fazer, é baixar a biblioteca Phobos e seu “adapter” para o Tufão.

Então, usando o plugin do Tufão para o QtCreator, crie um novo projeto usando o template “application“.

Com o projeto criado, extraia o conteúdo dos arquivos baixados para a pasta do projeto e edite o arquivo *.pro do mesmo, de forma que as seguintes linhas sejam adicionadas:

Pronto, você concluiu as etapas iniciais para trabalhar com um projeto usando JSON-RPC 2.0 em C++. A etapa seguinte dependerá se o projeto criado é o servidor ou o cliente.

Preparando um novo projeto (servidor)

Grande parte da “aplicação web” já está pronta, utilizando o “esqueleto” do projeto genérico criado pelo plugin do Tufão. As alterações que você precisa fazer se resumem a criar uma classe para tratar conexões WebSocket e uma classe Handler para ser utilizada pelo RPC.

Comece criando a classe WebServer, que deve herdar de Tufao::HttpServer e deve implementar o método protegido upgrade, que deve ficar assim:

Implemente a classe Handler herdando de QObject e utilizando a macro Q_INVOKABLE na frente da declaração/assinatura dos métodos que você deseja exportar para o cliente remoto.

O último passo é editar o arquivo main.cpp, para que o mesmo utilize a classe WebServer criada. Para isso, só precisa mudar o tipo da variável server dentro da função main, de Tufao::HttpServer para WebServer.

Preparando um novo projeto (cliente)

O cliente tem uma natureza bem diferente do esqueleto genérico de aplicação criado pelo plugin do Tufão e isso requer que você faça mais mudanças que no caso do servidor.

Primeiro, apague as classes (desnecessários para o projeto) NotFound e PluginReloader. Apague também o arquivo de recursos static.qrc e seu recurso associado, notfound.html.

Segundo, apague quase todo o conteúdo da função main, para que se resuma ao seguinte:

Com isso terminaram as remoções necessários do projeto-base. Agora restam as adições, que se dividem em duas partes, relacionadas ao Tufão e relacionadas ao Phobos. Irei comentar o mínimo possível sobre o Tufão, pois o mesmo está bem documentado e torna-se desnecessário que eu faça comentários extras.

Começando pela parte do Tufão, você precisará criar um objeto da classe Tufao::WebSocket e chamar o método connectToHost. Quando o sinal connected for emitido, o objeto estará pronto para ser utilizado.

Do lado do Phobos, você precisará, assim como no servidor, de um objeto Handler, que herde da classe QObject e utilize a macro Q_INVOKABLE na frente da declaração/assinatura dos métodos que você deseja exportar para o servidor remoto (o protocolo JSON-RPC não distingue servidor de cliente e, uma vez iniciada a conexão, ambos podem realizar chamadas remotas, enquanto a camada de transporte permitir).

Invocando métodos remotos

Para chamar métodos remotos, utilize o método JsonRpc::callWith. Os dois primeiros argumentos que ele recebe lembram o método singleShot da classe QTimer, com a diferença que a macro SLOT não cerca o argumento member no método callWith. Os argumentos restantes representam, respectivamente, o nome do método remoto e seus argumentos. Exemplificando:

Be happy

Você pode obter o código-fonte das aplicações desenvolvidas nesse texto aqui.

Anúncios

JSON-RPC 2.0 com Phobos e Deimos

JSON-RPC é uma especificação que descreve como implementar técnicas RPC no seu sistema usando como base o formato JSON. O formato JSON é mais enxuto que o XML na maior parte dos casos, por possuir tipos primitivos como ints, floats e strings nativamente e não possuir a redundância que as tags do xml criam. Trabalhando no projeto BlowThemAll, cujo objetivo é criar um jogo no estilo do clássico Bomberman, mas que não só supere-o, mas também o leve a outro limite, o time optou por utilizar o JSON-RPC, versão 2.0, para toda comunicação entre os nós. Surgiu assim a necessidade de duas implementações (Qt e node.js) do JSON-RPC 2.0, e dessa necessidade surgiram as implementações Phobos & Deimos.

Phobos

Phobos é uma implementação do JSON-RPC 2.0 para Qt. Por não ter encontrado nenhuma implementação suficientemente boa para o jogo, eu a criei do 0. Possui as seguintes características:

  • Simétrica: Os dois lados da conexão podem enviar e receber chamadas remotas.
  • Completamente assíncrono: Graças ao padrão de signals & slots do Qt e seu loop de eventos, você pode tratar todas as chamadas em um sistema orientado a eventos, e tudo ocorrendo em uma mesma thread.
  • Simples: Há somente 3 classes para todo o projeto.
  • Completamente abstrata da camada de transporte: O que minha implementação faz é avisar quando há novas mensagens (que são do tipo QByteArray) para serem enviadas e disponibiliza métodos para tratar mensagens recebidas. Assim, caso você forneça um meio de transporte orientado a mensagens, pode utilizá-la para rodar no topo de qualquer camada (TCP, HTTP, …).
  • Não possui suporte a Batch (funcionalidade que só tem utilidade quando a camada de transporte é HTTP) e é licenciada sob os termos da licença GNU LGPL v3.

Nota: Phobos utiliza algumas características do novo padrão C++. Foi testada com o GCC 4.6.

Instalação/configuração

Há duas formas principais de configurar seu projeto para utilizar essa biblioteca. Um dos meios é embutir o código-fonte dela no seu projeto, cujo build precisa ser baseado no qmake. Esse é o meio de incluir a biblioteca “estaticamente”. Note que assim seu programa precisaria estar licenciado sob alguma licença compatível com a licença do projeto.

A outra forma de configurar a biblioteca seria configurando uma linkagem dinâmica, o que não colocaria nenhuma restrição de licenciamento no seu projeto. Por motivos de força maior (preguiça), colocarei aqui somente o meio fácil de configurar a biblioteca, que é embutindo seu código-fonte, mas acredito que se você tem experiência com Qt, não precisará de minha ajuda para configurar uma linkagem dinâmica.

NOTA: A Phobos depende de outra biblioteca para fazer o parse dos objetos JSON, a QJson. Não é complicado instalá-la. Ela possui arquivos para projetos a usarem através do cmake e do pkfconfig (o que eu uso) e está disponível no repositório oficial das distribuições linux mais importantes.

Baixe o arquivo phobos-1.0.tar.bz2 aqui e descompacte na raiz do seu projeto. Feito isso, adicione as seguintes linhas no arquivo .pro de seu projeto:

Agora seu projeto está pronto para utilizar a biblioteca.

Uso

Para implementar um sistema que se comunique através de JSON-RPC 2.0 usando a implementação Phobos, crie um objeto da classe Phobos::Peer e faça a conexão correta dos sinais:

Você então terá a responsabilidade de tratar o envio e o recebimento das mensagens. Caso esteja trabalhando com TCP, uma solução simples seria:

Agora o objeto peer está pronto para uso. Ele irá emitir o sinal readyRequest(QSharedPointer<Phobos::ResponseHandler>) sempre que uma nova requisição for recebida e o sinal readyResponse(QVariant,QVariant) quando houver uma nova resposta para uma de suas requisições, que são realizadas chamando o método call.

Há um exemplo completo na pasta phobos/examples e a documentação nos arquivos de cabeçalho está bem completa. Pretendo implementar as classes TcpHelper e HttpHelper, que irão tratar o envio e recebimento de mensagens para você, na versão 1.1.

Deimos

Deimos é uma implementação em javascript para node.js que apenas trata requisições/chamadas (você não pode usá-lo para fazer requisições/chamadas). Foi baseada no node-jsonrpc, que implementa o padrão 1.0 do formato. Deimos é uma implementação completa que suporta ambas as versões (1.0 e 2.0) do JSON-RPC e é licenciada sob a licença MIT.

Instalação

Sua instalação é muito simples, e requer apenas que você execute o seguinte comando dentro da pasta do seu projeto node.js:

Uso

Para permitir que seu servidor trate requisições JSON-RPC, primeiro importe a classe RpcHandler do módulo deimos:

Então toda vez que você receber uma requisição POST, pode tratá-la criando um novo objeto RpcHandler, passando como parâmetros os objetos request, response e um objeto contendo os métodos disponíveis:

Há um quarto argumento que o construtor de RpcHandler recebe, opcional, que indica se o modo de debug deve ser ativado. Se um dos métodos do objeto methods disparar uma exceção, o objeto RpcHandler vai responder com “Internal error” e a resposta pode ou não incluir a mensagem descrevendo a exceção, dependendo se o modo de debug está ou não ativo.

Suas funções sempre devem enviar uma mensagem de resposta exatamente uma vez. Essa mensagem é gerada automaticamente quando você chama response ou error (e suas variações). Se você quiser esconder sua função, simplesmente use o método methodNotFound. Verifique o arquivo deimos.js e a documentação do JSON-RPC 2.0 para mais informações.

Um pouco de cultura

Phobos e Deimos eram os deuses do horror e do terror, na mitologia grega. Eram irmãos-gêmeos, filhos de Ares, deus da guerra (fonte: wikipédia).

UPDATE:

Biblioteca Phobos atualizada (versão 1.1). Agora inclui as classes TcpHelper e HttpHelper, que abstraem o tratamento da camada de comunicação.

%d blogueiros gostam disto: