Delphi

Upload e download su Amazon S3 da Delphi con l'AWS SDK

calendar_today personTeam EGSOFT schedule4 min di lettura
info

Disclaimer: le informazioni pubblicate in questa sezione hanno finalità di pura divulgazione tecnica. EG Software S.r.l. non si assume alcuna responsabilità per un utilizzo improprio dei contenuti, né per eventuali danni diretti o indiretti derivanti dalla loro applicazione, e non garantisce l'aggiornamento, l'accuratezza o la completezza delle informazioni riportate. Prima di utilizzare in produzione codice o procedure qui descritte, verificane sempre l'adeguatezza al proprio contesto.

Quando un'applicazione Delphi deve archiviare file su uno storage cloud — backup, documenti, allegati — Amazon S3 è una delle destinazioni più comuni. L'AWS SDK for Delphi espone un client dedicato che evita di dover costruire a mano le richieste firmate richieste dal protocollo AWS (la parte più delicata e facile da sbagliare se fatta manualmente via HTTP).

Incapsulare il client S3

Anche qui vale il principio già visto per altre integrazioni: una classe di servizio nasconde la creazione del client e le credenziali, esponendo solo i due metodi che servono davvero al resto dell'applicazione.

unit S3StorageService;

interface

uses
  System.SysUtils, System.Classes, AWS.S3, Vcl.ComCtrls;

type
  TS3StorageService = class
  private
    FS3Client: IAmazonSimpleStorageService;
  public
    constructor Create(const AccessKey, SecretKey, Region: string);
    destructor Destroy; override;
    function UploadFile(const BucketName, LocalFilePath, S3ObjectKey: string;
      ProgressBar: TProgressBar = nil): Boolean;
    function DownloadFile(const BucketName, S3ObjectKey, LocalFilePath: string;
      ProgressBar: TProgressBar = nil): Boolean;
  end;

implementation

constructor TS3StorageService.Create(const AccessKey, SecretKey, Region: string);
begin
  inherited Create;
  FS3Client := TAmazonSimpleStorageServiceClient.Create(AccessKey, SecretKey, Region);
end;

destructor TS3StorageService.Destroy;
begin
  FS3Client := nil;
  inherited;
end;

end.

Upload con avanzamento

La richiesta di upload accetta uno stream di input e un handler opzionale per l'avanzamento, comodo per collegare direttamente una TProgressBar senza logica aggiuntiva nel form chiamante:

function TS3StorageService.UploadFile(const BucketName, LocalFilePath, S3ObjectKey: string;
  ProgressBar: TProgressBar): Boolean;
var
  Request: TPutObjectRequest;
  Stream: TFileStream;
begin
  Result := False;
  Stream := TFileStream.Create(LocalFilePath, fmOpenRead or fmShareDenyWrite);
  try
    Request := TPutObjectRequest.Create;
    try
      Request.BucketName := BucketName;
      Request.Key := S3ObjectKey;
      Request.InputStream := Stream;

      if Assigned(ProgressBar) then
        Request.OnUploadProgress := procedure(const Sender: TObject; BytesSent, TotalBytes: Int64)
        begin
          ProgressBar.Position := Round((BytesSent / TotalBytes) * 100);
        end;

      FS3Client.PutObject(Request);
      Result := True;
    finally
      Request.Free;
    end;
  finally
    Stream.Free;
  end;
end;

Download, stesso principio

Il download è speculare: uno stream di destinazione al posto di quello sorgente, e lo stesso tipo di callback per l'avanzamento, questa volta sui byte ricevuti.

function TS3StorageService.DownloadFile(const BucketName, S3ObjectKey, LocalFilePath: string;
  ProgressBar: TProgressBar): Boolean;
var
  Request: TGetObjectRequest;
  Stream: TFileStream;
begin
  Result := False;
  Stream := TFileStream.Create(LocalFilePath, fmCreate);
  try
    Request := TGetObjectRequest.Create;
    try
      Request.BucketName := BucketName;
      Request.Key := S3ObjectKey;

      if Assigned(ProgressBar) then
        Request.OnDownloadProgress := procedure(const Sender: TObject; BytesRead, TotalBytes: Int64)
        begin
          ProgressBar.Position := Round((BytesRead / TotalBytes) * 100);
        end;

      FS3Client.GetObject(Request, Stream);
      Result := True;
    finally
      Request.Free;
    end;
  finally
    Stream.Free;
  end;
end;

Dove tenere le credenziali

Access key e secret key non vanno mai scritte nel codice sorgente: si leggono da un file di configurazione (idealmente offuscato, come nell'articolo sulla protezione dei file INI) o, meglio ancora quando l'infrastruttura lo consente, da un ruolo IAM temporaneo invece di una coppia di chiavi statiche a lunga durata. Per applicazioni desktop distribuite a più postazioni, conviene inoltre limitare i permessi della policy IAM associata alle chiavi al solo bucket e alle sole operazioni realmente necessarie (upload e download), non ad accesso amministrativo completo su S3.

Altri articoli su Delphi grid_viewTutte le tematiche
Scrivici su WhatsApp