Google Cloud Storage es el servicio de almacenamiento de objetos de Google. Los datos viven en buckets, y cada bucket contiene objetos (archivos) que subes, listas, lees y eliminas. La mayoría del código Delphi lo alcanza a través de la API REST JSON, pero el servicio de almacenamiento también expone una API gRPC que habla Protocol Buffers sobre HTTP/2. sgcWebSockets Enterprise incluye un cliente gRPC de Cloud Storage tipado construido sobre TsgcGRPCClient, así que puedes manejar buckets y objetos desde Delphi y C++Builder sin ningún runtime externo ni stubs generados.
Cómo funciona
La API gRPC de Storage vive en storage.googleapis.com:443 y habla el servicio google.storage.v2.Storage. sgcWebSockets ya incluye una pila HTTP/2 completa, así que el cliente tipado se apoya sobre un transporte TsgcHTTP2Client con TLS habilitado. TsgcGRPCClient hace el enmarcado gRPC, las cabeceras y la gestión de timeouts, abre el stream HTTP/2, y analiza la respuesta y los trailers de vuelta en un TsgcGRPCResponse.
La capa tipada está en la unidad sgcGRPC_Google_Storage. Te da clases de petición y respuesta como TsgcGRPCStorageListBucketsRequest, TsgcGRPCStorageListObjectsResponse y TsgcGRPCStorageBucket que se serializan a sí mismas hacia y desde Protocol Buffers. Estableces propiedades tipadas, llamas a ToBytes para obtener la carga de la petición, la envías con Call, y cargas la respuesta con LoadFromBytes. Sin compilador de protobuf, sin etiquetas de campo escritas a mano.
La autenticación usa una cuenta de servicio de Google. El cliente firma un JSON Web Token a partir de la clave de la cuenta de servicio y lo presenta como un token Bearer en la metadata authorization de gRPC, que es la forma estándar en que Google Cloud autoriza las llamadas servidor a servidor.
Configurar el transporte
Un canal gRPC no es más que una conexión HTTP/2. Apunta un TsgcHTTP2Client al endpoint de almacenamiento con TLS activado, luego adjúntalo a TsgcGRPCClient y selecciona el content type binario de Protocol Buffers.
uses
sgcHTTP2_Client, sgcGRPC_Client, sgcGRPC_Types, sgcGRPC_Google_Storage;
var
HTTP2: TsgcHTTP2Client;
GRPC: TsgcGRPCClient;
begin
HTTP2 := TsgcHTTP2Client.Create(nil);
HTTP2.Host := 'storage.googleapis.com';
HTTP2.Port := 443;
HTTP2.TLS := True;
GRPC := TsgcGRPCClient.Create(nil);
GRPC.Client := HTTP2;
GRPC.ChannelOptions.ContentType := grpcProto;
GRPC.ChannelOptions.Compression := grpcNoCompression;
HTTP2.Active := True;
end;
Autenticación con una cuenta de servicio
Carga la clave JSON de la cuenta de servicio, configura un JWT firmado para el endpoint de almacenamiento, y coloca el token resultante en DefaultMetadata para que viaje en cada llamada. El JWT de cuenta de servicio autofirmado está vinculado a la audiencia, así que el API_Endpoint debe apuntar a storage.googleapis.com para que el token sea aceptado.
var
Cloud: TsgcHTTPGoogleCloud_PubSub_Client;
begin
Cloud := TsgcHTTPGoogleCloud_PubSub_Client.Create(nil);
Cloud.LoadSettingsFromFile('service-account.json');
Cloud.GoogleCloudOptions.Authentication := gcaJWT;
Cloud.GoogleCloudOptions.JWT.API_Endpoint := 'https://storage.googleapis.com/';
// OnAuthToken fires when the token is ready; copy it into the gRPC metadata
GRPC.DefaultMetadata.Clear;
GRPC.DefaultMetadata.Add('authorization', 'Bearer ' + Token);
end;
Listar buckets
Para enumerar los buckets de un proyecto, rellena un TsgcGRPCStorageListBucketsRequest con el proyecto como Parent, serialízalo, y haz un Call unario al método ListBuckets. Los bytes de la respuesta se cargan directamente en un TsgcGRPCStorageListBucketsResponse, que expone cada bucket con su nombre y ubicación.
var
oRequest: TsgcGRPCStorageListBucketsRequest;
oResponse: TsgcGRPCResponse;
oBuckets: TsgcGRPCStorageListBucketsResponse;
i: Integer;
begin
oRequest := TsgcGRPCStorageListBucketsRequest.Create;
try
oRequest.Parent := 'projects/' + ProjectId;
oRequest.PageSize := 100;
oResponse := GRPC.Call('google.storage.v2.Storage', 'ListBuckets',
oRequest.ToBytes);
finally
oRequest.Free;
end;
if oResponse.StatusCode = grpcOK then
begin
oBuckets := TsgcGRPCStorageListBucketsResponse.Create;
try
oBuckets.LoadFromBytes(oResponse.Data);
for i := 0 to oBuckets.BucketCount - 1 do
Memo1.Lines.Add(oBuckets.Bucket(i).Name + ' (location: ' +
oBuckets.Bucket(i).Location + ')');
finally
oBuckets.Free;
end;
end;
end;
Crear un bucket
Crear un bucket sigue el mismo patrón con TsgcGRPCStorageCreateBucketRequest. Establece el proyecto parent, el id del nuevo bucket, y el proyecto propietario del recurso bucket, luego llama a CreateBucket. La respuesta lleva el TsgcGRPCStorageBucket creado.
var
oRequest: TsgcGRPCStorageCreateBucketRequest;
oResponse: TsgcGRPCResponse;
begin
oRequest := TsgcGRPCStorageCreateBucketRequest.Create;
try
oRequest.Parent := 'projects/' + ProjectId;
oRequest.BucketId := 'my-new-bucket';
oRequest.Bucket.Project := 'projects/' + ProjectId;
oResponse := GRPC.Call('google.storage.v2.Storage', 'CreateBucket',
oRequest.ToBytes);
finally
oRequest.Free;
end;
end;
Listar objetos en un bucket
Listar los objetos de un bucket usa TsgcGRPCStorageListObjectsRequest. El parent es el nombre del recurso bucket, en la forma projects/_/buckets/<bucket>. La respuesta te da el nombre, el tamaño y el content type de cada objeto, y opcionalmente puedes establecer Prefix y Delimiter para recorrer una jerarquía tipo carpeta.
var
oRequest: TsgcGRPCStorageListObjectsRequest;
oResponse: TsgcGRPCResponse;
oObjects: TsgcGRPCStorageListObjectsResponse;
i: Integer;
begin
oRequest := TsgcGRPCStorageListObjectsRequest.Create;
try
oRequest.Parent := 'projects/_/buckets/' + BucketName;
oRequest.PageSize := 100;
oResponse := GRPC.Call('google.storage.v2.Storage', 'ListObjects',
oRequest.ToBytes);
finally
oRequest.Free;
end;
if oResponse.StatusCode = grpcOK then
begin
oObjects := TsgcGRPCStorageListObjectsResponse.Create;
try
oObjects.LoadFromBytes(oResponse.Data);
for i := 0 to oObjects.ObjectCount - 1 do
Memo1.Lines.Add(oObjects.Object_(i).Name + ' (size: ' +
IntToStr(oObjects.Object_(i).Size) + ', type: ' +
oObjects.Object_(i).ContentType + ')');
finally
oObjects.Free;
end;
end;
end;
Leer y escribir datos de objetos
Más allá de los metadatos de bucket y objeto, la unidad también cubre las cargas de los objetos. TsgcGRPCStorageReadObjectRequest lee bytes de vuelta de un objeto, con ReadOffset y ReadLimit opcionales para descargas por rango, y la respuesta correspondiente expone los bytes Data en bruto. TsgcGRPCStorageWriteObjectRequest sube el contenido del objeto en trozos: establece el recurso WriteObjectSpec para el primer trozo, empuja Data en valores crecientes de WriteOffset, y marca FinishWrite en el último trozo. Como cada mensaje se serializa a través de ToBytes y LoadFromBytes, las mismas clases tipadas funcionan tanto si subes un archivo pequeño en una sola llamada como si transmites un objeto grande en partes.
Paginación y manejo de errores
Las respuestas de listado devuelven un NextPageToken cuando hay más resultados disponibles. Cópialo en el PageToken de la siguiente petición y vuelve a llamar para paginar buckets grandes o largos listados de objetos. En el lado de los errores, cada TsgcGRPCResponse lleva un StatusCode tipado, así que un resultado distinto de grpcOK te dice exactamente qué salió mal, desde grpcUNAUTHENTICATED para un token erróneo o ausente hasta grpcNOT_FOUND para un bucket inexistente. Para el trabajo asíncrono, OnGRPCResponse, OnGRPCError y OnGRPCException entregan la misma información a través de eventos.
Disponibilidad
El cliente gRPC de Google Cloud Storage tipado forma parte de la edición Enterprise de sgcWebSockets. Un ejemplo completo y listo para ejecutar está en Demos\21.GRPC\15.Cloud_Storage, que cubre la autenticación, el listado y la creación de buckets, y el listado de objetos. La referencia completa está en la página de producto del Cliente gRPC.
¿Preguntas o comentarios? Ponte en contacto. Recibirás respuesta de las personas que escribieron el código.
