Solo otro contenedor Qt para gRPC y protobuf



No hace mucho tiempo, me sorprendió el hecho de que no hay suficientes envoltorios y generadores simples y convenientes para protobuf y gRPC, basados ​​y totalmente compatibles con Qt. Encontré artículos, incluyendo aquí sobre envoltorios, pero su uso me pareció mucho menos práctico que incluso la API C ++ existente.

Un poco sobre gRPC y protobuf


Simulemos una situación: vas a escribir un proyecto multiplataforma y debes elegir un marco RPC para comunicarte con tus servicios. Siempre puedes golpearte en el pecho y decir "Soy mi propio marco", pero me parece que estamos viviendo en una era de soluciones listas para usar. Una de esas soluciones nos fue presentada por una empresa reconocida durante mucho tiempo. No pretendo comparar marcos RPC, este no es el propósito de este artículo. Solo para enumerar lo que me gusta de gRPC:

  • IDL conciso y claro
  • La presencia de una gran cantidad de generadores para varias plataformas.
  • Código de cliente / servidor generado para la creación rápida y sencilla de prototipos y aplicaciones de prueba de escritura

Al punto


Debido a que a Qt le está yendo bastante bien con la reflexión de tipo, y la cantidad de metainformación generalmente está en el nivel más alto, se dio cuenta de que necesita su propio generador que generaría un código Qt "puro", sin intercalar bibliotecas de terceros. Así nació qtprotobufgen.

qtprotobufgen


qtprotobufgen es el generador inherentemente más simple, que se basa en la API proporcionada por libprotoc. En caso de que quieras hacer algo así para tus necesidades, te dejaré un poco de trampa.

  • Tiene un único punto de entrada a la clase de complemento :: google :: protobuf :: compilador :: CodeGenerator, del cual necesita heredar
  • Generar método virtual determina la generación cuando se trabaja con un archivo .proto separado
  • El método virtual GenerateAll determina la generación cuando se trabaja con una matriz completa de archivos .proto proporcionados para generar o ser dependencias.
  • El método virtual HasGenerateAll es esencialmente una reliquia que sobrevive de versiones anteriores. Volver verdadero

Debo decir de inmediato que no había ningún deseo de escribir mi propio analizador / generador desde cero, ya que existe una solución preparada por los desarrolladores de protobuf. Pero si lo desea, puede leer la secuencia binaria que emite el protocolo o escribir su propio analizador de protoarchivos.

Durante el desarrollo, surgió un inconveniente significativo de un generador escrito en un lenguaje compilado: era difícil poner la generación y la compilación en una pila CMake. Debido al hecho de que Qt genera información de metaobjetos, basándose en los archivos de encabezado que tienen la macro Q_OBJECT en el cuerpo de las clases declaradas en el archivo de encabezado, es necesario en la etapa de configuración (leer cmake) tener una idea de los archivos que moc proporcionará para la generación de código adicional. Como solución, tuve que recurrir al lenguaje interpretado Go (Lang), que no creó dependencias adicionales e hizo su trabajo perfectamente, pero no pasó suficientes pruebas.

El generador está sujeto a las reglas de protocolo existentes y, al momento de escribir, no presenta ninguna opción de generación adicional:

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

Por simplicidad y facilidad de uso, puede usar rutinas cmake especialmente preparadas para generar código e incrustarlas en un proyecto cmake. Más detalles ...

Sobre bibliotecas


No veo mucho sentido describir la API en detalle. Aquellos que lo deseen pueden generar documentación y leer un poco más sobre la API disponible actualmente.

El proyecto se divide en 2 partes lógicas qtprotobuf y qtgrpc. Por los nombres, creo que el propósito de cada componente es claro. Intentamos hacer el uso lo más conveniente posible, porque hay opciones de integración con la biblioteca preensamblada e instalada en el sistema, y ​​la integración del subproyecto en su proyecto cmake.

El código generado se exporta * completamente a QML, lo que hace que trabajar con la API gRPC sea mucho más fácil.

Uso


Después de integrarse con el proyecto y realizar la generación, recibirá un conjunto de archivos fuente, que luego se recopilarán en una biblioteca estática y se vincularán a su archivo binario. Los cambios recientes excluyeron la posibilidad de registro estático de generados y prototipos. Por lo tanto, debe encargarse de su registro en el proyecto:

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

En el momento de la escritura, no existe un método único para registrar todos los tipos generados para un paquete prototipo, por lo que debe llamar al método qRegisterProtobufType para todos los tipos utilizados en la aplicación:

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

El uso de bibliotecas y un generador se describe en README, y un par de ejemplos acompañan el proyecto. Para aquellos que no están familiarizados con gRPC / protobuf, les sugiero que lean la documentación oficial

Para desarrolladores


Intentamos adherirnos a TDD durante el desarrollo, y no queremos desviarnos de él. Como ha demostrado nuestra experiencia, TDD le ahorra al refactorizar o actualizar la API, ayuda a detectar problemas ocultos. Por lo tanto, si desea contribuir, prepárese para escribir unidades, pruebas unitarias y funcionales.

* Problemas conocidos


Actualmente hay una serie de problemas relacionados con Qt. Algunos de ellos se resolvieron, con la nuestra o sin nuestra participación, pero no todos se incluyeron en las versiones actuales de Qt. El principal es la inaccesibilidad de algunos tipos básicos de protobuf del código qml. Creo que no es ningún secreto para nadie que el conjunto de tipos disponibles en QML es muy limitado, en parte debido al uso de V8 como motor JS. Un intento de hacer que QML sea un poco más amigable con los tipos personalizados (por ejemplo, fixed32, sint32) falló, pero resultó solucionar el origen del problema . La implementación actual de QtNetwork también tiene varios problemas, pero el equipo de Qt los soluciona rápidamente.
QTBUG-77852
QTBUG-76303
QTBUG-78310

Planes


Todas las actividades actuales están relacionadas con la resolución de problemas en el código del proyecto o en el código Qt. Pero hay una gran cantidad de trabajo asociado con la nueva funcionalidad:

  1. Transición a un solo par de archivos .h / .cpp para el código generado
  2. Implementación del servidor GRPC
  3. API de reciclaje para credenciales gRPC
  4. Distribución del código generado en directorios y creación de complementos de subproyectos para cargar por separado los paquetes y módulos generados
  5. Integración Qmake
  6. Implementación de CI

Hay algunos trabajos pendientes, que todavía se almacenan en su propio repositorio de proyectos.

En lugar de una conclusión, me gustaría dar las gracias a los camaradas de PVS-Studio por la clave proporcionada para los proyectos de OSS. Con su ayuda, encontraron un error bastante crítico en el código generado.

Descargar, ver el proyecto y jugar con ejemplos aquí .

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


All Articles