O Google Cloud Storage é o serviço de armazenamento de objetos do Google. Os dados vivem em buckets, e cada bucket contém objetos (arquivos) que você envia, lista, lê e exclui. A maior parte do código Delphi o alcança através da API REST JSON, mas o serviço de storage também expõe uma API gRPC que fala Protocol Buffers sobre HTTP/2. O sgcWebSockets Enterprise inclui um cliente Cloud Storage gRPC tipado construído sobre o TsgcGRPCClient, para que você possa gerenciar buckets e objetos a partir do Delphi e do C++Builder sem nenhum runtime externo ou stubs gerados.
Como funciona
A API gRPC de Storage fica em storage.googleapis.com:443 e fala o serviço google.storage.v2.Storage. O sgcWebSockets já vem com uma pilha HTTP/2 completa, então o cliente tipado se apoia sobre um transporte TsgcHTTP2Client com TLS habilitado. O TsgcGRPCClient faz o enquadramento gRPC, os cabeçalhos e o tratamento de timeout, abre o stream HTTP/2 e analisa a resposta e os trailers de volta em um TsgcGRPCResponse.
A camada tipada está na unidade sgcGRPC_Google_Storage. Ela fornece classes de requisição e resposta como TsgcGRPCStorageListBucketsRequest, TsgcGRPCStorageListObjectsResponse e TsgcGRPCStorageBucket que se serializam de e para Protocol Buffers. Você define propriedades tipadas, chama ToBytes para obter o payload da requisição, o envia com Call e carrega a resposta com LoadFromBytes. Sem compilador protobuf, sem tags de campo escritas à mão.
A autenticação usa uma conta de serviço do Google. O cliente assina um JSON Web Token a partir da chave da conta de serviço e o apresenta como um token Bearer no metadado authorization do gRPC, que é a maneira padrão pela qual o Google Cloud autoriza chamadas servidor a servidor.
Configurando o transporte
Um canal gRPC é apenas uma conexão HTTP/2. Aponte um TsgcHTTP2Client para o endpoint de storage com TLS ligado, então anexe-o ao TsgcGRPCClient e selecione o tipo de conteúdo Protocol Buffers binário.
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;
Autenticando com uma conta de serviço
Carregue a chave JSON da conta de serviço, configure um JWT assinado para o endpoint de storage e coloque o token resultante no DefaultMetadata para que ele acompanhe cada chamada. O JWT autoassinado de conta de serviço é vinculado à audiência, então o API_Endpoint precisa apontar para storage.googleapis.com para que o token seja aceito.
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;
Listando buckets
Para enumerar os buckets de um projeto, preencha um TsgcGRPCStorageListBucketsRequest com o projeto como Parent, serialize-o e faça um Call unário ao método ListBuckets. Os bytes da resposta carregam diretamente em um TsgcGRPCStorageListBucketsResponse, que expõe cada bucket com seu nome e localização.
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;
Criando um bucket
Criar um bucket segue o mesmo padrão com TsgcGRPCStorageCreateBucketRequest. Defina o projeto parent, o id do novo bucket e o projeto que é dono do recurso bucket, então chame CreateBucket. A resposta carrega o TsgcGRPCStorageBucket criado.
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;
Listando objetos em um bucket
Listar os objetos em um bucket usa TsgcGRPCStorageListObjectsRequest. O parent é o nome do recurso do bucket, na forma projects/_/buckets/<bucket>. A resposta fornece o nome, o tamanho e o tipo de conteúdo de cada objeto, e você pode opcionalmente definir Prefix e Delimiter para percorrer uma hierarquia parecida com pastas.
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;
Lendo e escrevendo dados de objeto
Além dos metadados de bucket e objeto, a unidade também cobre os payloads de objetos. O TsgcGRPCStorageReadObjectRequest lê bytes de volta de um objeto, com ReadOffset e ReadLimit opcionais para downloads por faixa, e a resposta correspondente expõe os bytes brutos de Data. O TsgcGRPCStorageWriteObjectRequest envia o conteúdo do objeto em pedaços: defina o recurso WriteObjectSpec para o primeiro pedaço, envie Data em valores crescentes de WriteOffset e marque FinishWrite no último pedaço. Como cada mensagem serializa através de ToBytes e LoadFromBytes, as mesmas classes tipadas funcionam quer você envie um arquivo pequeno em uma chamada ou faça streaming de um objeto grande em partes.
Paginação e tratamento de erros
As respostas de listagem retornam um NextPageToken quando há mais resultados disponíveis. Copie-o para o PageToken da próxima requisição e chame novamente para paginar por buckets grandes ou longas listagens de objetos. No lado do erro, cada TsgcGRPCResponse carrega um StatusCode tipado, então um resultado diferente de grpcOK diz exatamente o que deu errado, de grpcUNAUTHENTICATED para um token inválido ou ausente até grpcNOT_FOUND para um bucket inexistente. Para trabalho assíncrono, OnGRPCResponse, OnGRPCError e OnGRPCException entregam a mesma informação através de eventos.
Disponibilidade
O cliente Google Cloud Storage gRPC tipado faz parte da edição Enterprise do sgcWebSockets. Um exemplo completo e pronto para executar está em Demos\21.GRPC\15.Cloud_Storage, cobrindo autenticação, listagem e criação de buckets, e listagem de objetos. A referência completa está na página do produto gRPC Client.
Dúvidas ou comentários? Entre em contato. Você receberá uma resposta das pessoas que escreveram o código.
