Saltar al contenido principal
Versión: 0.3.0

gRPC

El servidor está construido con Connect-RPC, así que los mismos handlers responden a gRPC (HTTP/2), gRPC-Web y el protocolo Connect. Escucha con h2c, por lo que gRPC funciona sin TLS delante; en producción un proxy inverso termina el TLS.

Generar un cliente​

El contrato vive en proto/openbeehive/v1 y se compila con buf. El buf.gen.yaml del repositorio genera Go (protocolbuffers/go + connectrpc/go) en server/internal/gen y TypeScript (bufbuild/es v2) en app/src/lib/proto. Ambos directorios de salida están en el gitignore; ejecuta make proto después de clonar. Para otro lenguaje, copia el directorio proto/ y apunta tu propio buf.gen.yaml a los plugins que necesites.

Go​

import (
"connectrpc.com/connect"
obv1 "github.com/openbeehive-org/openbeehive-app/server/internal/gen/openbeehive/v1"
"github.com/openbeehive-org/openbeehive-app/server/internal/gen/openbeehive/v1/openbeehivev1connect"
)

client := openbeehivev1connect.NewApiaryServiceClient(http.DefaultClient, "https://bees.example.com")
req := connect.NewRequest(&obv1.ListApiariesRequest{})
req.Header().Set("Authorization", "Bearer "+token)
res, err := client.ListApiaries(ctx, req)

Cada uno de los diez servicios tiene su propio constructor de cliente (NewApiaryServiceClient, NewHiveServiceClient, NewQueenServiceClient, NewInspectionServiceClient, NewTaskServiceClient, NewTreatmentServiceClient, NewHarvestServiceClient, NewEventServiceClient, NewStatsServiceClient, NewSyncServiceClient). Una báscula de colmena, por ejemplo, publica a través de InspectionService:

insp := openbeehivev1connect.NewInspectionServiceClient(http.DefaultClient, "https://bees.example.com")
req := connect.NewRequest(&obv1.CreateInspectionRequest{HiveId: hiveID, WeightKg: 42.5, TempHive: 34.2})
req.Header().Set("Authorization", "Bearer "+token)
res, err := insp.CreateInspection(ctx, req)

El paquete generado es internal al módulo del servidor, así que un programa Go aparte tiene que generar su propia copia a partir de los archivos .proto.

TypeScript​

El propio cliente de la aplicación está en app/src/lib/client.ts:

import { createClient } from '@connectrpc/connect';
import { createConnectTransport } from '@connectrpc/connect-web';
import { SyncService } from './proto/openbeehive/v1/sync_pb';

const transport = createConnectTransport({ baseUrl: origin, interceptors: [authInterceptor] });
export const syncClient = createClient(SyncService, transport);

authInterceptor establece Authorization: Bearer <token> a partir de la sesión almacenada.

Desde la shell​

buf curl habla los tres protocolos usando el esquema del repositorio:

cd openbeehive-app
buf curl --schema . \
--header "Authorization: Bearer $TOKEN" \
--data '{"apiaryId":"2b1f6c0e-..."}' \
https://bees.example.com/openbeehive.v1.HiveService/ListHives

Añade --protocol grpc para forzar gRPC en lugar de Connect.

Autenticación​

Envía una clave API (obhk_..., creada en Ajustes → Claves API) o un token de sesión como cabecera Authorization: Bearer <token> (metadatos gRPC); token en los fragmentos anteriores es cualquiera de los dos. La cookie obh_session también se acepta para los tokens de sesión. El mismo interceptor verifica ambos tipos y cubre por igual las llamadas unarias y el stream Subscribe. Una instancia sin ningún método de inicio de sesión configurado no necesita cabecera. Consulta la visión general.

Subscribe​

rpc Subscribe(SubscribeRequest) returns (stream SubscribeEvent);
message SubscribeRequest { string cursor = 1; }
message SubscribeEvent { string server_cursor = 1; }

El servidor sondea su contador global de cambios cada dos segundos y envía un SubscribeEvent cada vez que el contador ha avanzado más allá del cursor que enviaste (y del último valor que envió). El evento no lleva datos; llama a Pull con tu cursor almacenado cuando recibas uno. Las filas fuera de tus ámbitos también hacen avanzar el contador, así que un Pull tras un evento puede volver vacío.

La aplicación no usa Subscribe. Hace push y pull cada 15 segundos, tras cada escritura local y en el evento online del navegador.