Quick.Azure.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. { ***************************************************************************
  2. Copyright (c) 2015-2023 Kike Pérez
  3. Unit : Quick.Azure
  4. Description : Azure blobs operations
  5. Author : Kike Pérez
  6. Version : 1.4
  7. Created : 27/08/2015
  8. Modified : 14/07/2023
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Azure;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. System.SysUtils,
  27. System.Generics.Collections,
  28. IPPeerClient,
  29. IdURI,
  30. Data.Cloud.CloudAPI,
  31. Data.Cloud.AzureAPI,
  32. Quick.Commons;
  33. type
  34. TAzureProtocol = (azHTTP,azHTTPS);
  35. //TAzureBlob = Data.Cloud.AzureAPI.TAzureBlob;
  36. TBlobPublicAccess = Data.Cloud.AzureAPI.TBlobPublicAccess;
  37. TAzureResponseInfo = record
  38. StatusCode : Integer;
  39. StatusMsg : string;
  40. end;
  41. TAzureBlobObject = class
  42. Name : string;
  43. Size : Int64;
  44. IsDir : Boolean;
  45. LastModified : TDateTime;
  46. end;
  47. TBlobList = class (TObjectList<TAzureBlobObject>);
  48. TQuickAzure = class
  49. private
  50. fconAzure : TAzureConnectionInfo;
  51. fAccountName : string;
  52. fAccountKey : string;
  53. fAzureProtocol : TAzureProtocol;
  54. fTimeOut : Integer;
  55. procedure SetAccountName(azAccountName : string);
  56. procedure SetAccountKey(azAccountKey : string);
  57. procedure SetAzureProtocol(azProtocol : TAzureProtocol);
  58. function FileToArray(cFilename : string) : TArray<Byte>;
  59. function StreamToArray(cStream : TStream) : TArray<Byte>;
  60. function ByteContent(DataStream: TStream): TBytes;
  61. function GMT2DateTime(const gmtdate : string):TDateTime;
  62. function CheckContainer(const aContainer : string) : string;
  63. function RemoveFirstSlash(const aValue : string) : string;
  64. public
  65. constructor Create; overload;
  66. constructor Create(azAccountName, azAccountKey : string); overload;
  67. destructor Destroy; override;
  68. property AccountName : string read fAccountName write SetAccountName;
  69. property AccountKey : string read fAccountKey write SetAccountKey;
  70. property AzureProtocol : TAzureProtocol read fAzureProtocol write SetAzureProtocol;
  71. property TimeOut : Integer read fTimeOut write fTimeOut;
  72. function PutBlob(const azContainer, cFilename, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; overload;
  73. function PutBlob(const azContainer : string; cStream : TStream; const azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean; overload;
  74. function GetBlob(const azContainer, azBlobName, cFilenameTo : string; out azResponseInfo : TAzureResponseInfo) : Boolean; overload;
  75. function GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo; out Stream : TMemoryStream) : Boolean; overload;
  76. function GetBlob(const azContainer, azBlobName: string; out azResponseInfo: TAzureResponseInfo; var Stream: TStream): Boolean; overload;
  77. function GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : TMemoryStream; overload;
  78. function CopyBlob(const azSourceContainer, azSourceBlobName : string; azTargetContainer, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  79. function RenameBlob(const azContainer, azSourceBlobName, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  80. function ExistsObject(const azContainer, azBlobName : string) : Boolean;
  81. function ExistsFolder(const azContainer, azFolderName : string) : Boolean;
  82. function DeleteBlob(const azContainer,azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  83. function ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList;
  84. function ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
  85. function ExistsContainer(const azContainer : string) : Boolean;
  86. function ListContainers(const azContainersStartWith : string; out azResponseInfo : TAzureResponseInfo) : TStrings;
  87. function CreateContainer(const azContainer : string; azPublicAccess : TBlobPublicAccess; out azResponseInfo : TAzureResponseInfo) : Boolean;
  88. function DeleteContainer(const azContainer : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  89. end;
  90. implementation
  91. constructor TQuickAzure.Create;
  92. begin
  93. inherited;
  94. fconAzure := TAzureConnectionInfo.Create(nil);
  95. fAzureProtocol := azHTTP;
  96. fTimeOut := 30;
  97. end;
  98. constructor TQuickAzure.Create(azAccountName, azAccountKey : string);
  99. begin
  100. Create;
  101. SetAccountName(azAccountName);
  102. SetAccountKey(azAccountKey);
  103. end;
  104. destructor TQuickAzure.Destroy;
  105. begin
  106. if Assigned(fconAzure) then fconAzure.Free;
  107. inherited;
  108. end;
  109. procedure TQuickAzure.SetAccountName(azAccountName : string);
  110. begin
  111. if fAccountName <> azAccountName then
  112. begin
  113. fAccountName := azAccountName;
  114. fconAzure.AccountName := azAccountName;
  115. end;
  116. end;
  117. procedure TQuickAzure.SetAccountKey(azAccountKey : string);
  118. begin
  119. if fAccountKey <> azAccountKey then
  120. begin
  121. fAccountKey := azAccountKey ;
  122. fconAzure.AccountKey := azAccountKey;
  123. end;
  124. end;
  125. procedure TQuickAzure.SetAzureProtocol(azProtocol: TAzureProtocol);
  126. begin
  127. if fAzureProtocol <> azProtocol then
  128. begin
  129. fAzureProtocol := azProtocol;
  130. if azProtocol = azHTTP then fconAzure.Protocol := 'HTTP'
  131. else fconAzure.Protocol := 'HTTPS';
  132. end;
  133. end;
  134. function TQuickAzure.FileToArray(cFilename : string) : TArray<Byte>;
  135. var
  136. fs : TFileStream;
  137. begin
  138. fs := TFileStream.Create(cFilename, fmOpenRead);
  139. try
  140. Result := ByteContent(fs);
  141. finally
  142. fs.Free;
  143. end;
  144. end;
  145. function TQuickAzure.StreamToArray(cStream : TStream) : TArray<Byte>;
  146. var
  147. bs : TBytesStream;
  148. begin
  149. bs := TBytesStream.Create(Result);
  150. try
  151. bs.LoadFromStream(cStream);
  152. Result := bs.Bytes;
  153. finally
  154. bs.Free
  155. end;
  156. end;
  157. function TQuickAzure.ByteContent(DataStream: TStream): TBytes;
  158. var
  159. Buffer: TBytes;
  160. begin
  161. if not Assigned(DataStream) then Exit(nil);
  162. SetLength(Buffer, DataStream.Size);
  163. // the content may have been read
  164. DataStream.Position := 0;
  165. if DataStream.Size > 0 then
  166. DataStream.Read(Buffer[0], DataStream.Size);
  167. Result := Buffer;
  168. end;
  169. function TQuickAzure.GMT2DateTime(const gmtdate : string):TDateTime;
  170. function GetMonthDig(Value : string):Integer;
  171. const
  172. aMonth : array[1..12] of string = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
  173. var
  174. idx : Integer;
  175. begin
  176. Result := 0;
  177. for idx := 1 to 12 do
  178. begin
  179. if CompareText(Value,aMonth[idx]) = 0 then
  180. begin
  181. Result := idx;
  182. Break;
  183. end;
  184. end;
  185. end;
  186. var
  187. i : Integer;
  188. Len : Integer;
  189. wDay, wMonth, wYear,
  190. wHour, wMinute, wSec : Word;
  191. begin
  192. //GMT Format: 'Mon, 12 Jan 2014 16:20:35 GMT'
  193. Result := 0;
  194. Len := 0;
  195. if gmtdate = '' then Exit;
  196. try
  197. for i := 0 to Length(gmtdate) do
  198. begin
  199. if gmtdate[i] in ['0'..'9'] then
  200. begin
  201. Len := i;
  202. Break;
  203. end;
  204. end;
  205. //Day
  206. wDay := StrToIntDef(Copy(gmtdate,Len,2),0);
  207. if wDay = 0 then Exit;
  208. Inc(Len,3);
  209. //Month
  210. wMonth := GetMonthDig(Copy(gmtdate,Len,3));
  211. if wMonth = 0 then Exit;
  212. Inc(Len,4);
  213. //Year
  214. wYear := StrToIntDef(Copy(gmtdate,Len,4),0);
  215. if wYear = 0 then Exit;
  216. Inc(Len,5);
  217. //Hour
  218. wHour := StrToIntDef(Copy(gmtdate,Len,2),99);
  219. if wHour = 99 then Exit;
  220. Inc(Len,3);
  221. //Min
  222. wMinute := StrToIntDef(Copy(gmtdate,Len,2),99);
  223. if wMinute = 99 then Exit;
  224. Inc(Len,3);
  225. //Sec
  226. wSec := StrToIntDef(Copy(gmtdate,Len,2),99);
  227. if wSec = 99 then Exit;
  228. Result := EncodeDate(wYear,wMonth,wDay) + EncodeTime(wHour,wMinute,wSec,0);
  229. except
  230. Result := 0;
  231. end;
  232. end;
  233. function GetResponseInfo(ResponseInfo : TCloudResponseInfo) : TAzureResponseInfo;
  234. begin
  235. Result.StatusCode := ResponseInfo.StatusCode;
  236. Result.StatusMsg := ResponseInfo.StatusMessage;
  237. end;
  238. function TQuickAzure.PutBlob(const azContainer, cFilename, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  239. var
  240. BlobService : TAzureBlobService;
  241. Content : TArray<Byte>;
  242. CloudResponseInfo : TCloudResponseInfo;
  243. container : string;
  244. blobname : string;
  245. begin
  246. BlobService := TAzureBlobService.Create(fconAzure);
  247. try
  248. container := CheckContainer(azContainer);
  249. CloudResponseInfo := TCloudResponseInfo.Create;
  250. try
  251. BlobService.Timeout := fTimeout;
  252. Content := FileToArray(cFilename);
  253. if azBlobName = '' then blobname := cFilename
  254. else blobname := azBlobName;
  255. if blobname.StartsWith('/') then blobname := Copy(blobname,2,Length(blobname));
  256. Result := BlobService.PutBlockBlob(container,blobname,Content,EmptyStr,nil,nil,CloudResponseInfo);
  257. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  258. finally
  259. CloudResponseInfo.Free;
  260. end;
  261. finally
  262. BlobService.Free;
  263. end;
  264. end;
  265. function TQuickAzure.PutBlob(const azContainer : string; cStream : TStream; const azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  266. var
  267. BlobService : TAzureBlobService;
  268. Content : TBytes;
  269. CloudResponseInfo : TCloudResponseInfo;
  270. container : string;
  271. blobname : string;
  272. begin
  273. Result := False;
  274. azResponseInfo.StatusCode := 500;
  275. if cStream.Size = 0 then
  276. begin
  277. azResponseInfo.StatusMsg := 'Stream is empty';
  278. Exit;
  279. end;
  280. container := CheckContainer(azContainer);
  281. blobname := RemoveFirstSlash(azBlobName);
  282. try
  283. BlobService := TAzureBlobService.Create(fconAzure);
  284. try
  285. BlobService.Timeout := fTimeout;
  286. CloudResponseInfo := TCloudResponseInfo.Create;
  287. try
  288. Content := ByteContent(cStream);
  289. Result := BlobService.PutBlockBlob(container,blobname,Content,EmptyStr,nil,nil,CloudResponseInfo);
  290. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  291. finally
  292. CloudResponseInfo.Free;
  293. end;
  294. finally
  295. BlobService.Free;
  296. end;
  297. except
  298. on E : Exception do
  299. begin
  300. azResponseInfo.StatusCode := 500;
  301. azResponseInfo.StatusMsg := e.message;
  302. Result := False;
  303. end;
  304. end;
  305. end;
  306. function TQuickAzure.GetBlob(const azContainer, azBlobName, cFilenameTo : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  307. var
  308. BlobService : TAzureBlobService;
  309. fs : TFileStream;
  310. CloudResponseInfo : TCloudResponseInfo;
  311. container : string;
  312. blobname : string;
  313. begin
  314. container := CheckContainer(azContainer);
  315. blobname := RemoveFirstSlash(azBlobName);
  316. BlobService := TAzureBlobService.Create(fconAzure);
  317. try
  318. BlobService.Timeout := fTimeout;
  319. fs := TFileStream.Create(cFilenameTo,fmCreate);
  320. try
  321. try
  322. CloudResponseInfo := TCloudResponseInfo.Create;
  323. try
  324. Result := BlobService.GetBlob(container,blobname,fs,EmptyStr,CloudResponseInfo);
  325. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  326. finally
  327. CloudResponseInfo.Free;
  328. end;
  329. except
  330. Result := False;
  331. end;
  332. finally
  333. fs.Free;
  334. end;
  335. finally
  336. BlobService.Free;
  337. end;
  338. end;
  339. function TQuickAzure.GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo; out Stream : TMemoryStream) : Boolean;
  340. begin
  341. Stream := TMemoryStream.Create;
  342. try
  343. Result := GetBlob(azContainer,azBlobName,azResponseInfo,TStream(Stream));
  344. except
  345. Stream.Free;
  346. end;
  347. end;
  348. function TQuickAzure.GetBlob(const azContainer, azBlobName : string; out azResponseInfo : TAzureResponseInfo) : TMemoryStream;
  349. begin
  350. GetBlob(azContainer,azBlobName,azResponseInfo,Result);
  351. end;
  352. function TQuickAzure.GetBlob(const azContainer, azBlobName: string; out azResponseInfo: TAzureResponseInfo; var Stream: TStream): Boolean;
  353. var
  354. BlobService : TAzureBlobService;
  355. CloudResponseInfo : TCloudResponseInfo;
  356. container : string;
  357. blobname : string;
  358. begin
  359. container := CheckContainer(azContainer);
  360. blobname := RemoveFirstSlash(azBlobName);
  361. BlobService := TAzureBlobService.Create(fconAzure);
  362. try
  363. BlobService.Timeout := fTimeout;
  364. CloudResponseInfo := TCloudResponseInfo.Create;
  365. try
  366. Result := BlobService.GetBlob(container,blobname,Stream,EmptyStr,CloudResponseInfo);
  367. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  368. finally
  369. CloudResponseInfo.Free;
  370. end;
  371. finally
  372. BlobService.Free;
  373. end;
  374. end;
  375. function TQuickAzure.CheckContainer(const aContainer: string): string;
  376. begin
  377. if aContainer = '' then Result := '$root'
  378. else Result := aContainer;
  379. end;
  380. function TQuickAzure.CopyBlob(const azSourceContainer, azSourceBlobName : string; azTargetContainer, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  381. var
  382. BlobService : TAzureBlobService;
  383. CloudResponseInfo : TCloudResponseInfo;
  384. sourcecontainer : string;
  385. targetcontainer : string;
  386. sourceblobname : string;
  387. targetblobname : string;
  388. begin
  389. sourcecontainer := CheckContainer(azSourceContainer);
  390. targetcontainer := CheckContainer(azTargetContainer);
  391. sourceblobname := RemoveFirstSlash(azSourceBlobName);
  392. targetblobname := RemoveFirstSlash(azTargetBlobName);
  393. BlobService := TAzureBlobService.Create(fconAzure);
  394. try
  395. BlobService.Timeout := fTimeout;
  396. try
  397. CloudResponseInfo := TCloudResponseInfo.Create;
  398. try
  399. Result := BlobService.CopyBlob(targetcontainer,targetblobname,sourcecontainer,sourceblobname,'',nil,CloudResponseInfo);
  400. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  401. finally
  402. CloudResponseInfo.Free;
  403. end;
  404. except
  405. on E : Exception do
  406. begin
  407. Result := False;
  408. azResponseInfo.StatusCode := 500;
  409. azResponseInfo.StatusMsg := e.message;
  410. end;
  411. end;
  412. finally
  413. BlobService.Free;
  414. end;
  415. end;
  416. function TQuickAzure.RemoveFirstSlash(const aValue: string): string;
  417. begin
  418. if aValue.StartsWith('/') then Result := Copy(aValue,2,Length(aValue))
  419. else Result := aValue;
  420. end;
  421. function TQuickAzure.RenameBlob(const azContainer, azSourceBlobName, azTargetBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  422. var
  423. sourceblobname : string;
  424. begin
  425. Result := False;
  426. if sourceblobname.Contains('%') then sourceblobname := azSourceBlobName
  427. else sourceblobname := TIdURI.PathEncode(azSourceBlobName);
  428. if CopyBlob(azContainer,sourceblobname,azContainer,azTargetBlobName,azResponseInfo) then
  429. begin
  430. Result := DeleteBlob(azContainer,azSourceBlobName,azResponseInfo);
  431. end;
  432. end;
  433. function TQuickAzure.ExistsObject(const azContainer, azBlobName : string) : Boolean;
  434. var
  435. azBlob : string;
  436. azBlobs : TStrings;
  437. ResponseInfo : TAzureResponseInfo;
  438. begin
  439. Result := False;
  440. azBlobs := ListBlobsNames(azContainer,azBlobName,False,ResponseInfo);
  441. try
  442. if (ResponseInfo.StatusCode = 200) and (Assigned(azBlobs)) then
  443. begin
  444. for azBlob in azBlobs do
  445. begin
  446. if azBlob = azBlobName then
  447. begin
  448. Result := True;
  449. Break;
  450. end;
  451. end;
  452. end;
  453. finally
  454. azBlobs.Free;
  455. end;
  456. end;
  457. function TQuickAzure.ExistsFolder(const azContainer, azFolderName : string) : Boolean;
  458. var
  459. BlobService : TAzureBlobService;
  460. azBlob : TAzureBlob;
  461. azBlobList : TList<TAzureBlob>;
  462. CloudResponseInfo : TCloudResponseInfo;
  463. AzParams : TStrings;
  464. cNextMarker : string;
  465. container : string;
  466. foldername : string;
  467. begin
  468. Result := False;
  469. container := CheckContainer(azContainer);
  470. BlobService := TAzureBlobService.Create(fconAzure);
  471. try
  472. BlobService.Timeout := fTimeout;
  473. AzParams := TStringList.Create;
  474. try
  475. if not azFolderName.EndsWith('/') then foldername := azFolderName + '/'
  476. else foldername := azFolderName;
  477. AzParams.Values['prefix'] := foldername;
  478. AzParams.Values['delimiter'] := '/';
  479. AzParams.Values['maxresults'] := '1';
  480. cNextMarker := '';
  481. CloudResponseInfo := TCloudResponseInfo.Create;
  482. try
  483. azBlobList := BlobService.ListBlobs(container,cNextMarker,AzParams,CloudResponseInfo);
  484. try
  485. if (Assigned(azBlobList)) and (azBlobList.Count > 0) and (CloudResponseInfo.StatusCode = 200) then Result := True;
  486. finally
  487. //frees azbloblist objects
  488. for azBlob in azBlobList do azBlob.Free;
  489. azBlobList.Free;
  490. end;
  491. finally
  492. CloudResponseInfo.Free;
  493. end;
  494. finally
  495. AzParams.Free;
  496. end;
  497. finally
  498. BlobService.Free;
  499. end;
  500. end;
  501. function TQuickAzure.DeleteBlob(const azContainer,azBlobName : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  502. var
  503. BlobService : TAzureBlobService;
  504. CloudResponseInfo : TCloudResponseInfo;
  505. container : string;
  506. blobname : string;
  507. begin
  508. container := CheckContainer(azContainer);
  509. blobname := RemoveFirstSlash(azBlobName);
  510. BlobService := TAzureBlobService.Create(fconAzure);
  511. try
  512. BlobService.Timeout := fTimeout;
  513. CloudResponseInfo := TCloudResponseInfo.Create;
  514. try
  515. Result := BlobService.DeleteBlob(container,blobname,False,EmptyStr,CloudResponseInfo);
  516. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  517. finally
  518. CloudResponseInfo.Free;
  519. end;
  520. finally
  521. BlobService.Free;
  522. end;
  523. end;
  524. {$IFDEF DELPHITOKYO_UP}
  525. function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList;
  526. var
  527. BlobService : TAzureBlobService;
  528. azBlob : TAzureBlobItem;
  529. azBlobList : TArray<TAzureBlobItem>;
  530. Blob : TAzureBlobObject;
  531. CloudResponseInfo : TCloudResponseInfo;
  532. cNextMarker : string;
  533. container : string;
  534. prefix : string;
  535. blobprefix : TArray<string>;
  536. xmlresp : string;
  537. folder : string;
  538. prop : TPair<string,string>;
  539. previousMaker : string;
  540. begin
  541. Result := TBlobList.Create(True);
  542. cNextMarker := '';
  543. container := CheckContainer(azContainer);
  544. BlobService := TAzureBlobService.Create(fconAzure);
  545. try
  546. if Recursive then prefix := ''
  547. else prefix := '/';
  548. BlobService.Timeout := fTimeout;
  549. repeat
  550. CloudResponseInfo := TCloudResponseInfo.Create;
  551. try
  552. previousMaker := cNextMarker;
  553. cNextMarker := '';
  554. azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',previousMaker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
  555. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  556. if Assigned(azBlobList) then
  557. begin
  558. if Result.Capacity < High(azBlobList) then Result.Capacity := High(azBlobList);
  559. end;
  560. //get folders (prefix)
  561. for folder in blobprefix do
  562. begin
  563. Blob := TAzureBlobObject.Create;
  564. if folder.EndsWith('/') then Blob.Name := RemoveLastChar(folder)
  565. else Blob.Name := folder;
  566. Blob.Name := Copy(Blob.Name,Blob.Name.LastDelimiter('/')+2,Blob.Name.Length);
  567. Blob.IsDir := True;
  568. Result.Add(Blob);
  569. end;
  570. //get files (blobs)
  571. if Assigned(azBlobList) then
  572. begin
  573. for azBlob in azBlobList do
  574. begin
  575. Blob := TAzureBlobObject.Create;
  576. Blob.Name := azBlob.Name;
  577. for prop in azBlob.Properties do
  578. begin
  579. if prop.Key = 'Content-Length' then Blob.Size := StrToInt64Def(prop.Value,0)
  580. else if prop.Key = 'Last-Modified' then Blob.LastModified := GMT2DateTime(prop.Value);
  581. end;
  582. Blob.IsDir := False;
  583. Result.Add(Blob);
  584. end;
  585. end;
  586. azBlobList := nil;
  587. finally
  588. CloudResponseInfo.Free;
  589. end;
  590. until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
  591. finally
  592. BlobService.Free;
  593. end;
  594. end;
  595. {$ELSE}
  596. function TQuickAzure.ListBlobs(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TBlobList;
  597. var
  598. BlobService : TAzureBlobService;
  599. azBlob : TAzureBlob;
  600. azBlobList : TList<TAzureBlob>;
  601. Blob : TAzureBlobObject;
  602. CloudResponseInfo : TCloudResponseInfo;
  603. cNextMarker : string;
  604. AzParams : TStrings;
  605. container : string;
  606. xmlresp : string;
  607. previousMarker : string;
  608. begin
  609. Result := TBlobList.Create(True);
  610. cNextMarker := '';
  611. container := CheckContainer(azContainer);
  612. BlobService := TAzureBlobService.Create(fconAzure);
  613. try
  614. BlobService.Timeout := fTimeout;
  615. repeat
  616. AzParams := TStringList.Create;
  617. try
  618. AzParams.Values['prefix'] := azBlobsStartWith;
  619. if not Recursive then AzParams.Values['delimiter'] := '/';
  620. if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker;
  621. CloudResponseInfo := TCloudResponseInfo.Create;
  622. try
  623. azBlobList := BlobService.ListBlobs(container,cNextMarker,AzParams,CloudResponseInfo);
  624. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  625. if Assigned(azBlobList) then
  626. begin
  627. Result.Capacity := High(azBlobList);
  628. try
  629. for azBlob in azBlobList do
  630. begin
  631. Blob := TAzureBlobObject.Create;
  632. Blob.Name := azBlob.Name;
  633. Blob.Size := StrToInt64Def(azBlob.Properties.Values['Content-Length'],0);
  634. Blob.LastModified := GMT2DateTime(azBlob.Properties.Values['Last-Modified']);
  635. Result.Add(Blob);
  636. end;
  637. finally
  638. //frees azbloblist objects
  639. for azBlob in azBlobList do azBlob.Free;
  640. azBlobList.Free;
  641. end;
  642. end;
  643. azBlobList := nil;
  644. finally
  645. CloudResponseInfo.Free;
  646. end;
  647. finally
  648. FreeAndNil(AzParams);
  649. end;
  650. until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
  651. finally
  652. BlobService.Free;
  653. end;
  654. end;
  655. {$ENDIF}
  656. {$IFDEF DELPHITOKYO_UP}
  657. function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
  658. var
  659. BlobService : TAzureBlobService;
  660. azBlob : TAzureBlobItem;
  661. azBlobList : TArray<TAzureBlobItem>;
  662. Blob : TAzureBlobObject;
  663. CloudResponseInfo : TCloudResponseInfo;
  664. cNextMarker : string;
  665. container : string;
  666. prefix : string;
  667. blobprefix : TArray<string>;
  668. xmlresp : string;
  669. folder : string;
  670. prop : TPair<string,string>;
  671. previousMaker : string;
  672. begin
  673. Result := TStringList.Create;
  674. cNextMarker := '';
  675. container := CheckContainer(azContainer);
  676. BlobService := TAzureBlobService.Create(fconAzure);
  677. try
  678. if Recursive then prefix := ''
  679. else prefix := '/';
  680. BlobService.Timeout := fTimeout;
  681. repeat
  682. CloudResponseInfo := TCloudResponseInfo.Create;
  683. try
  684. previousMaker := cNextMarker;
  685. azBlobList := BlobService.ListBlobs(azContainer,azBlobsStartWith,'/',previousMaker,100,[],cNextMarker,blobprefix,xmlresp,CloudResponseInfo);
  686. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  687. if Assigned(azBlobList) then Result.Capacity := High(azBlobList);
  688. //get folders (prefix)
  689. for folder in blobprefix do
  690. begin
  691. Blob := TAzureBlobObject.Create;
  692. if folder.EndsWith('/') then Blob.Name := RemoveLastChar(folder)
  693. else Blob.Name := folder;
  694. Result.Add(Copy(Blob.Name,Blob.Name.LastDelimiter('/')+2,Blob.Name.Length));
  695. end;
  696. //get files (blobs)
  697. if Assigned(azBlobList) then
  698. begin
  699. for azBlob in azBlobList do
  700. begin
  701. Result.Add(azBlob.Name);
  702. end;
  703. end;
  704. finally
  705. CloudResponseInfo.Free;
  706. end;
  707. until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
  708. finally
  709. BlobService.Free;
  710. end;
  711. end;
  712. {$ELSE}
  713. function TQuickAzure.ListBlobsNames(const azContainer, azBlobsStartWith : string; Recursive : Boolean; out azResponseInfo : TAzureResponseInfo) : TStrings;
  714. var
  715. BlobService : TAzureBlobService;
  716. azBlob : TAzureBlob;
  717. azBlobList : TList<TAzureBlob>;
  718. CloudResponseInfo : TCloudResponseInfo;
  719. cNextMarker : string;
  720. AzParams : TStrings;
  721. container : string;
  722. begin
  723. Result := TStringList.Create;
  724. cNextMarker := '';
  725. container := CheckContainer(azContainer);
  726. BlobService := TAzureBlobService.Create(fconAzure);
  727. CloudResponseInfo := TCloudResponseInfo.Create;
  728. try
  729. BlobService.Timeout := fTimeout;
  730. repeat
  731. AzParams := TStringList.Create;
  732. try
  733. AzParams.Values['prefix'] := azBlobsStartWith;
  734. if not Recursive then AzParams.Values['delimiter'] := '/';
  735. if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker;
  736. azBlobList := BlobService.ListBlobs(container,cNextMarker,AzParams,CloudResponseInfo);
  737. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  738. if Assigned(azBlobList) then
  739. begin
  740. Result.Capacity := azBlobList.Count;
  741. Result.BeginUpdate;
  742. try
  743. for azBlob in azBlobList do Result.Add(azBlob.Name);
  744. finally
  745. Result.EndUpdate;
  746. //frees bloblist objects
  747. for azBlob in azBlobList do azBlob.Free;
  748. azBlobList.Free;
  749. end;
  750. end;
  751. finally
  752. AzParams.Free;
  753. end;
  754. until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
  755. finally
  756. BlobService.Free;
  757. CloudResponseInfo.Free;
  758. end;
  759. end;
  760. {$ENDIF}
  761. function TQuickAzure.ExistsContainer(const azContainer : string) : Boolean;
  762. var
  763. Container : string;
  764. Containers : TStrings;
  765. ResponseInfo : TAzureResponseInfo;
  766. begin
  767. Result := False;
  768. Containers := ListContainers(azContainer,ResponseInfo);
  769. try
  770. if (ResponseInfo.StatusCode = 200) and (Assigned(Containers)) then
  771. begin
  772. for Container in Containers do
  773. begin
  774. if Container = azContainer then
  775. begin
  776. Result := True;
  777. Break;
  778. end;
  779. end;
  780. end;
  781. finally
  782. Containers.Free;
  783. end;
  784. end;
  785. function TQuickAzure.ListContainers(const azContainersStartWith : string; out azResponseInfo : TAzureResponseInfo) : TStrings;
  786. var
  787. BlobService : TAzureBlobService;
  788. CloudResponseInfo : TCloudResponseInfo;
  789. cNextMarker : string;
  790. AzParams : TStrings;
  791. AzContainer : TAzureContainer;
  792. AzContainers : TList<TAzureContainer>;
  793. begin
  794. Result := TStringList.Create;
  795. cNextMarker := '';
  796. BlobService := TAzureBlobService.Create(fconAzure);
  797. CloudResponseInfo := TCloudResponseInfo.Create;
  798. try
  799. BlobService.Timeout := fTimeout;
  800. repeat
  801. AzParams := TStringList.Create;
  802. try
  803. if azContainersStartWith <> '' then AzParams.Values['prefix'] := azContainersStartWith;
  804. if cNextMarker <> '' then AzParams.Values['marker'] := cNextMarker;
  805. AzContainers := BlobService.ListContainers(cNextMarker,AzParams,CloudResponseInfo);
  806. try
  807. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  808. if (azResponseInfo.StatusCode = 200) and (Assigned(AzContainers)) then
  809. begin
  810. Result.Capacity := AzContainers.Count;
  811. for AzContainer in AzContainers do
  812. begin
  813. Result.Add(AzContainer.Name);
  814. end;
  815. end;
  816. finally
  817. if Assigned(AzContainers) then
  818. begin
  819. //frees ContainerList objects
  820. for AzContainer in AzContainers do AzContainer.Free;
  821. AzContainers.Free;
  822. end;
  823. end;
  824. finally
  825. AzParams.Free;
  826. end;
  827. until (cNextMarker = '') or (azResponseInfo.StatusCode <> 200);
  828. finally
  829. BlobService.Free;
  830. CloudResponseInfo.Free;
  831. end;
  832. end;
  833. function TQuickAzure.CreateContainer(const azContainer : string; azPublicAccess : TBlobPublicAccess; out azResponseInfo : TAzureResponseInfo) : Boolean;
  834. var
  835. BlobService : TAzureBlobService;
  836. CloudResponseInfo : TCloudResponseInfo;
  837. begin
  838. Result := False;
  839. if azContainer = '' then Exit;
  840. BlobService := TAzureBlobService.Create(fconAzure);
  841. try
  842. BlobService.Timeout := fTimeout;
  843. CloudResponseInfo := TCloudResponseInfo.Create;
  844. try
  845. Result := BlobService.CreateContainer(azContainer,nil,azPublicAccess,CloudResponseInfo);
  846. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  847. finally
  848. CloudResponseInfo.Free;
  849. end;
  850. finally
  851. BlobService.Free;
  852. end;
  853. end;
  854. function TQuickAzure.DeleteContainer(const azContainer : string; out azResponseInfo : TAzureResponseInfo) : Boolean;
  855. var
  856. BlobService : TAzureBlobService;
  857. CloudResponseInfo : TCloudResponseInfo;
  858. begin
  859. Result := False;
  860. if azContainer = '' then Exit;
  861. BlobService := TAzureBlobService.Create(fconAzure);
  862. try
  863. BlobService.Timeout := fTimeout;
  864. CloudResponseInfo := TCloudResponseInfo.Create;
  865. try
  866. Result := BlobService.DeleteContainer(azContainer,CloudResponseInfo);
  867. azResponseInfo := GetResponseInfo(CloudResponseInfo);
  868. finally
  869. CloudResponseInfo.Free;
  870. end;
  871. finally
  872. BlobService.Free;
  873. end;
  874. end;
  875. end.