Apenas mais um invólucro Qt para gRPC e protobuf



Há não muito tempo, fiquei intrigado com o fato de não existirem invólucros e geradores simples e convenientes e simples para protobuf e gRPC, baseados e totalmente compatíveis com o Qt. Me deparei com artigos, incluindo aqui sobre wrappers, mas seu uso me pareceu muito menos prático do que a API C ++ existente.

Um pouco sobre gRPC e protobuf


Vamos simular uma situação: você escreverá um projeto de plataforma múltipla e precisará escolher uma estrutura RPC para se comunicar com seus serviços. Você sempre pode dar um soco no peito e dizer "Eu sou o meu próprio quadro", mas parece-me que estamos vivendo uma era de soluções prontas. Uma dessas soluções nos foi apresentada por uma empresa conhecida por um longo tempo. Não presumo comparar estruturas RPC, este não é o objetivo deste artigo. Apenas para listar o que eu gosto no gRPC:

  • IDL conciso e claro
  • A presença de um grande número de geradores para várias plataformas
  • Código cliente / servidor gerado para aplicações de teste de gravação e prototipagem rápidas e fáceis

Ao ponto


Devido ao fato de o Qt estar se saindo muito bem com a reflexão de tipos e a quantidade de meta-informações geralmente estar no nível mais alto, chegou-se à conclusão de que você precisa de seu próprio gerador que gere código Qt "puro", sem intercalar bibliotecas de terceiros. Então, qtprotobufgen nasceu.

qtprotobufgen


qtprotobufgen é o gerador inerentemente mais simples, baseado na API fornecida pelo libprotoc. Caso você queira fazer algo assim para suas necessidades, deixarei um pouco de trapaça.

  • Você tem um único ponto de entrada para a classe do plugin :: google :: protobuf :: compiler :: CodeGenerator, da qual você precisa herdar
  • O método virtual Generate determina a geração ao trabalhar com um arquivo .proto separado
  • O método virtual GenerateAll determina a geração ao trabalhar com uma matriz completa de arquivos .proto fornecidos para geração ou dependência
  • O método virtual HasGenerateAll é essencialmente uma relíquia sobrevivente de versões anteriores. Return true

Devo dizer imediatamente que não havia desejo de escrever meu próprio analisador / gerador do zero, pois existe uma solução pronta dos desenvolvedores do protobuf. Mas, se desejar, você pode ler o fluxo binário que protoc emite ou escrever seu próprio analisador de arquivos proto.

Durante o desenvolvimento, surgiu uma desvantagem significativa de um gerador escrito em uma linguagem compilada: era difícil colocar a geração e a compilação em uma pilha do CMake. Devido ao fato de o Qt gerar informações de metaobjetos, com base em arquivos de cabeçalho com a macro Q_OBJECT no corpo das classes declaradas no arquivo de cabeçalho, é necessário, no estágio de configuração (leia cmake), ter uma idéia dos arquivos que o moc fornecerá para a geração de código adicional. Como solução, tive que recorrer à linguagem interpretada Go (Lang), que não criou dependências adicionais e fez seu trabalho perfeitamente, mas não passou em testes suficientes.

O gerador está sujeito às regras protoc existentes e, no momento da redação deste documento, não introduz nenhuma opção adicional de geração:

protoc --plugin=protoc-gen-qtprotobuf=<path/to/bin>/qtprotobufgen --qtprotobuf_out=<output_dir> <protofile>.proto [--qtprotobuf_opt=out=<output_dir>] 

Para simplificar e facilitar o uso, você pode usar rotinas cmake especialmente preparadas para gerar código e incorporá-las em um projeto cmake. Mais detalhes ...

Sobre bibliotecas


Não vejo muito sentido em descrever a API em detalhes. Quem desejar pode gerar documentação e ler um pouco mais sobre a API atualmente disponível.

O projeto é dividido em 2 partes lógicas qtprotobuf e qtgrpc. Pelos nomes, acho que o objetivo de cada componente é claro. Tentamos tornar o uso o mais conveniente possível, porque existem opções de integração com a biblioteca pré-montada e instalada no sistema e a integração do subprojeto no seu projeto cmake.

O código gerado é * exportado completamente para QML, o que facilita muito o trabalho com a API gRPC.

Use


Após a integração com o projeto e a execução da geração, você receberá um conjunto de arquivos de origem, que posteriormente serão coletados em uma biblioteca estática e vinculados ao seu arquivo binário. Mudanças recentes excluíram a possibilidade de registro estático dos tipos gerados e protótipos. Portanto, você precisa cuidar do registro deles no projeto:

 ... #include <QtProtobufTypes> ... int main(int argc, char *argv[]) { QtProtobuf::registerProtoTypes(); ... //   Qt  } 

No momento da redação deste artigo, não havia um método único para registrar todos os tipos gerados para um proto-pacote, portanto, você precisa chamar o método qRegisterProtobufType para todos os tipos usados ​​no aplicativo:

 ... qRegisterProtobufType<MyProtoType>(); ... 

O uso de bibliotecas e um gerador é descrito em README, e alguns exemplos acompanham o projeto. Para aqueles que não estão familiarizados com o gRPC / protobuf, sugiro que você leia a documentação oficial

Para desenvolvedores


Tentamos aderir ao TDD durante o desenvolvimento e não queremos nos afastar dele. Como nossa experiência demonstrou, o TDD economiza você ao refatorar ou atualizar a API, ajudando a detectar problemas ocultos. Portanto, se houver um desejo de contribuir, esteja preparado para escrever unidades, testes unitários e funcionais.

* Problemas conhecidos


Atualmente, existem vários problemas relacionados ao Qt. Alguns deles foram resolvidos, com ou sem a nossa participação, mas nem todos foram incluídos nos lançamentos atuais do Qt. O principal é a inacessibilidade de alguns tipos básicos de protobuf do código qml. Acho que não é segredo para ninguém que o conjunto de tipos disponíveis na QML é muito limitado, em parte devido ao uso da V8 como um mecanismo JS. Uma tentativa de tornar a QML um pouco mais amigável para tipos personalizados (por exemplo, fixed32, sint32) falhou, mas acabou por corrigir a origem do problema . A implementação atual do QtNetwork também apresenta vários problemas, mas a equipe do Qt os corrige rapidamente.
QTBUG-77852
QTBUG-76303
QTBUG-78310

Planos


Todas as atividades atuais estão relacionadas à solução de problemas no código do projeto ou no código Qt. Mas há uma quantidade bastante grande de trabalho associada à nova funcionalidade:

  1. Transição para um único par de arquivos .h / .cpp para o código gerado
  2. Implementação do servidor GRPC
  3. API de reciclagem para credenciais de gRPC
  4. Distribuição do código gerado nos diretórios e criação de plug-ins de subprojetos para carregamento separado de pacotes e módulos gerados
  5. Integração Qmake
  6. Implementação de IC

Há alguma lista de pendências, que ainda é armazenada em seu próprio repositório de projetos.

Em vez de uma conclusão, gostaria de agradecer aos camaradas do PVS-Studio pela chave fornecida para os projetos de OSS. Com a ajuda deles, eles encontraram um bug bastante crítico no código gerado.

Faça o download, veja o projeto e brinque com exemplos aqui .

Source: https://habr.com/ru/post/pt467893/


All Articles