func (c Client) ListObjects(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo {
	objectStatCh := make(chan ObjectInfo, 1)
	delimiter := "/"
	if recursive {
		delimiter = ""
	}
	if err := s3utils.CheckValidBucketName(bucketName); err != nil {
		defer close(objectStatCh)
		objectStatCh <- ObjectInfo{
			Err: err,
		}
		return objectStatCh
	}
	if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil {
		defer close(objectStatCh)
		objectStatCh <- ObjectInfo{
			Err: err,
		}
		return objectStatCh
	}
	go func(objectStatCh chan<- ObjectInfo) {
		defer close(objectStatCh)
		var marker string
		for {
			result, err := c.listObjectsQuery(bucketName, objectPrefix, marker, delimiter, 0)
			if err != nil {
				objectStatCh <- ObjectInfo{
					Err: err,
				}
				return
			}
			for _, object := range result.Contents {
				marker = object.Key
				select {
				case objectStatCh <- object:
				case <-doneCh:
					return
				}
			}
			for _, obj := range result.CommonPrefixes {
				select {
				case objectStatCh <- ObjectInfo{Key: obj.Prefix}:
				case <-doneCh:
					return
				}
			}
			if result.NextMarker != "" {
				marker = result.NextMarker
			}
			if !result.IsTruncated {
				return
			}
		}
	}(objectStatCh)
	return objectStatCh
}
ListObjects - (List Objects) - List some objects or all recursively.

ListObjects lists all objects matching the objectPrefix from
the specified bucket. If recursion is enabled it would list
all subdirectories and all its contents.

Your input parameters are just bucketName, objectPrefix, recursive
and a done channel for pro-actively closing the internal go
routine. If you enable recursive as 'true' this function will
return back all the objects in a given bucket name and object
prefix.

api := client.New(....)
// Create a done channel.
doneCh := make(chan struct{})
defer close(doneCh)
// Recurively list all objects in 'mytestbucket'
recursive := true
for message := range api.ListObjects("mytestbucket", "starthere", recursive, doneCh) {
fmt.Println(message)
}
package minio
import (
	"context"
	"fmt"
	"net/http"
	"net/url"
	"github.com/minio/minio-go/v6/pkg/s3utils"
)
func (c Client) ListBuckets() ([]BucketInfo, error) {
	return c.ListBucketsWithContext(context.Background())
}
func (c Client) ListBucketsWithContext(ctx context.Context) ([]BucketInfo, error) {
	resp, err := c.executeMethod(ctx, "GET", requestMetadata{contentSHA256Hex: emptySHA256Hex})
	defer closeResponse(resp)
	if err != nil {
		return nil, err
	}
	if resp != nil {
		if resp.StatusCode != http.StatusOK {
			return nil, httpRespToErrorResponse(resp, "", "")
		}
	}
	listAllMyBucketsResult := listAllMyBucketsResult{}
	err = xmlDecoder(resp.Body, &listAllMyBucketsResult)
	if err != nil {
		return nil, err
	}
	return listAllMyBucketsResult.Buckets.Bucket, nil
}
func (c Client) ListObjectsV2WithMetadata(bucketName, objectPrefix string, recursive bool,
	doneCh <-chan struct{}) <-chan ObjectInfo {
	if location, ok := c.bucketLocCache.Get(bucketName); ok {
		if location == "snowball" {
			return c.ListObjects(bucketName, objectPrefix, recursive, doneCh)
		}
	}
	return c.listObjectsV2(bucketName, objectPrefix, recursive, true, doneCh)
}
func (c Client) listObjectsV2(bucketName, objectPrefix string, recursive, metadata bool, doneCh <-chan struct{}) <-chan ObjectInfo {
	objectStatCh := make(chan ObjectInfo, 1)
	delimiter := "/"
	if recursive {
		delimiter = ""
	}
	fetchOwner := true
	if err := s3utils.CheckValidBucketName(bucketName); err != nil {
		defer close(objectStatCh)
		objectStatCh <- ObjectInfo{
			Err: err,
		}
		return objectStatCh
	}
	if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil {
		defer close(objectStatCh)
		objectStatCh <- ObjectInfo{
			Err: err,
		}
		return objectStatCh
	}
	go func(objectStatCh chan<- ObjectInfo) {
		defer close(objectStatCh)
		var continuationToken string
		for {
			result, err := c.listObjectsV2Query(bucketName, objectPrefix, continuationToken,
				fetchOwner, metadata, delimiter, 0, "")
			if err != nil {
				objectStatCh <- ObjectInfo{
					Err: err,
				}
				return
			}
			for _, object := range result.Contents {
				object.ETag = trimEtag(object.ETag)
				select {
				case objectStatCh <- object:
				case <-doneCh:
					return
				}
			}
			for _, obj := range result.CommonPrefixes {
				select {
				case objectStatCh <- ObjectInfo{Key: obj.Prefix}:
				case <-doneCh:
					return
				}
			}
			if result.NextContinuationToken != "" {
				continuationToken = result.NextContinuationToken
			}
			if !result.IsTruncated {
				return
			}
		}
	}(objectStatCh)
	return objectStatCh
}
func (c Client) ListObjectsV2(bucketName, objectPrefix string, recursive bool, doneCh <-chan struct{}) <-chan ObjectInfo {
	if location, ok := c.bucketLocCache.Get(bucketName); ok {
		if location == "snowball" {
			return c.ListObjects(bucketName, objectPrefix, recursive, doneCh)
		}
	}
	return c.listObjectsV2(bucketName, objectPrefix, recursive, false, doneCh)
}
func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken string, fetchOwner, metadata bool, delimiter string, maxkeys int, startAfter string) (ListBucketV2Result, error) {
	if err := s3utils.CheckValidBucketName(bucketName); err != nil {
		return ListBucketV2Result{}, err
	}
	if err := s3utils.CheckValidObjectNamePrefix(objectPrefix); err != nil {
		return ListBucketV2Result{}, err
	}
	urlValues := make(url.Values)
	urlValues.Set("list-type", "2")
	if metadata {
		urlValues.Set("metadata", "true")
	}
	urlValues.Set("encoding-type", "url")
	urlValues.Set("prefix", objectPrefix)
	urlValues.Set("delimiter", delimiter)
	if continuationToken != "" {
		urlValues.Set("continuation-token", continuationToken)
	}
	if fetchOwner {
		urlValues.Set("fetch-owner", "true")
	}
	if maxkeys > 0 {
		urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))
	}
	if startAfter != "" {
		urlValues.Set("start-after", startAfter)
	}
	resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
		bucketName:       bucketName,
		queryValues:      urlValues,
		contentSHA256Hex: emptySHA256Hex,
	})
	defer closeResponse(resp)
	if err != nil {
		return ListBucketV2Result{}, err
	}
	if resp != nil {
		if resp.StatusCode != http.StatusOK {
			return ListBucketV2Result{}, httpRespToErrorResponse(resp, bucketName, "")
		}
	}
	listBucketResult := ListBucketV2Result{}
	if err = xmlDecoder(resp.Body, &listBucketResult); err != nil {
		return listBucketResult, err
	}
	if listBucketResult.IsTruncated && listBucketResult.NextContinuationToken == "" {
		return listBucketResult, ErrorResponse{
			Code:    "NotImplemented",
			Message: "Truncated response should have continuation token set",
		}
	}
	for i, obj := range listBucketResult.Contents {
		listBucketResult.Contents[i].Key, err = decodeS3Name(obj.Key, listBucketResult.EncodingType)
		if err != nil {
			return listBucketResult, err
		}
	}
	for i, obj := range listBucketResult.CommonPrefixes {
		listBucketResult.CommonPrefixes[i].Prefix, err = decodeS3Name(obj.Prefix, listBucketResult.EncodingType)
		if err != nil {
			return listBucketResult, err
		}
	}
	return listBucketResult, nil
}