oss/client_extension.go (139 lines of code) (raw):
package oss
import (
"context"
"errors"
"fmt"
"hash"
"io"
"os"
)
// NewDownloader creates a new Downloader instance to download objects.
func (c *Client) NewDownloader(optFns ...func(*DownloaderOptions)) *Downloader {
return NewDownloader(c, optFns...)
}
// NewUploader creates a new Uploader instance to upload objects.
func (c *Client) NewUploader(optFns ...func(*UploaderOptions)) *Uploader {
return NewUploader(c, optFns...)
}
// NewCopier creates a new Copier instance to copy objects.
func (c *Client) NewCopier(optFns ...func(*CopierOptions)) *Copier {
return NewCopier(c, optFns...)
}
// OpenFile opens the named file for reading.
func (c *Client) OpenFile(ctx context.Context, bucket string, key string, optFns ...func(*OpenOptions)) (*ReadOnlyFile, error) {
return NewReadOnlyFile(ctx, c, bucket, key, optFns...)
}
// AppendFile opens or creates the named file for appending.
func (c *Client) AppendFile(ctx context.Context, bucket string, key string, optFns ...func(*AppendOptions)) (*AppendOnlyFile, error) {
return NewAppendFile(ctx, c, bucket, key, optFns...)
}
type IsObjectExistOptions struct {
VersionId *string
RequestPayer *string
}
// IsObjectExist checks if the object exists.
func (c *Client) IsObjectExist(ctx context.Context, bucket string, key string, optFns ...func(*IsObjectExistOptions)) (bool, error) {
options := IsObjectExistOptions{}
for _, fn := range optFns {
fn(&options)
}
_, err := c.GetObjectMeta(ctx, &GetObjectMetaRequest{Bucket: Ptr(bucket), Key: Ptr(key), VersionId: options.VersionId, RequestPayer: options.RequestPayer})
if err == nil {
return true, nil
}
var serr *ServiceError
errors.As(err, &serr)
if errors.As(err, &serr) {
if serr.Code == "NoSuchKey" ||
// error code not in response header
(serr.StatusCode == 404 && serr.Code == "BadErrorResponse") {
return false, nil
}
}
return false, err
}
// IsBucketExist checks if the bucket exists.
func (c *Client) IsBucketExist(ctx context.Context, bucket string, optFns ...func(*Options)) (bool, error) {
_, err := c.GetBucketAcl(ctx, &GetBucketAclRequest{Bucket: Ptr(bucket)}, optFns...)
if err == nil {
return true, nil
}
var serr *ServiceError
if errors.As(err, &serr) {
if serr.Code == "NoSuchBucket" {
return false, nil
}
return true, nil
}
return false, err
}
// PutObjectFromFile creates a new object from the local file.
func (c *Client) PutObjectFromFile(ctx context.Context, request *PutObjectRequest, filePath string, optFns ...func(*Options)) (*PutObjectResult, error) {
if request == nil {
return nil, NewErrParamNull("request")
}
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
pRequest := *request
pRequest.Body = file
return c.PutObject(ctx, &pRequest, optFns...)
}
// GetObjectToFile downloads the object into a local file.
func (c *Client) GetObjectToFile(ctx context.Context, request *GetObjectRequest, filePath string, optFns ...func(*Options)) (*GetObjectResult, error) {
if request == nil {
return nil, NewErrParamNull("request")
}
var (
hash hash.Hash64
prog *progressTracker
result *GetObjectResult
err error
retry bool
)
if request.ProgressFn != nil {
prog = &progressTracker{
pr: request.ProgressFn,
}
}
if c.hasFeature(FeatureEnableCRC64CheckDownload) {
hash = NewCRC64(0)
}
i := 0
maxRetrys := c.retryMaxAttempts(nil)
for {
i++
result, retry, err = c.getObjectToFileNoRerty(ctx, request, filePath, hash, prog, optFns...)
if err == nil || !retry {
break
}
if i > maxRetrys {
break
}
}
return result, err
}
func (c *Client) getObjectToFileNoRerty(ctx context.Context, request *GetObjectRequest, filePath string,
hash hash.Hash64, prog *progressTracker, optFns ...func(*Options)) (*GetObjectResult, bool, error) {
result, err := c.GetObject(ctx, request, optFns...)
if err != nil {
return nil, false, err
}
defer result.Body.Close()
file, err := os.Create(filePath)
if err != nil {
return nil, false, err
}
defer file.Close()
var writers []io.Writer
if hash != nil {
hash.Reset()
writers = append(writers, hash)
}
if prog != nil {
prog.total = result.ContentLength
prog.Reset()
writers = append(writers, prog)
}
var r io.Reader = result.Body
if len(writers) > 0 {
r = io.TeeReader(result.Body, io.MultiWriter(writers...))
}
_, err = io.Copy(file, r)
if err == nil && hash != nil {
err = checkResponseHeaderCRC64(fmt.Sprint(hash.Sum64()), result.Headers)
}
return result, true, err
}