123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- { ***************************************************************************
- Copyright (c) 2016-2019 Kike Pérez
- Unit : Quick.CloudStorage.Provider.Azure
- Description : CloudStorage Azure provider
- Author : Kike Pérez
- Version : 1.8
- Created : 14/10/2018
- Modified : 07/10/2019
- 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.CloudStorage.Provider.Azure;
- {$i QuickLib.inc}
- interface
- uses
- Classes,
- System.SysUtils,
- System.Generics.Collections,
- IPPeerClient,
- Quick.Commons,
- Quick.CloudStorage,
- Data.Cloud.CloudAPI,
- Data.Cloud.AzureAPI;
- type
- TCloudStorageAzureProvider = class(TCloudStorageProvider)
- private
- fAzureConnection : TAzureConnectionInfo;
- fAzureID : string;
- fAzureKey : string;
- procedure SetSecure(aValue: Boolean); override;
- function ListContainers(azContainersStartWith : string; azResponseInfo : TResponseInfo) : TStrings;
- public
- constructor Create; overload; override;
- constructor Create(const aAccountName, aAccountKey : string); overload;
- destructor Destroy; override;
- function GetRootFolders : TStrings; override;
- procedure OpenDir(const aPath : string); override;
- function GetFile(const aPath: string; out stream : TStream) : Boolean; override;
- function GetURL(const aPath : string) : string; override;
- end;
- implementation
- { TCloudExplorerProvider }
- constructor TCloudStorageAzureProvider.Create;
- begin
- fAzureConnection := TAzureConnectionInfo.Create(nil);
- end;
- constructor TCloudStorageAzureProvider.Create(const aAccountName, aAccountKey : string);
- begin
- inherited Create;
- Create;
- fAzureID := aAccountName;
- fAzureKey := aAccountKey;
- fAzureConnection.AccountName := aAccountName;
- fAzureConnection.AccountKey := aAccountKey;
- end;
- destructor TCloudStorageAzureProvider.Destroy;
- begin
- if Assigned(fAzureConnection) then fAzureConnection.Free;
- inherited;
- end;
- function TCloudStorageAzureProvider.GetFile(const aPath: string; out stream : TStream) : Boolean;
- var
- BlobService : TAzureBlobService;
- CloudResponseInfo : TCloudResponseInfo;
- begin
- BlobService := TAzureBlobService.Create(fAzureConnection);
- try
- CloudResponseInfo := TCloudResponseInfo.Create;
- try
- Result := BlobService.GetBlob(RootFolder,aPath,stream,'',CloudResponseInfo);
- if not Result then raise Exception.CreateFmt('Cloud error %d : %s',[CloudResponseInfo.StatusCode,CloudResponseInfo.StatusMessage]);
- finally
- CloudResponseInfo.Free;
- end;
- finally
- BlobService.Free;
- end;
- end;
- function TCloudStorageAzureProvider.GetRootFolders: TStrings;
- var
- respinfo : TResponseInfo;
- begin
- Result := ListContainers('',respinfo);
- end;
- function TCloudStorageAzureProvider.GetURL(const aPath: string): string;
- begin
- Result := Format('https://%s.blob.core.windows.net/%s/%s',[fAzureConnection.AccountName,RootFolder,aPath]);
- end;
- function TCloudStorageAzureProvider.ListContainers(azContainersStartWith : string; azResponseInfo : TResponseInfo) : TStrings;
- var
- BlobService : TAzureBlobService;
- CloudResponseInfo : TCloudResponseInfo;
- cNextMarker : string;
- AzParams : TStrings;
- AzContainer : TAzureContainer;
- AzContainers : TList<TAzureContainer>;
- begin
- Result := TStringList.Create;
- cNextMarker := '';
- BlobService := TAzureBlobService.Create(fAzureConnection);
- CloudResponseInfo := TCloudResponseInfo.Create;
- try
- BlobService.Timeout := Timeout;
- 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.Get(CloudResponseInfo);
- if (azResponseInfo.StatusCode = 200) and (Assigned(AzContainers)) then
- begin
- for AzContainer in AzContainers do
- begin
- Result.Add(AzContainer.Name);
- end;
- end;
- finally
- if Assigned(AzContainer) 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;
- {$IFDEF DELPHITOKYO_UP}
- procedure TCloudStorageAzureProvider.OpenDir(const aPath: string);
- var
- BlobService : TAzureBlobService;
- azBlob : TAzureBlobItem;
- DirItem : TCloudItem;
- CloudResponseInfo : TCloudResponseInfo;
- cNextMarker : string;
- azBlobList : TArray<TAzureBlobItem>;
- blobprefix : TArray<string>;
- xmlresp : string;
- azResponseInfo : TResponseInfo;
- azContainer : string;
- folder : string;
- prop : TPair<string,string>;
- begin
- Status := stSearching;
- cNextMarker := '';
- if aPath = '..' then
- begin
- CurrentPath := RemoveLastPathSegment(CurrentPath);
- end
- else
- begin
- if (CurrentPath = '') or (aPath.StartsWith('/')) then CurrentPath := aPath
- else CurrentPath := CurrentPath + aPath;
- end;
- if Assigned(OnBeginReadDir) then OnBeginReadDir(CurrentPath);
- if CurrentPath.StartsWith('/') then CurrentPath := Copy(CurrentPath,2,CurrentPath.Length);
- if (not CurrentPath.IsEmpty) and (not CurrentPath.EndsWith('/')) then CurrentPath := CurrentPath + '/';
- azContainer := RootFolder;
- if azContainer = '' then azContainer := '$root';
- BlobService := TAzureBlobService.Create(fAzureConnection);
- try
- BlobService.Timeout := Timeout;
- Status := stRetrieving;
- if Assigned(OnGetListItem) then
- begin
- DirItem := TCloudItem.Create;
- try
- DirItem.Name := '..';
- DirItem.IsDir := True;
- DirItem.Date := 0;
- OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- end;
- repeat
- if not (Status in [stSearching,stRetrieving]) then Exit;
- if fCancelOperation then
- begin
- fCancelOperation := False;
- Exit;
- end;
- CloudResponseInfo := TCloudResponseInfo.Create;
- try
- azBlobList := BlobService.ListBlobs(azContainer,CurrentPath,'/',cNextMarker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
- azResponseInfo.Get(CloudResponseInfo);
- if azResponseInfo.StatusCode = 200 then
- begin
- //get folders (prefix)
- for folder in blobprefix do
- begin
- if not (Status in [stSearching,stRetrieving]) then Exit;
- DirItem := TCloudItem.Create;
- try
- if folder.EndsWith('/') then DirItem.Name := RemoveLastChar(folder)
- else DirItem.Name := folder;
- DirItem.Name := Copy(DirItem.Name,DirItem.Name.LastDelimiter('/')+2,DirItem.Name.Length);
- DirItem.IsDir := True;
- if Assigned(OnGetListItem) then OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- end;
- //get files (blobs)
- for azBlob in azBlobList do
- begin
- if not (Status in [stSearching,stRetrieving]) then Exit;
- if fCancelOperation then
- begin
- fCancelOperation := False;
- Exit;
- end;
- DirItem := TCloudItem.Create;
- try
- DirItem.Name := azBlob.Name;
- if DirItem.Name.StartsWith(CurrentPath) then DirItem.Name := StringReplace(DirItem.Name,CurrentPath,'',[]);
- if DirItem.Name.Contains('/') then
- begin
- DirItem.IsDir := True;
- DirItem.Name := Copy(DirItem.Name,1,DirItem.Name.IndexOf('/'));
- end
- else
- begin
- DirItem.IsDir := False;
- for prop in azBlob.Properties do
- begin
- if prop.Key = 'Content-Length' then DirItem.Size := StrToInt64Def(prop.Value,0)
- else if prop.Key = 'Last-Modified' then DirItem.Date := GMT2DateTime(prop.Value);
- end;
- end;
- if Assigned(OnGetListItem) then OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- end;
- end
- else
- begin
- Status := stFailed;
- Exit;
- end;
- finally
- CloudResponseInfo.Free;
- end;
- if Assigned(OnRefreshReadDir) then OnRefreshReadDir(CurrentPath);
- until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
- Status := stDone;
- finally
- BlobService.Free;
- if Assigned(OnEndReadDir) then OnEndReadDir(CurrentPath);
- end;
- end;
- {$ELSE}
- procedure TCloudStorageAzureProvider.OpenDir(const aPath: string);
- var
- BlobService : TAzureBlobService;
- azBlob : TAzureBlob;
- DirItem : TCloudItem;
- CloudResponseInfo : TCloudResponseInfo;
- cNextMarker : string;
- azBlobList : TList<TAzureBlob>;
- AzParams : TStrings;
- azResponseInfo : TResponseInfo;
- azContainer : string;
- begin
- Status := stSearching;
- cNextMarker := '';
- if aPath = '..' then
- begin
- CurrentPath := RemoveLastPathSegment(CurrentPath);
- end
- else
- begin
- if (CurrentPath = '') or (aPath.StartsWith('/')) then CurrentPath := aPath
- else CurrentPath := CurrentPath + aPath;
- end;
- if Assigned(OnBeginReadDir) then OnBeginReadDir(CurrentPath);
- if CurrentPath.StartsWith('/') then CurrentPath := Copy(CurrentPath,2,CurrentPath.Length);
- if (not CurrentPath.IsEmpty) and (not CurrentPath.EndsWith('/')) then CurrentPath := CurrentPath + '/';
- azContainer := RootFolder;
- if azContainer = '' then azContainer := '$root';
- BlobService := TAzureBlobService.Create(fAzureConnection);
- try
- BlobService.Timeout := Timeout;
- Status := stRetrieving;
- if Assigned(OnGetListItem) then
- begin
- DirItem := TCloudItem.Create;
- try
- DirItem.Name := '..';
- DirItem.IsDir := True;
- DirItem.Date := 0;
- OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- end;
- repeat
- if not (Status in [stSearching,stRetrieving]) then Exit;
- AzParams := TStringList.Create;
- try
- if fCancelOperation then
- begin
- fCancelOperation := False;
- Exit;
- end;
- AzParams.Values['prefix'] := CurrentPath;
- //if not Recursive then
- AzParams.Values['delimiter'] := '/';
- AzParams.Values['maxresults'] := '100';
- if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker;
- CloudResponseInfo := TCloudResponseInfo.Create;
- try
- azBlobList := BlobService.ListBlobs(azContainer,cNextMarker,AzParams,CloudResponseInfo);
- azResponseInfo.Get(CloudResponseInfo);
- if azResponseInfo.StatusCode = 200 then
- begin
- try
- for azBlob in azBlobList do
- begin
- if not (Status in [stSearching,stRetrieving]) then Exit;
- if fCancelOperation then
- begin
- fCancelOperation := False;
- Exit;
- end;
- DirItem := TCloudItem.Create;
- try
- DirItem.Name := azBlob.Name;
- if DirItem.Name.StartsWith(CurrentPath) then DirItem.Name := StringReplace(DirItem.Name,CurrentPath,'',[]);
- if DirItem.Name.Contains('/') then
- begin
- DirItem.IsDir := True;
- DirItem.Name := Copy(DirItem.Name,1,DirItem.Name.IndexOf('/'));
- end
- else
- begin
- DirItem.IsDir := False;
- DirItem.Size := StrToInt64Def(azBlob.Properties.Values['Content-Length'],0);
- DirItem.Date := GMT2DateTime(azBlob.Properties.Values['Last-Modified']);
- end;
- if Assigned(OnGetListItem) then OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- azBlob.Free;
- end;
- finally
- //frees azbloblist objects
- //for azBlob in azBlobList do azBlob.Free;
- azBlobList.Free;
- end;
- end
- else
- begin
- Status := stFailed;
- Exit;
- end;
- finally
- CloudResponseInfo.Free;
- end;
- finally
- FreeAndNil(AzParams);
- end;
- if Assigned(OnRefreshReadDir) then OnRefreshReadDir(CurrentPath);
- until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
- Status := stDone;
- finally
- BlobService.Free;
- if Assigned(OnEndReadDir) then OnEndReadDir(CurrentPath);
- end;
- end;
- {$ENDIF}
- {procedure TCloudStorageAzureProvider.OpenDir(const aPath : string);
- var
- lista : TBlobList;
- Blob : TAzureBlobObject;
- i : Integer;
- azurefilter : string;
- DirItem : TCloudItem;
- respinfo : TAzureResponseInfo;
- begin
- if aPath = '..' then
- begin
- CurrentPath := RemoveLastPathSegment(CurrentPath);
- end
- else
- begin
- if CurrentPath = '' then CurrentPath := aPath
- else CurrentPath := CurrentPath + aPath;
- end;
- if Assigned(OnBeginReadDir) then OnBeginReadDir(CurrentPath);
- if CurrentPath.StartsWith('/') then CurrentPath := Copy(CurrentPath,2,CurrentPath.Length);
- if (not CurrentPath.IsEmpty) and (not CurrentPath.EndsWith('/')) then CurrentPath := CurrentPath + '/';
- Status := stRetrieving;
- lista := fAzure.ListBlobs(RootFolder,CurrentPath,False,respinfo);
- try
- if Assigned(lista) then
- begin
- if Assigned(OnGetListItem) then
- begin
- DirItem := TCloudItem.Create;
- try
- DirItem.Name := '..';
- DirItem.IsDir := True;
- DirItem.Date := 0;
- OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- end;
- end;
- if respinfo.StatusCode = 200 then
- begin
- for Blob in lista do
- begin
- DirItem := TCloudItem.Create;
- try
- if Blob.Name.StartsWith(CurrentPath) then Blob.Name := StringReplace(Blob.Name,CurrentPath,'',[]);
- if Blob.Name.Contains('/') then
- begin
- DirItem.IsDir := True;
- DirItem.Name := Copy(Blob.Name,1,Blob.Name.IndexOf('/'));
- end
- else
- begin
- DirItem.IsDir := False;
- DirItem.Name := Blob.Name;
- DirItem.Size := Blob.Size;
- DirItem.Date := Blob.LastModified;
- end;
- if Assigned(OnGetListItem) then OnGetListItem(DirItem);
- finally
- DirItem.Free;
- end;
- end;
- Status := stDone;
- end
- else Status := stFailed;
- finally
- lista.Free;
- ResponseInfo.Get(respinfo.StatusCode,respinfo.StatusMsg);
- end;
- end;}
- procedure TCloudStorageAzureProvider.SetSecure(aValue: Boolean);
- begin
- inherited;
- if aValue then fAzureConnection.Protocol := 'HTTPS'
- else fAzureConnection.Protocol := 'HTTP';
- end;
- end.
|