@@ -55,17 +55,19 @@ func (a *AzureReader) Close() error { return nil }
5555var  _  Client  =  (* AzureClient )(nil )
5656
5757func  newAzureClient (cfg  Config ) (* AzureClient , error ) {
58+ 	// backwards compatible, don't know why we kept the "blob" in the code instead of letting it be input externally. 
59+ 	ep  :=  fmt .Sprintf ("https://%s.blob.%s" , cfg .Credential .AzureAccountName , cfg .Endpoint )
5860	switch  cfg .Credential .Type  {
5961	case  IAM :
6062		cred , err  :=  azidentity .NewDefaultAzureCredential (nil )
6163		if  err  !=  nil  {
6264			return  nil , fmt .Errorf ("storage: new azure default azure credential %w" , err )
6365		}
64- 		cli , err  :=  azblob .NewClient (cfg . Endpoint , cred , nil )
66+ 		cli , err  :=  azblob .NewClient (ep , cred , nil )
6567		if  err  !=  nil  {
6668			return  nil , fmt .Errorf ("storage: new azure client %w" , err )
6769		}
68- 		sasCli , err  :=  service .NewClient (cfg . Endpoint , cred , nil )
70+ 		sasCli , err  :=  service .NewClient (ep , cred , nil )
6971		if  err  !=  nil  {
7072			return  nil , fmt .Errorf ("storage: new azure service client %w" , err )
7173		}
@@ -76,11 +78,11 @@ func newAzureClient(cfg Config) (*AzureClient, error) {
7678		if  err  !=  nil  {
7779			return  nil , fmt .Errorf ("storage: new azure shared key credential %w" , err )
7880		}
79- 		cli , err  :=  azblob .NewClientWithSharedKeyCredential (cfg . Endpoint , cred , nil )
81+ 		cli , err  :=  azblob .NewClientWithSharedKeyCredential (ep , cred , nil )
8082		if  err  !=  nil  {
8183			return  nil , fmt .Errorf ("storage: new azure client %w" , err )
8284		}
83- 		sasCli , err  :=  service .NewClientWithSharedKeyCredential (cfg . Endpoint , cred , nil )
85+ 		sasCli , err  :=  service .NewClientWithSharedKeyCredential (ep , cred , nil )
8486		return  & AzureClient {cfg : cfg , cli : cli , sasCli : sasCli }, nil 
8587	default :
8688		return  nil , fmt .Errorf ("storage: azure unsupported credential type: %s" , cfg .Credential .Type .String ())
@@ -219,46 +221,139 @@ func (a *AzureClient) UploadObject(ctx context.Context, i UploadObjectInput) err
219221	return  nil 
220222}
221223
222- type  AzureObjectIterator  struct  {
224+ type  AzureObjectFlatIterator  struct  {
223225	cli  * AzureClient 
224226
225- 	pager      * runtime.Pager [azblob.ListBlobsFlatResponse ]
226- 	currPage   azblob.ListBlobsFlatResponse 
227- 	currIndex  int 
227+ 	pager  * runtime.Pager [azblob.ListBlobsFlatResponse ]
228+ 
229+ 	currPage  []ObjectAttr 
230+ 	nextIdx   int 
231+ }
232+ 
233+ func  (flatIter  * AzureObjectFlatIterator ) HasNext () bool  {
234+ 	// current page has more entries 
235+ 	if  flatIter .nextIdx  <  len (flatIter .currPage ) {
236+ 		return  true 
237+ 	}
238+ 
239+ 	// current page is the last page 
240+ 	if  ! flatIter .pager .More () {
241+ 		return  false 
242+ 	}
243+ 
244+ 	// try to get next page 
245+ 	page , err  :=  flatIter .pager .NextPage (context .Background ())
246+ 	if  err  !=  nil  {
247+ 		log .Warn ("failed to get next page" , zap .Error (err ))
248+ 		return  false 
249+ 	}
250+ 	flatIter .currPage  =  flatIter .currPage [:0 ]
251+ 	for  _ , blob  :=  range  page .Segment .BlobItems  {
252+ 		attr  :=  ObjectAttr {Key : * blob .Name , Length : * blob .Properties .ContentLength }
253+ 		flatIter .currPage  =  append (flatIter .currPage , attr )
254+ 	}
255+ 	flatIter .nextIdx  =  0 
256+ 	return  true 
257+ }
258+ 
259+ func  (flatIter  * AzureObjectFlatIterator ) Next () (ObjectAttr , error ) {
260+ 	attr  :=  flatIter .currPage [flatIter .nextIdx ]
261+ 	flatIter .nextIdx  +=  1 
262+ 
263+ 	return  attr , nil 
264+ }
265+ 
266+ type  AzureObjectHierarchyIterator  struct  {
267+ 	cli  * AzureClient 
268+ 
269+ 	pager  * runtime.Pager [container.ListBlobsHierarchyResponse ]
270+ 
271+ 	currPage  []ObjectAttr 
272+ 	nextIdx   int 
228273}
229274
230- func  (a   * AzureObjectIterator ) HasNext () bool  {
275+ func  (hierIter   * AzureObjectHierarchyIterator ) HasNext () bool  {
231276	// current page has more entries 
232- 	if  a . currIndex  <  len (a .currPage . Segment . BlobItems ) {
277+ 	if  hierIter . nextIdx  <  len (hierIter .currPage ) {
233278		return  true 
234279	}
235280
236- 	// current page is the last page, try to get next  page 
237- 	if  ! a .pager .More () {
281+ 	// no more  page 
282+ 	if  ! hierIter .pager .More () {
238283		return  false 
239284	}
240285
241- 	page , err  :=  a .pager .NextPage (context .Background ())
286+ 	// try to get next page 
287+ 	page , err  :=  hierIter .pager .NextPage (context .Background ())
242288	if  err  !=  nil  {
243289		log .Warn ("failed to get next page" , zap .Error (err ))
244290		return  false 
245291	}
246- 	a .currPage  =  page 
247- 	a .currIndex  =  0 
292+ 	hierIter .currPage  =  hierIter .currPage [:0 ]
293+ 	for  _ , blob  :=  range  page .Segment .BlobItems  {
294+ 		attr  :=  ObjectAttr {Key : * blob .Name , Length : * blob .Properties .ContentLength }
295+ 		hierIter .currPage  =  append (hierIter .currPage , attr )
296+ 	}
297+ 	for  _ , prefix  :=  range  page .Segment .BlobPrefixes  {
298+ 		hierIter .currPage  =  append (hierIter .currPage , ObjectAttr {Key : * prefix .Name })
299+ 	}
300+ 	hierIter .nextIdx  =  0 
248301	return  true 
249302}
250303
251- func  (a   * AzureObjectIterator ) Next () (ObjectAttr , error ) {
252- 	blob  :=  a .currPage . Segment . BlobItems [ a . currIndex ]
253- 	a . currIndex ++ 
304+ func  (hierIter   * AzureObjectHierarchyIterator ) Next () (ObjectAttr , error ) {
305+ 	attr  :=  hierIter .currPage [ hierIter . nextIdx ]
306+ 	hierIter . nextIdx   +=   1 
254307
255- 	return  ObjectAttr { Key :  * blob . Name ,  Length :  * blob . Properties . ContentLength } , nil 
308+ 	return  attr , nil 
256309}
257310
258- func  (a  * AzureClient ) ListPrefix (_  context.Context , prefix  string , _  bool ) (ObjectIterator , error ) {
259- 	// currently only support list prefix recursively 
311+ func  (a  * AzureClient ) ListPrefix (_  context.Context , prefix  string , recursive  bool ) (ObjectIterator , error ) {
312+ 	if  recursive  {
313+ 		return  a .listPrefixRecursive (prefix )
314+ 	}
315+ 	return  a .listPrefixNonRecursive (prefix )
316+ }
317+ 
318+ func  (a  * AzureClient ) listPrefixRecursive (prefix  string ) (* AzureObjectFlatIterator , error ) {
260319	pager  :=  a .cli .NewListBlobsFlatPager (a .cfg .Bucket , & azblob.ListBlobsFlatOptions {Prefix : to .Ptr (prefix )})
261- 	return  & AzureObjectIterator {cli : a , pager : pager }, nil 
320+ 	page , err  :=  pager .NextPage (context .Background ())
321+ 	if  err  !=  nil  {
322+ 		return  nil , fmt .Errorf ("storage: azure list prefix %w" , err )
323+ 	}
324+ 
325+ 	var  currPage  []ObjectAttr 
326+ 	if  page .Segment  !=  nil  {
327+ 		for  _ , blob  :=  range  page .Segment .BlobItems  {
328+ 			attr  :=  ObjectAttr {Key : * blob .Name , Length : * blob .Properties .ContentLength }
329+ 			currPage  =  append (currPage , attr )
330+ 		}
331+ 	}
332+ 
333+ 	return  & AzureObjectFlatIterator {cli : a , pager : pager , currPage : currPage }, nil 
334+ }
335+ 
336+ func  (a  * AzureClient ) listPrefixNonRecursive (prefix  string ) (* AzureObjectHierarchyIterator , error ) {
337+ 	pager  :=  a .cli .ServiceClient ().
338+ 		NewContainerClient (a .cfg .Bucket ).
339+ 		NewListBlobsHierarchyPager ("/" , & container.ListBlobsHierarchyOptions {Prefix : to .Ptr (prefix )})
340+ 	page , err  :=  pager .NextPage (context .Background ())
341+ 	if  err  !=  nil  {
342+ 		return  nil , fmt .Errorf ("storage: azure list prefix %w" , err )
343+ 	}
344+ 
345+ 	var  currPage  []ObjectAttr 
346+ 	if  page .Segment  !=  nil  {
347+ 		for  _ , blob  :=  range  page .Segment .BlobItems  {
348+ 			attr  :=  ObjectAttr {Key : * blob .Name , Length : * blob .Properties .ContentLength }
349+ 			currPage  =  append (currPage , attr )
350+ 		}
351+ 		for  _ , pre  :=  range  page .Segment .BlobPrefixes  {
352+ 			currPage  =  append (currPage , ObjectAttr {Key : * pre .Name })
353+ 		}
354+ 	}
355+ 
356+ 	return  & AzureObjectHierarchyIterator {cli : a , pager : pager , currPage : currPage }, nil 
262357}
263358
264359func  (a  * AzureClient ) DeleteObject (ctx  context.Context , prefix  string ) error  {
0 commit comments