{ *************************************************************************** Copyright (c) 2015-2023 Kike Pérez Unit : Quick.Azure Description : Azure blobs operations Author : Kike Pérez Version : 1.4 Created : 27/08/2015 Modified : 14/07/2023 This file is part of QuickLib: https://github.com/exilon/QuickLib *************************************************************************** Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *************************************************************************** } unit Quick.Azure; {$i QuickLib.inc} interface uses Classes, System.SysUtils, System.Generics.Collections, IPPeerClient, IdURI, Data.Cloud.CloudAPI, Data.Cloud.AzureAPI, Quick.Commons; type TAzureProtocol = (azHTTP,azHTTPS); //TAzureBlob = Data.Cloud.AzureAPI.TAzureBlob; TBlobPublicAccess = Data.Cloud.AzureAPI.TBlobPublicAccess; TAzureResponseInfo = record StatusCode : Integer; StatusMsg : string; end; TAzureBlobObject = class Name : string; Size : Int64; IsDir : Boolean; LastModified : TDateTime; end; TBlobList = class (TObjectList); TQuickAzure = class private fconAzure : TAzureConnectionInfo; fAccountName : string; fAccountKey : string; fAzureProtocol : TAzureProtocol; fTimeOut : Integer; procedure SetAccountName(azAccountName : string); procedure SetAccountKey(azAccountKey : string); procedure SetAzureProtocol(azProtocol : TAzureProtocol); function FileToArray(cFilename : string) : TArray; function StreamToArray(cStream : TStream) : TArray; function ByteContent(DataStream: TStream): TBytes; function GMT2DateTime(const gmtdate : string):TDateTime; function CheckContainer(const aContainer : string) : string; function RemoveFirstSlash(const aValue : string) : string; public constructor Create; overload; constructor Create(azAccountName, azAccountKey : string); overload; destructor Destroy; override; property AccountName : string read fAccountName write SetAccountName; property AccountKey : string read fAccountKey write SetAccountKey; property AzureProtocol : TAzureProtocol read fAzureProtocol write SetAzureProtocol; property TimeOut : Integer read fTimeOut write fTimeOut; function PutBlob(const azContainer, cFilename, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; overload; function PutBlob(const azContainer : string; cStream : TStream; const azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; overload; function GetBlob(const azContainer, azBlobName, cFilenameTo : string; out azResponseInfo : TAzureResponseInfo) : Boolean; overload; function GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo; out Stream : TMemoryStream) : Boolean; overload; function GetBlob(const azContainer, azBlobName: string; out azResponseInfo: TAzureResponseInfo; var Stream: TStream): Boolean; overload; function GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : TMemoryStream; overload; function CopyBlob(const azSourceContainer, azSourceBlobName : string; azTargetContainer, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; function RenameBlob(const azContainer, azSourceBlobName, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; function ExistsObject(const azContainer, azBlobName : string) : Boolean; function ExistsFolder(const azContainer, azFolderName : string) : Boolean; function DeleteBlob(const azContainer,azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; function ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList; function ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings; function ExistsContainer(const azContainer : string) : Boolean; function ListContainers(const azContainersStartWith : string; out azResponseInfo : TAzureResponseInfo) : TStrings; function CreateContainer(const azContainer : string; azPublicAccess : TBlobPublicAccess; out azResponseInfo : TAzureResponseInfo) : Boolean; function DeleteContainer(const azContainer : string; out azResponseInfo : TAzureResponseInfo) : Boolean; end; implementation constructor TQuickAzure.Create; begin inherited; fconAzure := TAzureConnectionInfo.Create(nil); fAzureProtocol := azHTTP; fTimeOut := 30; end; constructor TQuickAzure.Create(azAccountName, azAccountKey : string); begin Create; SetAccountName(azAccountName); SetAccountKey(azAccountKey); end; destructor TQuickAzure.Destroy; begin if Assigned(fconAzure) then fconAzure.Free; inherited; end; procedure TQuickAzure.SetAccountName(azAccountName : string); begin if fAccountName <> azAccountName then begin fAccountName := azAccountName; fconAzure.AccountName := azAccountName; end; end; procedure TQuickAzure.SetAccountKey(azAccountKey : string); begin if fAccountKey <> azAccountKey then begin fAccountKey := azAccountKey ; fconAzure.AccountKey := azAccountKey; end; end; procedure TQuickAzure.SetAzureProtocol(azProtocol: TAzureProtocol); begin if fAzureProtocol <> azProtocol then begin fAzureProtocol := azProtocol; if azProtocol = azHTTP then fconAzure.Protocol := 'HTTP' else fconAzure.Protocol := 'HTTPS'; end; end; function TQuickAzure.FileToArray(cFilename : string) : TArray; var fs : TFileStream; begin fs := TFileStream.Create(cFilename, fmOpenRead); try Result := ByteContent(fs); finally fs.Free; end; end; function TQuickAzure.StreamToArray(cStream : TStream) : TArray; var bs : TBytesStream; begin bs := TBytesStream.Create(Result); try bs.LoadFromStream(cStream); Result := bs.Bytes; finally bs.Free end; end; function TQuickAzure.ByteContent(DataStream: TStream): TBytes; var Buffer: TBytes; begin if not Assigned(DataStream) then Exit(nil); SetLength(Buffer, DataStream.Size); // the content may have been read DataStream.Position := 0; if DataStream.Size > 0 then DataStream.Read(Buffer[0], DataStream.Size); Result := Buffer; end; function TQuickAzure.GMT2DateTime(const gmtdate : string):TDateTime; function GetMonthDig(Value : string):Integer; const aMonth : array[1..12] of string = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); var idx : Integer; begin Result := 0; for idx := 1 to 12 do begin if CompareText(Value,aMonth[idx]) = 0 then begin Result := idx; Break; end; end; end; var i : Integer; Len : Integer; wDay, wMonth, wYear, wHour, wMinute, wSec : Word; begin //GMT Format: 'Mon, 12 Jan 2014 16:20:35 GMT' Result := 0; Len := 0; if gmtdate = '' then Exit; try for i := 0 to Length(gmtdate) do begin if gmtdate[i] in ['0'..'9'] then begin Len := i; Break; end; end; //Day wDay := StrToIntDef(Copy(gmtdate,Len,2),0); if wDay = 0 then Exit; Inc(Len,3); //Month wMonth := GetMonthDig(Copy(gmtdate,Len,3)); if wMonth = 0 then Exit; Inc(Len,4); //Year wYear := StrToIntDef(Copy(gmtdate,Len,4),0); if wYear = 0 then Exit; Inc(Len,5); //Hour wHour := StrToIntDef(Copy(gmtdate,Len,2),99); if wHour = 99 then Exit; Inc(Len,3); //Min wMinute := StrToIntDef(Copy(gmtdate,Len,2),99); if wMinute = 99 then Exit; Inc(Len,3); //Sec wSec := StrToIntDef(Copy(gmtdate,Len,2),99); if wSec = 99 then Exit; Result := EncodeDate(wYear,wMonth,wDay) + EncodeTime(wHour,wMinute,wSec,0); except Result := 0; end; end; function GetResponseInfo(ResponseInfo : TCloudResponseInfo) : TAzureResponseInfo; begin Result.StatusCode := ResponseInfo.StatusCode; Result.StatusMsg := ResponseInfo.StatusMessage; end; function TQuickAzure.PutBlob(const azContainer, cFilename, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; Content : TArray; CloudResponseInfo : TCloudResponseInfo; container : string; blobname : string; begin BlobService := TAzureBlobService.Create(fconAzure); try container := CheckContainer(azContainer); CloudResponseInfo := TCloudResponseInfo.Create; try BlobService.Timeout := fTimeout; Content := FileToArray(cFilename); if azBlobName = '' then blobname := cFilename else blobname := azBlobName; if blobname.StartsWith('/') then blobname := Copy(blobname,2,Length(blobname)); Result := BlobService.PutBlockBlob(container,blobname,Content,EmptyStr,nil,nil,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; finally BlobService.Free; end; end; function TQuickAzure.PutBlob(const azContainer : string; cStream : TStream; const azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; Content : TBytes; CloudResponseInfo : TCloudResponseInfo; container : string; blobname : string; begin Result := False; azResponseInfo.StatusCode := 500; if cStream.Size = 0 then begin azResponseInfo.StatusMsg := 'Stream is empty'; Exit; end; container := CheckContainer(azContainer); blobname := RemoveFirstSlash(azBlobName); try BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; CloudResponseInfo := TCloudResponseInfo.Create; try Content := ByteContent(cStream); Result := BlobService.PutBlockBlob(container,blobname,Content,EmptyStr,nil,nil,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; finally BlobService.Free; end; except on E : Exception do begin azResponseInfo.StatusCode := 500; azResponseInfo.StatusMsg := e.message; Result := False; end; end; end; function TQuickAzure.GetBlob(const azContainer, azBlobName, cFilenameTo : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; fs : TFileStream; CloudResponseInfo : TCloudResponseInfo; container : string; blobname : string; begin container := CheckContainer(azContainer); blobname := RemoveFirstSlash(azBlobName); BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; fs := TFileStream.Create(cFilenameTo,fmCreate); try try CloudResponseInfo := TCloudResponseInfo.Create; try Result := BlobService.GetBlob(container,blobname,fs,EmptyStr,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; except Result := False; end; finally fs.Free; end; finally BlobService.Free; end; end; function TQuickAzure.GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo; out Stream : TMemoryStream) : Boolean; begin Stream := TMemoryStream.Create; try Result := GetBlob(azContainer,azBlobName,azResponseInfo,TStream(Stream)); except Stream.Free; end; end; function TQuickAzure.GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : TMemoryStream; begin GetBlob(azContainer,azBlobName,azResponseInfo,Result); end; function TQuickAzure.GetBlob(const azContainer, azBlobName: string; out azResponseInfo: TAzureResponseInfo; var Stream: TStream): Boolean; var BlobService : TAzureBlobService; CloudResponseInfo : TCloudResponseInfo; container : string; blobname : string; begin container := CheckContainer(azContainer); blobname := RemoveFirstSlash(azBlobName); BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; CloudResponseInfo := TCloudResponseInfo.Create; try Result := BlobService.GetBlob(container,blobname,Stream,EmptyStr,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; finally BlobService.Free; end; end; function TQuickAzure.CheckContainer(const aContainer: string): string; begin if aContainer = '' then Result := '$root' else Result := aContainer; end; function TQuickAzure.CopyBlob(const azSourceContainer, azSourceBlobName : string; azTargetContainer, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; CloudResponseInfo : TCloudResponseInfo; sourcecontainer : string; targetcontainer : string; sourceblobname : string; targetblobname : string; begin sourcecontainer := CheckContainer(azSourceContainer); targetcontainer := CheckContainer(azTargetContainer); sourceblobname := RemoveFirstSlash(azSourceBlobName); targetblobname := RemoveFirstSlash(azTargetBlobName); BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; try CloudResponseInfo := TCloudResponseInfo.Create; try Result := BlobService.CopyBlob(targetcontainer,targetblobname,sourcecontainer,sourceblobname,'',nil,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; except on E : Exception do begin Result := False; azResponseInfo.StatusCode := 500; azResponseInfo.StatusMsg := e.message; end; end; finally BlobService.Free; end; end; function TQuickAzure.RemoveFirstSlash(const aValue: string): string; begin if aValue.StartsWith('/') then Result := Copy(aValue,2,Length(aValue)) else Result := aValue; end; function TQuickAzure.RenameBlob(const azContainer, azSourceBlobName, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var sourceblobname : string; begin Result := False; if sourceblobname.Contains('%') then sourceblobname := azSourceBlobName else sourceblobname := TIdURI.PathEncode(azSourceBlobName); if CopyBlob(azContainer,sourceblobname,azContainer,azTargetBlobName,azResponseInfo) then begin Result := DeleteBlob(azContainer,azSourceBlobName,azResponseInfo); end; end; function TQuickAzure.ExistsObject(const azContainer, azBlobName : string) : Boolean; var azBlob : string; azBlobs : TStrings; ResponseInfo : TAzureResponseInfo; begin Result := False; azBlobs := ListBlobsNames(azContainer,azBlobName,False,ResponseInfo); try if (ResponseInfo.StatusCode = 200) and (Assigned(azBlobs)) then begin for azBlob in azBlobs do begin if azBlob = azBlobName then begin Result := True; Break; end; end; end; finally azBlobs.Free; end; end; function TQuickAzure.ExistsFolder(const azContainer, azFolderName : string) : Boolean; var BlobService : TAzureBlobService; azBlob : TAzureBlob; azBlobList : TList; CloudResponseInfo : TCloudResponseInfo; AzParams : TStrings; cNextMarker : string; container : string; foldername : string; begin Result := False; container := CheckContainer(azContainer); BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; AzParams := TStringList.Create; try if not azFolderName.EndsWith('/') then foldername := azFolderName + '/' else foldername := azFolderName; AzParams.Values['prefix'] := foldername; AzParams.Values['delimiter'] := '/'; AzParams.Values['maxresults'] := '1'; cNextMarker := ''; CloudResponseInfo := TCloudResponseInfo.Create; try azBlobList := BlobService.ListBlobs(container,cNextMarker,AzParams,CloudResponseInfo); try if (Assigned(azBlobList)) and (azBlobList.Count > 0) and (CloudResponseInfo.StatusCode = 200) then Result := True; finally //frees azbloblist objects for azBlob in azBlobList do azBlob.Free; azBlobList.Free; end; finally CloudResponseInfo.Free; end; finally AzParams.Free; end; finally BlobService.Free; end; end; function TQuickAzure.DeleteBlob(const azContainer,azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; CloudResponseInfo : TCloudResponseInfo; container : string; blobname : string; begin container := CheckContainer(azContainer); blobname := RemoveFirstSlash(azBlobName); BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; CloudResponseInfo := TCloudResponseInfo.Create; try Result := BlobService.DeleteBlob(container,blobname,False,EmptyStr,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; finally BlobService.Free; end; end; {$IFDEF DELPHITOKYO_UP} function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList; var BlobService : TAzureBlobService; azBlob : TAzureBlobItem; azBlobList : TArray; Blob : TAzureBlobObject; CloudResponseInfo : TCloudResponseInfo; cNextMarker : string; container : string; prefix : string; blobprefix : TArray; xmlresp : string; folder : string; prop : TPair; previousMaker : string; begin Result := TBlobList.Create(True); cNextMarker := ''; container := CheckContainer(azContainer); BlobService := TAzureBlobService.Create(fconAzure); try if Recursive then prefix := '' else prefix := '/'; BlobService.Timeout := fTimeout; repeat CloudResponseInfo := TCloudResponseInfo.Create; try previousMaker := cNextMarker; cNextMarker := ''; azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',previousMaker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); if Assigned(azBlobList) then begin if Result.Capacity < High(azBlobList) then Result.Capacity := High(azBlobList); end; //get folders (prefix) for folder in blobprefix do begin Blob := TAzureBlobObject.Create; if folder.EndsWith('/') then Blob.Name := RemoveLastChar(folder) else Blob.Name := folder; Blob.Name := Copy(Blob.Name,Blob.Name.LastDelimiter('/')+2,Blob.Name.Length); Blob.IsDir := True; Result.Add(Blob); end; //get files (blobs) if Assigned(azBlobList) then begin for azBlob in azBlobList do begin Blob := TAzureBlobObject.Create; Blob.Name := azBlob.Name; for prop in azBlob.Properties do begin if prop.Key = 'Content-Length' then Blob.Size := StrToInt64Def(prop.Value,0) else if prop.Key = 'Last-Modified' then Blob.LastModified := GMT2DateTime(prop.Value); end; Blob.IsDir := False; Result.Add(Blob); end; end; azBlobList := nil; finally CloudResponseInfo.Free; end; until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200); finally BlobService.Free; end; end; {$ELSE} function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList; var BlobService : TAzureBlobService; azBlob : TAzureBlob; azBlobList : TList; Blob : TAzureBlobObject; CloudResponseInfo : TCloudResponseInfo; cNextMarker : string; AzParams : TStrings; container : string; xmlresp : string; previousMarker : string; begin Result := TBlobList.Create(True); cNextMarker := ''; container := CheckContainer(azContainer); BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; repeat AzParams := TStringList.Create; try AzParams.Values['prefix'] := azBlobsStartWith; if not Recursive then AzParams.Values['delimiter'] := '/'; if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker; CloudResponseInfo := TCloudResponseInfo.Create; try azBlobList := BlobService.ListBlobs(container,cNextMarker,AzParams,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); if Assigned(azBlobList) then begin Result.Capacity := High(azBlobList); try for azBlob in azBlobList do begin Blob := TAzureBlobObject.Create; Blob.Name := azBlob.Name; Blob.Size := StrToInt64Def(azBlob.Properties.Values['Content-Length'],0); Blob.LastModified := GMT2DateTime(azBlob.Properties.Values['Last-Modified']); Result.Add(Blob); end; finally //frees azbloblist objects for azBlob in azBlobList do azBlob.Free; azBlobList.Free; end; end; azBlobList := nil; finally CloudResponseInfo.Free; end; finally FreeAndNil(AzParams); end; until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200); finally BlobService.Free; end; end; {$ENDIF} {$IFDEF DELPHITOKYO_UP} function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings; var BlobService : TAzureBlobService; azBlob : TAzureBlobItem; azBlobList : TArray; Blob : TAzureBlobObject; CloudResponseInfo : TCloudResponseInfo; cNextMarker : string; container : string; prefix : string; blobprefix : TArray; xmlresp : string; folder : string; prop : TPair; previousMaker : string; begin Result := TStringList.Create; cNextMarker := ''; container := CheckContainer(azContainer); BlobService := TAzureBlobService.Create(fconAzure); try if Recursive then prefix := '' else prefix := '/'; BlobService.Timeout := fTimeout; repeat CloudResponseInfo := TCloudResponseInfo.Create; try previousMaker := cNextMarker; azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',previousMaker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); if Assigned(azBlobList) then Result.Capacity := High(azBlobList); //get folders (prefix) for folder in blobprefix do begin Blob := TAzureBlobObject.Create; if folder.EndsWith('/') then Blob.Name := RemoveLastChar(folder) else Blob.Name := folder; Result.Add(Copy(Blob.Name,Blob.Name.LastDelimiter('/')+2,Blob.Name.Length)); end; //get files (blobs) if Assigned(azBlobList) then begin for azBlob in azBlobList do begin Result.Add(azBlob.Name); end; end; finally CloudResponseInfo.Free; end; until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200); finally BlobService.Free; end; end; {$ELSE} function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings; var BlobService : TAzureBlobService; azBlob : TAzureBlob; azBlobList : TList; CloudResponseInfo : TCloudResponseInfo; cNextMarker : string; AzParams : TStrings; container : string; begin Result := TStringList.Create; cNextMarker := ''; container := CheckContainer(azContainer); BlobService := TAzureBlobService.Create(fconAzure); CloudResponseInfo := TCloudResponseInfo.Create; try BlobService.Timeout := fTimeout; repeat AzParams := TStringList.Create; try AzParams.Values['prefix'] := azBlobsStartWith; if not Recursive then AzParams.Values['delimiter'] := '/'; if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker; azBlobList := BlobService.ListBlobs(container,cNextMarker,AzParams,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); if Assigned(azBlobList) then begin Result.Capacity := azBlobList.Count; Result.BeginUpdate; try for azBlob in azBlobList do Result.Add(azBlob.Name); finally Result.EndUpdate; //frees bloblist objects for azBlob in azBlobList do azBlob.Free; azBlobList.Free; end; end; finally AzParams.Free; end; until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200); finally BlobService.Free; CloudResponseInfo.Free; end; end; {$ENDIF} function TQuickAzure.ExistsContainer(const azContainer : string) : Boolean; var Container : string; Containers : TStrings; ResponseInfo : TAzureResponseInfo; begin Result := False; Containers := ListContainers(azContainer,ResponseInfo); try if (ResponseInfo.StatusCode = 200) and (Assigned(Containers)) then begin for Container in Containers do begin if Container = azContainer then begin Result := True; Break; end; end; end; finally Containers.Free; end; end; function TQuickAzure.ListContainers(const azContainersStartWith : string; out azResponseInfo : TAzureResponseInfo) : TStrings; var BlobService : TAzureBlobService; CloudResponseInfo : TCloudResponseInfo; cNextMarker : string; AzParams : TStrings; AzContainer : TAzureContainer; AzContainers : TList; begin Result := TStringList.Create; cNextMarker := ''; BlobService := TAzureBlobService.Create(fconAzure); CloudResponseInfo := TCloudResponseInfo.Create; try BlobService.Timeout := fTimeout; repeat AzParams := TStringList.Create; try if azContainersStartWith <> '' then AzParams.Values['prefix'] := azContainersStartWith; if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker; AzContainers := BlobService.ListContainers(cNextMarker,AzParams,CloudResponseInfo); try azResponseInfo := GetResponseInfo(CloudResponseInfo); if (azResponseInfo.StatusCode = 200) and (Assigned(AzContainers)) then begin Result.Capacity := AzContainers.Count; for AzContainer in AzContainers do begin Result.Add(AzContainer.Name); end; end; finally if Assigned(AzContainers) then begin //frees ContainerList objects for AzContainer in AzContainers do AzContainer.Free; AzContainers.Free; end; end; finally AzParams.Free; end; until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200); finally BlobService.Free; CloudResponseInfo.Free; end; end; function TQuickAzure.CreateContainer(const azContainer : string; azPublicAccess : TBlobPublicAccess; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; CloudResponseInfo : TCloudResponseInfo; begin Result := False; if azContainer = '' then Exit; BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; CloudResponseInfo := TCloudResponseInfo.Create; try Result := BlobService.CreateContainer(azContainer,nil,azPublicAccess,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; finally BlobService.Free; end; end; function TQuickAzure.DeleteContainer(const azContainer : string; out azResponseInfo : TAzureResponseInfo) : Boolean; var BlobService : TAzureBlobService; CloudResponseInfo : TCloudResponseInfo; begin Result := False; if azContainer = '' then Exit; BlobService := TAzureBlobService.Create(fconAzure); try BlobService.Timeout := fTimeout; CloudResponseInfo := TCloudResponseInfo.Create; try Result := BlobService.DeleteContainer(azContainer,CloudResponseInfo); azResponseInfo := GetResponseInfo(CloudResponseInfo); finally CloudResponseInfo.Free; end; finally BlobService.Free; end; end; end.