|
|
/*
|
|
|
* Copyright 2017 Baidu, Inc.
|
|
|
*
|
|
|
* 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.
|
|
|
*/
|
|
|
|
|
|
// client.go - define the client for BOS service
|
|
|
|
|
|
// Package bos defines the BOS services of BCE. The supported APIs are all defined in sub-package
|
|
|
// model with three types: 16 bucket APIs, 9 object APIs and 7 multipart APIs.
|
|
|
package bos
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"io"
|
|
|
"net/http"
|
|
|
"os"
|
|
|
|
|
|
"github.com/baidubce/bce-sdk-go/auth"
|
|
|
"github.com/baidubce/bce-sdk-go/bce"
|
|
|
"github.com/baidubce/bce-sdk-go/services/bos/api"
|
|
|
"github.com/baidubce/bce-sdk-go/util/log"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
DEFAULT_SERVICE_DOMAIN = bce.DEFAULT_REGION + ".bcebos.com"
|
|
|
DEFAULT_MAX_PARALLEL = 10
|
|
|
MULTIPART_ALIGN = 1 << 20 // 1MB
|
|
|
MIN_MULTIPART_SIZE = 100 * (1 << 10) // 100 KB
|
|
|
DEFAULT_MULTIPART_SIZE = 12 * (1 << 20) // 12MB
|
|
|
|
|
|
MAX_PART_NUMBER = 10000
|
|
|
MAX_SINGLE_PART_SIZE = 5 * (1 << 30) // 5GB
|
|
|
MAX_SINGLE_OBJECT_SIZE = 48.8 * (1 << 40) // 48.8TB
|
|
|
)
|
|
|
|
|
|
// Client of BOS service is a kind of BceClient, so derived from BceClient
|
|
|
type Client struct {
|
|
|
*bce.BceClient
|
|
|
|
|
|
// Fileds that used in parallel operation for BOS service
|
|
|
MaxParallel int64
|
|
|
MultipartSize int64
|
|
|
}
|
|
|
|
|
|
// BosClientConfiguration defines the config components structure by user.
|
|
|
type BosClientConfiguration struct {
|
|
|
Ak string
|
|
|
Sk string
|
|
|
Endpoint string
|
|
|
RedirectDisabled bool
|
|
|
}
|
|
|
|
|
|
// NewClient make the BOS service client with default configuration.
|
|
|
// Use `cli.Config.xxx` to access the config or change it to non-default value.
|
|
|
func NewClient(ak, sk, endpoint string) (*Client, error) {
|
|
|
return NewClientWithConfig(&BosClientConfiguration{
|
|
|
Ak: ak,
|
|
|
Sk: sk,
|
|
|
Endpoint: endpoint,
|
|
|
RedirectDisabled: false,
|
|
|
})
|
|
|
}
|
|
|
func NewClientWithConfig(config *BosClientConfiguration) (*Client, error) {
|
|
|
var credentials *auth.BceCredentials
|
|
|
var err error
|
|
|
ak, sk, endpoint := config.Ak, config.Sk, config.Endpoint
|
|
|
if len(ak) == 0 && len(sk) == 0 { // to support public-read-write request
|
|
|
credentials, err = nil, nil
|
|
|
} else {
|
|
|
credentials, err = auth.NewBceCredentials(ak, sk)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
}
|
|
|
if len(endpoint) == 0 {
|
|
|
endpoint = DEFAULT_SERVICE_DOMAIN
|
|
|
}
|
|
|
defaultSignOptions := &auth.SignOptions{
|
|
|
HeadersToSign: auth.DEFAULT_HEADERS_TO_SIGN,
|
|
|
ExpireSeconds: auth.DEFAULT_EXPIRE_SECONDS}
|
|
|
defaultConf := &bce.BceClientConfiguration{
|
|
|
Endpoint: endpoint,
|
|
|
Region: bce.DEFAULT_REGION,
|
|
|
UserAgent: bce.DEFAULT_USER_AGENT,
|
|
|
Credentials: credentials,
|
|
|
SignOption: defaultSignOptions,
|
|
|
Retry: bce.DEFAULT_RETRY_POLICY,
|
|
|
ConnectionTimeoutInMillis: bce.DEFAULT_CONNECTION_TIMEOUT_IN_MILLIS,
|
|
|
RedirectDisabled: config.RedirectDisabled}
|
|
|
v1Signer := &auth.BceV1Signer{}
|
|
|
|
|
|
client := &Client{bce.NewBceClient(defaultConf, v1Signer),
|
|
|
DEFAULT_MAX_PARALLEL, DEFAULT_MULTIPART_SIZE}
|
|
|
return client, nil
|
|
|
}
|
|
|
|
|
|
// ListBuckets - list all buckets
|
|
|
//
|
|
|
// RETURNS:
|
|
|
// - *api.ListBucketsResult: the all buckets
|
|
|
// - error: the return error if any occurs
|
|
|
func (c *Client) ListBuckets() (*api.ListBucketsResult, error) {
|
|
|
return api.ListBuckets(c)
|
|
|
}
|
|
|
|
|
|
// ListObjects - list all objects of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - args: the optional arguments to list objects
|
|
|
// RETURNS:
|
|
|
// - *api.ListObjectsResult: the all objects of the bucket
|
|
|
// - error: the return error if any occurs
|
|
|
func (c *Client) ListObjects(bucket string,
|
|
|
args *api.ListObjectsArgs) (*api.ListObjectsResult, error) {
|
|
|
return api.ListObjects(c, bucket, args)
|
|
|
}
|
|
|
|
|
|
// SimpleListObjects - list all objects of the given bucket with simple arguments
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - prefix: the prefix for listing
|
|
|
// - maxKeys: the max number of result objects
|
|
|
// - marker: the marker to mark the beginning for the listing
|
|
|
// - delimiter: the delimiter for list objects
|
|
|
// RETURNS:
|
|
|
// - *api.ListObjectsResult: the all objects of the bucket
|
|
|
// - error: the return error if any occurs
|
|
|
func (c *Client) SimpleListObjects(bucket, prefix string, maxKeys int, marker,
|
|
|
delimiter string) (*api.ListObjectsResult, error) {
|
|
|
args := &api.ListObjectsArgs{delimiter, marker, maxKeys, prefix}
|
|
|
return api.ListObjects(c, bucket, args)
|
|
|
}
|
|
|
|
|
|
// HeadBucket - test the given bucket existed and access authority
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if exists and have authority otherwise the specific error
|
|
|
func (c *Client) HeadBucket(bucket string) error {
|
|
|
return api.HeadBucket(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DoesBucketExist - test the given bucket existed or not
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - bool: true if exists and false if not exists or occurs error
|
|
|
// - error: nil if exists or not exist, otherwise the specific error
|
|
|
func (c *Client) DoesBucketExist(bucket string) (bool, error) {
|
|
|
err := api.HeadBucket(c, bucket)
|
|
|
if err == nil {
|
|
|
return true, nil
|
|
|
}
|
|
|
if realErr, ok := err.(*bce.BceServiceError); ok {
|
|
|
if realErr.StatusCode == http.StatusForbidden {
|
|
|
return true, nil
|
|
|
}
|
|
|
if realErr.StatusCode == http.StatusNotFound {
|
|
|
return false, nil
|
|
|
}
|
|
|
}
|
|
|
return false, err
|
|
|
}
|
|
|
|
|
|
// PutBucket - create a new bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the new bucket name
|
|
|
// RETURNS:
|
|
|
// - string: the location of the new bucket if create success
|
|
|
// - error: nil if create success otherwise the specific error
|
|
|
func (c *Client) PutBucket(bucket string) (string, error) {
|
|
|
return api.PutBucket(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucket - delete a empty bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name to be deleted
|
|
|
// RETURNS:
|
|
|
// - error: nil if delete success otherwise the specific error
|
|
|
func (c *Client) DeleteBucket(bucket string) error {
|
|
|
return api.DeleteBucket(c, bucket)
|
|
|
}
|
|
|
|
|
|
// GetBucketLocation - get the location fo the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - string: the location of the bucket
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketLocation(bucket string) (string, error) {
|
|
|
return api.GetBucketLocation(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketAcl - set the acl of the given bucket with acl body stream
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - aclBody: the acl json body stream
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketAcl(bucket string, aclBody *bce.Body) error {
|
|
|
return api.PutBucketAcl(c, bucket, "", aclBody)
|
|
|
}
|
|
|
|
|
|
// PutBucketAclFromCanned - set the canned acl of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - cannedAcl: the cannedAcl string
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketAclFromCanned(bucket, cannedAcl string) error {
|
|
|
return api.PutBucketAcl(c, bucket, cannedAcl, nil)
|
|
|
}
|
|
|
|
|
|
// PutBucketAclFromFile - set the acl of the given bucket with acl json file name
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - aclFile: the acl file name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketAclFromFile(bucket, aclFile string) error {
|
|
|
body, err := bce.NewBodyFromFile(aclFile)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketAcl(c, bucket, "", body)
|
|
|
}
|
|
|
|
|
|
// PutBucketAclFromString - set the acl of the given bucket with acl json string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - aclString: the acl string with json format
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketAclFromString(bucket, aclString string) error {
|
|
|
body, err := bce.NewBodyFromString(aclString)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketAcl(c, bucket, "", body)
|
|
|
}
|
|
|
|
|
|
// PutBucketAclFromStruct - set the acl of the given bucket with acl data structure
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - aclObj: the acl struct object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketAclFromStruct(bucket string, aclObj *api.PutBucketAclArgs) error {
|
|
|
jsonBytes, jsonErr := json.Marshal(aclObj)
|
|
|
if jsonErr != nil {
|
|
|
return jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketAcl(c, bucket, "", body)
|
|
|
}
|
|
|
|
|
|
// GetBucketAcl - get the acl of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - *api.GetBucketAclResult: the result of the bucket acl
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketAcl(bucket string) (*api.GetBucketAclResult, error) {
|
|
|
return api.GetBucketAcl(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketLogging - set the loging setting of the given bucket with json stream
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - body: the json body
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketLogging(bucket string, body *bce.Body) error {
|
|
|
return api.PutBucketLogging(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// PutBucketLoggingFromString - set the loging setting of the given bucket with json string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - logging: the json format string
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketLoggingFromString(bucket, logging string) error {
|
|
|
body, err := bce.NewBodyFromString(logging)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketLogging(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// PutBucketLoggingFromStruct - set the loging setting of the given bucket with args object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - obj: the logging setting object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketLoggingFromStruct(bucket string, obj *api.PutBucketLoggingArgs) error {
|
|
|
jsonBytes, jsonErr := json.Marshal(obj)
|
|
|
if jsonErr != nil {
|
|
|
return jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketLogging(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// GetBucketLogging - get the logging setting of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - *api.GetBucketLoggingResult: the logging setting of the bucket
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketLogging(bucket string) (*api.GetBucketLoggingResult, error) {
|
|
|
return api.GetBucketLogging(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketLogging - delete the logging setting of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketLogging(bucket string) error {
|
|
|
return api.DeleteBucketLogging(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketLifecycle - set the lifecycle rule of the given bucket with raw stream
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - lifecycle: the lifecycle rule json body
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketLifecycle(bucket string, lifecycle *bce.Body) error {
|
|
|
return api.PutBucketLifecycle(c, bucket, lifecycle)
|
|
|
}
|
|
|
|
|
|
// PutBucketLifecycleFromString - set the lifecycle rule of the given bucket with string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - lifecycle: the lifecycle rule json format string body
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketLifecycleFromString(bucket, lifecycle string) error {
|
|
|
body, err := bce.NewBodyFromString(lifecycle)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketLifecycle(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// GetBucketLifecycle - get the lifecycle rule of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - *api.GetBucketLifecycleResult: the lifecycle rule of the bucket
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketLifecycle(bucket string) (*api.GetBucketLifecycleResult, error) {
|
|
|
return api.GetBucketLifecycle(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketLifecycle - delete the lifecycle rule of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketLifecycle(bucket string) error {
|
|
|
return api.DeleteBucketLifecycle(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketStorageclass - set the storage class of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - storageClass: the storage class string value
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketStorageclass(bucket, storageClass string) error {
|
|
|
return api.PutBucketStorageclass(c, bucket, storageClass)
|
|
|
}
|
|
|
|
|
|
// GetBucketStorageclass - get the storage class of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - string: the storage class string value
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketStorageclass(bucket string) (string, error) {
|
|
|
return api.GetBucketStorageclass(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketReplication - set the bucket replication config of different region
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - replicationConf: the replication config json body stream
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketReplication(bucket string, replicationConf *bce.Body, replicationRuleId string) error {
|
|
|
return api.PutBucketReplication(c, bucket, replicationConf, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// PutBucketReplicationFromFile - set the bucket replication config with json file name
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - confFile: the config json file name
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketReplicationFromFile(bucket, confFile string, replicationRuleId string) error {
|
|
|
body, err := bce.NewBodyFromFile(confFile)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketReplication(c, bucket, body, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// PutBucketReplicationFromString - set the bucket replication config with json string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - confString: the config string with json format
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketReplicationFromString(bucket, confString string, replicationRuleId string) error {
|
|
|
body, err := bce.NewBodyFromString(confString)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketReplication(c, bucket, body, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// PutBucketReplicationFromStruct - set the bucket replication config with struct
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - confObj: the replication config struct object
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketReplicationFromStruct(bucket string,
|
|
|
confObj *api.PutBucketReplicationArgs, replicationRuleId string) error {
|
|
|
jsonBytes, jsonErr := json.Marshal(confObj)
|
|
|
if jsonErr != nil {
|
|
|
return jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketReplication(c, bucket, body, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// GetBucketReplication - get the bucket replication config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - *api.GetBucketReplicationResult: the result of the bucket replication config
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketReplication(bucket string, replicationRuleId string) (*api.GetBucketReplicationResult, error) {
|
|
|
return api.GetBucketReplication(c, bucket, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// ListBucketReplication - get all replication config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - *api.ListBucketReplicationResult: the list of the bucket replication config
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) ListBucketReplication(bucket string) (*api.ListBucketReplicationResult, error) {
|
|
|
return api.ListBucketReplication(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketReplication - delete the bucket replication config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketReplication(bucket string, replicationRuleId string) error {
|
|
|
return api.DeleteBucketReplication(c, bucket, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// GetBucketReplicationProgress - get the bucket replication process of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - replicationRuleId: the replication rule id composed of [0-9 A-Z a-z _ -]
|
|
|
// RETURNS:
|
|
|
// - *api.GetBucketReplicationProgressResult: the process of the bucket replication
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketReplicationProgress(bucket string, replicationRuleId string) (
|
|
|
*api.GetBucketReplicationProgressResult, error) {
|
|
|
return api.GetBucketReplicationProgress(c, bucket, replicationRuleId)
|
|
|
}
|
|
|
|
|
|
// PutBucketEncryption - set the bucket encryption config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - algorithm: the encryption algorithm name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketEncryption(bucket, algorithm string) error {
|
|
|
return api.PutBucketEncryption(c, bucket, algorithm)
|
|
|
}
|
|
|
|
|
|
// GetBucketEncryption - get the bucket encryption config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - string: the encryption algorithm name
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketEncryption(bucket string) (string, error) {
|
|
|
return api.GetBucketEncryption(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketEncryption - delete the bucket encryption config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketEncryption(bucket string) error {
|
|
|
return api.DeleteBucketEncryption(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketStaticWebsite - set the bucket static website config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - config: the static website config body stream
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketStaticWebsite(bucket string, config *bce.Body) error {
|
|
|
return api.PutBucketStaticWebsite(c, bucket, config)
|
|
|
}
|
|
|
|
|
|
// PutBucketStaticWebsiteFromString - set the bucket static website config from json string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - jsonConfig: the static website config json string
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketStaticWebsiteFromString(bucket, jsonConfig string) error {
|
|
|
body, err := bce.NewBodyFromString(jsonConfig)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketStaticWebsite(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// PutBucketStaticWebsiteFromStruct - set the bucket static website config from struct
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - confObj: the static website config object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketStaticWebsiteFromStruct(bucket string,
|
|
|
confObj *api.PutBucketStaticWebsiteArgs) error {
|
|
|
jsonBytes, jsonErr := json.Marshal(confObj)
|
|
|
if jsonErr != nil {
|
|
|
return jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketStaticWebsite(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// SimplePutBucketStaticWebsite - simple set the bucket static website config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - index: the static website config for index file name
|
|
|
// - notFound: the static website config for notFound file name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) SimplePutBucketStaticWebsite(bucket, index, notFound string) error {
|
|
|
confObj := &api.PutBucketStaticWebsiteArgs{index, notFound}
|
|
|
return c.PutBucketStaticWebsiteFromStruct(bucket, confObj)
|
|
|
}
|
|
|
|
|
|
// GetBucketStaticWebsite - get the bucket static website config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - result: the static website config result object
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketStaticWebsite(bucket string) (
|
|
|
*api.GetBucketStaticWebsiteResult, error) {
|
|
|
return api.GetBucketStaticWebsite(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketStaticWebsite - delete the bucket static website config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketStaticWebsite(bucket string) error {
|
|
|
return api.DeleteBucketStaticWebsite(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketCors - set the bucket CORS config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - config: the bucket CORS config body stream
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketCors(bucket string, config *bce.Body) error {
|
|
|
return api.PutBucketCors(c, bucket, config)
|
|
|
}
|
|
|
|
|
|
// PutBucketCorsFromFile - set the bucket CORS config from json config file
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - filename: the bucket CORS json config file name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketCorsFromFile(bucket, filename string) error {
|
|
|
body, err := bce.NewBodyFromFile(filename)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketCors(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// PutBucketCorsFromString - set the bucket CORS config from json config string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - filename: the bucket CORS json config string
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketCorsFromString(bucket, jsonConfig string) error {
|
|
|
body, err := bce.NewBodyFromString(jsonConfig)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketCors(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// PutBucketCorsFromStruct - set the bucket CORS config from json config object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - filename: the bucket CORS json config object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketCorsFromStruct(bucket string, confObj *api.PutBucketCorsArgs) error {
|
|
|
jsonBytes, jsonErr := json.Marshal(confObj)
|
|
|
if jsonErr != nil {
|
|
|
return jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutBucketCors(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// GetBucketCors - get the bucket CORS config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - result: the bucket CORS config result object
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketCors(bucket string) (*api.GetBucketCorsResult, error) {
|
|
|
return api.GetBucketCors(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketCors - delete the bucket CORS config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketCors(bucket string) error {
|
|
|
return api.DeleteBucketCors(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketCopyrightProtection - set the copyright protection config of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - cli: the client agent which can perform sending request
|
|
|
// - bucket: the bucket name
|
|
|
// - resources: the resource items in the bucket to be protected
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketCopyrightProtection(bucket string, resources ...string) error {
|
|
|
return api.PutBucketCopyrightProtection(c, bucket, resources...)
|
|
|
}
|
|
|
|
|
|
// GetBucketCopyrightProtection - get the bucket copyright protection config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - result: the bucket copyright protection config resources
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketCopyrightProtection(bucket string) ([]string, error) {
|
|
|
return api.GetBucketCopyrightProtection(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketCopyrightProtection - delete the bucket copyright protection config
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketCopyrightProtection(bucket string) error {
|
|
|
return api.DeleteBucketCopyrightProtection(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutObject - upload a new object or rewrite the existed object with raw stream
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store the object
|
|
|
// - object: the name of the object
|
|
|
// - body: the object content body
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: etag of the uploaded object
|
|
|
// - error: the uploaded error if any occurs
|
|
|
func (c *Client) PutObject(bucket, object string, body *bce.Body,
|
|
|
args *api.PutObjectArgs) (string, error) {
|
|
|
return api.PutObject(c, bucket, object, body, args)
|
|
|
}
|
|
|
|
|
|
// BasicPutObject - the basic interface of uploading an object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store the object
|
|
|
// - object: the name of the object
|
|
|
// - body: the object content body
|
|
|
// RETURNS:
|
|
|
// - string: etag of the uploaded object
|
|
|
// - error: the uploaded error if any occurs
|
|
|
func (c *Client) BasicPutObject(bucket, object string, body *bce.Body) (string, error) {
|
|
|
return api.PutObject(c, bucket, object, body, nil)
|
|
|
}
|
|
|
|
|
|
// PutObjectFromBytes - upload a new object or rewrite the existed object from a byte array
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store the object
|
|
|
// - object: the name of the object
|
|
|
// - bytesArr: the content byte array
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: etag of the uploaded object
|
|
|
// - error: the uploaded error if any occurs
|
|
|
func (c *Client) PutObjectFromBytes(bucket, object string, bytesArr []byte,
|
|
|
args *api.PutObjectArgs) (string, error) {
|
|
|
body, err := bce.NewBodyFromBytes(bytesArr)
|
|
|
if err != nil {
|
|
|
return "", err
|
|
|
}
|
|
|
return api.PutObject(c, bucket, object, body, args)
|
|
|
}
|
|
|
|
|
|
// PutObjectFromString - upload a new object or rewrite the existed object from a string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store the object
|
|
|
// - object: the name of the object
|
|
|
// - content: the content string
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: etag of the uploaded object
|
|
|
// - error: the uploaded error if any occurs
|
|
|
func (c *Client) PutObjectFromString(bucket, object, content string,
|
|
|
args *api.PutObjectArgs) (string, error) {
|
|
|
body, err := bce.NewBodyFromString(content)
|
|
|
if err != nil {
|
|
|
return "", err
|
|
|
}
|
|
|
return api.PutObject(c, bucket, object, body, args)
|
|
|
}
|
|
|
|
|
|
// PutObjectFromFile - upload a new object or rewrite the existed object from a local file
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store the object
|
|
|
// - object: the name of the object
|
|
|
// - fileName: the local file full path name
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: etag of the uploaded object
|
|
|
// - error: the uploaded error if any occurs
|
|
|
func (c *Client) PutObjectFromFile(bucket, object, fileName string,
|
|
|
args *api.PutObjectArgs) (string, error) {
|
|
|
body, err := bce.NewBodyFromFile(fileName)
|
|
|
if err != nil {
|
|
|
return "", err
|
|
|
}
|
|
|
return api.PutObject(c, bucket, object, body, args)
|
|
|
}
|
|
|
|
|
|
// PutObjectFromStream - upload a new object or rewrite the existed object from stream
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store the object
|
|
|
// - object: the name of the object
|
|
|
// - fileName: the local file full path name
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: etag of the uploaded object
|
|
|
// - error: the uploaded error if any occurs
|
|
|
func (c *Client) PutObjectFromStream(bucket, object string, reader io.Reader,
|
|
|
args *api.PutObjectArgs) (string, error) {
|
|
|
body, err := bce.NewBodyFromSizedReader(reader, -1)
|
|
|
if err != nil {
|
|
|
return "", err
|
|
|
}
|
|
|
return api.PutObject(c, bucket, object, body, args)
|
|
|
}
|
|
|
|
|
|
// CopyObject - copy a remote object to another one
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the destination bucket
|
|
|
// - object: the name of the destination object
|
|
|
// - srcBucket: the name of the source bucket
|
|
|
// - srcObject: the name of the source object
|
|
|
// - args: the optional arguments for copying object which are MetadataDirective, StorageClass,
|
|
|
// IfMatch, IfNoneMatch, ifModifiedSince, IfUnmodifiedSince
|
|
|
// RETURNS:
|
|
|
// - *api.CopyObjectResult: result struct which contains "ETag" and "LastModified" fields
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) CopyObject(bucket, object, srcBucket, srcObject string,
|
|
|
args *api.CopyObjectArgs) (*api.CopyObjectResult, error) {
|
|
|
source := fmt.Sprintf("/%s/%s", srcBucket, srcObject)
|
|
|
return api.CopyObject(c, bucket, object, source, args)
|
|
|
}
|
|
|
|
|
|
// BasicCopyObject - the basic interface of copying a object to another one
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the destination bucket
|
|
|
// - object: the name of the destination object
|
|
|
// - srcBucket: the name of the source bucket
|
|
|
// - srcObject: the name of the source object
|
|
|
// RETURNS:
|
|
|
// - *api.CopyObjectResult: result struct which contains "ETag" and "LastModified" fields
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) BasicCopyObject(bucket, object, srcBucket,
|
|
|
srcObject string) (*api.CopyObjectResult, error) {
|
|
|
source := fmt.Sprintf("/%s/%s", srcBucket, srcObject)
|
|
|
return api.CopyObject(c, bucket, object, source, nil)
|
|
|
}
|
|
|
|
|
|
// GetObject - get the given object with raw stream return
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - responseHeaders: the optional response headers to get the given object
|
|
|
// - ranges: the optional range start and end to get the given object
|
|
|
// RETURNS:
|
|
|
// - *api.GetObjectResult: result struct which contains "Body" and header fields
|
|
|
// for details reference https://cloud.baidu.com/doc/BOS/API.html#GetObject.E6.8E.A5.E5.8F.A3
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) GetObject(bucket, object string, responseHeaders map[string]string,
|
|
|
ranges ...int64) (*api.GetObjectResult, error) {
|
|
|
return api.GetObject(c, bucket, object, responseHeaders, ranges...)
|
|
|
}
|
|
|
|
|
|
// BasicGetObject - the basic interface of geting the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// RETURNS:
|
|
|
// - *api.GetObjectResult: result struct which contains "Body" and header fields
|
|
|
// for details reference https://cloud.baidu.com/doc/BOS/API.html#GetObject.E6.8E.A5.E5.8F.A3
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) BasicGetObject(bucket, object string) (*api.GetObjectResult, error) {
|
|
|
return api.GetObject(c, bucket, object, nil)
|
|
|
}
|
|
|
|
|
|
// BasicGetObjectToFile - use basic interface to get the given object to the given file path
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - filePath: the file path to store the object content
|
|
|
// RETURNS:
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) BasicGetObjectToFile(bucket, object, filePath string) error {
|
|
|
res, err := api.GetObject(c, bucket, object, nil)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
defer res.Body.Close()
|
|
|
|
|
|
file, fileErr := os.OpenFile(filePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
if fileErr != nil {
|
|
|
return fileErr
|
|
|
}
|
|
|
defer file.Close()
|
|
|
|
|
|
written, writeErr := io.CopyN(file, res.Body, res.ContentLength)
|
|
|
if writeErr != nil {
|
|
|
return writeErr
|
|
|
}
|
|
|
if written != res.ContentLength {
|
|
|
return fmt.Errorf("written content size does not match the response content")
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// GetObjectMeta - get the given object metadata
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// RETURNS:
|
|
|
// - *api.GetObjectMetaResult: metadata result, for details reference
|
|
|
// https://cloud.baidu.com/doc/BOS/API.html#GetObjectMeta.E6.8E.A5.E5.8F.A3
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) GetObjectMeta(bucket, object string) (*api.GetObjectMetaResult, error) {
|
|
|
return api.GetObjectMeta(c, bucket, object)
|
|
|
}
|
|
|
|
|
|
// SelectObject - select the object content
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - args: the optional arguments to select the object
|
|
|
// RETURNS:
|
|
|
// - *api.SelectObjectResult: select object result
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) SelectObject(bucket, object string, args *api.SelectObjectArgs) (*api.SelectObjectResult, error) {
|
|
|
return api.SelectObject(c, bucket, object, args)
|
|
|
}
|
|
|
|
|
|
// FetchObject - fetch the object content from the given source and store
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store
|
|
|
// - object: the name of the object to store
|
|
|
// - source: fetch source url
|
|
|
// - args: the optional arguments to fetch the object
|
|
|
// RETURNS:
|
|
|
// - *api.FetchObjectResult: result struct with Code, Message, RequestId and JobId fields
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) FetchObject(bucket, object, source string,
|
|
|
args *api.FetchObjectArgs) (*api.FetchObjectResult, error) {
|
|
|
return api.FetchObject(c, bucket, object, source, args)
|
|
|
}
|
|
|
|
|
|
// BasicFetchObject - the basic interface of the fetch object api
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store
|
|
|
// - object: the name of the object to store
|
|
|
// - source: fetch source url
|
|
|
// RETURNS:
|
|
|
// - *api.FetchObjectResult: result struct with Code, Message, RequestId and JobId fields
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) BasicFetchObject(bucket, object, source string) (*api.FetchObjectResult, error) {
|
|
|
return api.FetchObject(c, bucket, object, source, nil)
|
|
|
}
|
|
|
|
|
|
// SimpleFetchObject - fetch object with simple arguments interface
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to store
|
|
|
// - object: the name of the object to store
|
|
|
// - source: fetch source url
|
|
|
// - mode: fetch mode which supports sync and async
|
|
|
// - storageClass: the storage class of the fetched object
|
|
|
// RETURNS:
|
|
|
// - *api.FetchObjectResult: result struct with Code, Message, RequestId and JobId fields
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) SimpleFetchObject(bucket, object, source, mode,
|
|
|
storageClass string) (*api.FetchObjectResult, error) {
|
|
|
args := &api.FetchObjectArgs{mode, storageClass}
|
|
|
return api.FetchObject(c, bucket, object, source, args)
|
|
|
}
|
|
|
|
|
|
// AppendObject - append the given content to a new or existed object which is appendable
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - content: the append object stream
|
|
|
// - args: the optional arguments to append object
|
|
|
// RETURNS:
|
|
|
// - *api.AppendObjectResult: the result of the appended object
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) AppendObject(bucket, object string, content *bce.Body,
|
|
|
args *api.AppendObjectArgs) (*api.AppendObjectResult, error) {
|
|
|
return api.AppendObject(c, bucket, object, content, args)
|
|
|
}
|
|
|
|
|
|
// SimpleAppendObject - the interface to append object with simple offset argument
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - content: the append object stream
|
|
|
// - offset: the offset of where to append
|
|
|
// RETURNS:
|
|
|
// - *api.AppendObjectResult: the result of the appended object
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) SimpleAppendObject(bucket, object string, content *bce.Body,
|
|
|
offset int64) (*api.AppendObjectResult, error) {
|
|
|
return api.AppendObject(c, bucket, object, content, &api.AppendObjectArgs{Offset: offset})
|
|
|
}
|
|
|
|
|
|
// SimpleAppendObjectFromString - the simple interface of appending an object from a string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - content: the object string to append
|
|
|
// - offset: the offset of where to append
|
|
|
// RETURNS:
|
|
|
// - *api.AppendObjectResult: the result of the appended object
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) SimpleAppendObjectFromString(bucket, object, content string,
|
|
|
offset int64) (*api.AppendObjectResult, error) {
|
|
|
body, err := bce.NewBodyFromString(content)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return api.AppendObject(c, bucket, object, body, &api.AppendObjectArgs{Offset: offset})
|
|
|
}
|
|
|
|
|
|
// SimpleAppendObjectFromFile - the simple interface of appending an object from a file
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - filePath: the full file path
|
|
|
// - offset: the offset of where to append
|
|
|
// RETURNS:
|
|
|
// - *api.AppendObjectResult: the result of the appended object
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) SimpleAppendObjectFromFile(bucket, object, filePath string,
|
|
|
offset int64) (*api.AppendObjectResult, error) {
|
|
|
body, err := bce.NewBodyFromFile(filePath)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return api.AppendObject(c, bucket, object, body, &api.AppendObjectArgs{Offset: offset})
|
|
|
}
|
|
|
|
|
|
// DeleteObject - delete the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to delete
|
|
|
// - object: the name of the object to delete
|
|
|
// RETURNS:
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) DeleteObject(bucket, object string) error {
|
|
|
return api.DeleteObject(c, bucket, object)
|
|
|
}
|
|
|
|
|
|
// DeleteMultipleObjects - delete a list of objects
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to delete
|
|
|
// - objectListStream: the object list stream to be deleted
|
|
|
// RETURNS:
|
|
|
// - *api.DeleteMultipleObjectsResult: the delete information
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) DeleteMultipleObjects(bucket string,
|
|
|
objectListStream *bce.Body) (*api.DeleteMultipleObjectsResult, error) {
|
|
|
return api.DeleteMultipleObjects(c, bucket, objectListStream)
|
|
|
}
|
|
|
|
|
|
// DeleteMultipleObjectsFromString - delete a list of objects with json format string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to delete
|
|
|
// - objectListString: the object list string to be deleted
|
|
|
// RETURNS:
|
|
|
// - *api.DeleteMultipleObjectsResult: the delete information
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) DeleteMultipleObjectsFromString(bucket,
|
|
|
objectListString string) (*api.DeleteMultipleObjectsResult, error) {
|
|
|
body, err := bce.NewBodyFromString(objectListString)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return api.DeleteMultipleObjects(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// DeleteMultipleObjectsFromStruct - delete a list of objects with object list struct
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to delete
|
|
|
// - objectListStruct: the object list struct to be deleted
|
|
|
// RETURNS:
|
|
|
// - *api.DeleteMultipleObjectsResult: the delete information
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) DeleteMultipleObjectsFromStruct(bucket string,
|
|
|
objectListStruct *api.DeleteMultipleObjectsArgs) (*api.DeleteMultipleObjectsResult, error) {
|
|
|
jsonBytes, jsonErr := json.Marshal(objectListStruct)
|
|
|
if jsonErr != nil {
|
|
|
return nil, jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return api.DeleteMultipleObjects(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// DeleteMultipleObjectsFromKeyList - delete a list of objects with given key string array
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket to delete
|
|
|
// - keyList: the key string list to be deleted
|
|
|
// RETURNS:
|
|
|
// - *api.DeleteMultipleObjectsResult: the delete information
|
|
|
// - error: any error if it occurs
|
|
|
func (c *Client) DeleteMultipleObjectsFromKeyList(bucket string,
|
|
|
keyList []string) (*api.DeleteMultipleObjectsResult, error) {
|
|
|
if len(keyList) == 0 {
|
|
|
return nil, fmt.Errorf("the key list to be deleted is empty")
|
|
|
}
|
|
|
args := make([]api.DeleteObjectArgs, len(keyList))
|
|
|
for i, k := range keyList {
|
|
|
args[i].Key = k
|
|
|
}
|
|
|
argsContainer := &api.DeleteMultipleObjectsArgs{args}
|
|
|
|
|
|
jsonBytes, jsonErr := json.Marshal(argsContainer)
|
|
|
if jsonErr != nil {
|
|
|
return nil, jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return api.DeleteMultipleObjects(c, bucket, body)
|
|
|
}
|
|
|
|
|
|
// InitiateMultipartUpload - initiate a multipart upload to get a upload ID
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - contentType: the content type of the object to be uploaded which should be specified,
|
|
|
// otherwise use the default(application/octet-stream)
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - *InitiateMultipartUploadResult: the result data structure
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) InitiateMultipartUpload(bucket, object, contentType string,
|
|
|
args *api.InitiateMultipartUploadArgs) (*api.InitiateMultipartUploadResult, error) {
|
|
|
return api.InitiateMultipartUpload(c, bucket, object, contentType, args)
|
|
|
}
|
|
|
|
|
|
// BasicInitiateMultipartUpload - basic interface to initiate a multipart upload
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// RETURNS:
|
|
|
// - *InitiateMultipartUploadResult: the result data structure
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) BasicInitiateMultipartUpload(bucket,
|
|
|
object string) (*api.InitiateMultipartUploadResult, error) {
|
|
|
return api.InitiateMultipartUpload(c, bucket, object, "", nil)
|
|
|
}
|
|
|
|
|
|
// UploadPart - upload the single part in the multipart upload process
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - partNumber: the current part number
|
|
|
// - content: the uploaded part content
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: the etag of the uploaded part
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) UploadPart(bucket, object, uploadId string, partNumber int,
|
|
|
content *bce.Body, args *api.UploadPartArgs) (string, error) {
|
|
|
return api.UploadPart(c, bucket, object, uploadId, partNumber, content, args)
|
|
|
}
|
|
|
|
|
|
// BasicUploadPart - basic interface to upload the single part in the multipart upload process
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - partNumber: the current part number
|
|
|
// - content: the uploaded part content
|
|
|
// RETURNS:
|
|
|
// - string: the etag of the uploaded part
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) BasicUploadPart(bucket, object, uploadId string, partNumber int,
|
|
|
content *bce.Body) (string, error) {
|
|
|
return api.UploadPart(c, bucket, object, uploadId, partNumber, content, nil)
|
|
|
}
|
|
|
|
|
|
// UploadPartFromBytes - upload the single part in the multipart upload process
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - partNumber: the current part number
|
|
|
// - content: the uploaded part content
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - string: the etag of the uploaded part
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) UploadPartFromBytes(bucket, object, uploadId string, partNumber int,
|
|
|
content []byte, args *api.UploadPartArgs) (string, error) {
|
|
|
return api.UploadPartFromBytes(c, bucket, object, uploadId, partNumber, content, args)
|
|
|
}
|
|
|
|
|
|
// UploadPartCopy - copy the multipart object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - srcBucket: the source bucket
|
|
|
// - srcObject: the source object
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - partNumber: the current part number
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - *CopyObjectResult: the lastModified and eTag of the part
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) UploadPartCopy(bucket, object, srcBucket, srcObject, uploadId string,
|
|
|
partNumber int, args *api.UploadPartCopyArgs) (*api.CopyObjectResult, error) {
|
|
|
source := fmt.Sprintf("/%s/%s", srcBucket, srcObject)
|
|
|
return api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, args)
|
|
|
}
|
|
|
|
|
|
// BasicUploadPartCopy - basic interface to copy the multipart object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - srcBucket: the source bucket
|
|
|
// - srcObject: the source object
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - partNumber: the current part number
|
|
|
// RETURNS:
|
|
|
// - *CopyObjectResult: the lastModified and eTag of the part
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) BasicUploadPartCopy(bucket, object, srcBucket, srcObject, uploadId string,
|
|
|
partNumber int) (*api.CopyObjectResult, error) {
|
|
|
source := fmt.Sprintf("/%s/%s", srcBucket, srcObject)
|
|
|
return api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, nil)
|
|
|
}
|
|
|
|
|
|
// CompleteMultipartUpload - finish a multipart upload operation with parts stream
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - parts: all parts info stream
|
|
|
// - meta: user defined meta data
|
|
|
// RETURNS:
|
|
|
// - *CompleteMultipartUploadResult: the result data
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) CompleteMultipartUpload(bucket, object, uploadId string,
|
|
|
body *bce.Body, args *api.CompleteMultipartUploadArgs) (*api.CompleteMultipartUploadResult, error) {
|
|
|
return api.CompleteMultipartUpload(c, bucket, object, uploadId, body, args)
|
|
|
}
|
|
|
|
|
|
// CompleteMultipartUploadFromStruct - finish a multipart upload operation with parts struct
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - args: args info struct object
|
|
|
// RETURNS:
|
|
|
// - *CompleteMultipartUploadResult: the result data
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) CompleteMultipartUploadFromStruct(bucket, object, uploadId string,
|
|
|
args *api.CompleteMultipartUploadArgs) (*api.CompleteMultipartUploadResult, error) {
|
|
|
jsonBytes, jsonErr := json.Marshal(args)
|
|
|
if jsonErr != nil {
|
|
|
return nil, jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
return api.CompleteMultipartUpload(c, bucket, object, uploadId, body, args)
|
|
|
}
|
|
|
|
|
|
// AbortMultipartUpload - abort a multipart upload operation
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// RETURNS:
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) AbortMultipartUpload(bucket, object, uploadId string) error {
|
|
|
return api.AbortMultipartUpload(c, bucket, object, uploadId)
|
|
|
}
|
|
|
|
|
|
// ListParts - list the successfully uploaded parts info by upload id
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - *ListPartsResult: the uploaded parts info result
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) ListParts(bucket, object, uploadId string,
|
|
|
args *api.ListPartsArgs) (*api.ListPartsResult, error) {
|
|
|
return api.ListParts(c, bucket, object, uploadId, args)
|
|
|
}
|
|
|
|
|
|
// BasicListParts - basic interface to list the successfully uploaded parts info by upload id
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - uploadId: the multipart upload id
|
|
|
// RETURNS:
|
|
|
// - *ListPartsResult: the uploaded parts info result
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) BasicListParts(bucket, object, uploadId string) (*api.ListPartsResult, error) {
|
|
|
return api.ListParts(c, bucket, object, uploadId, nil)
|
|
|
}
|
|
|
|
|
|
// ListMultipartUploads - list the unfinished uploaded parts of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - args: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - *ListMultipartUploadsResult: the unfinished uploaded parts info result
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) ListMultipartUploads(bucket string,
|
|
|
args *api.ListMultipartUploadsArgs) (*api.ListMultipartUploadsResult, error) {
|
|
|
return api.ListMultipartUploads(c, bucket, args)
|
|
|
}
|
|
|
|
|
|
// BasicListMultipartUploads - basic interface to list the unfinished uploaded parts
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// RETURNS:
|
|
|
// - *ListMultipartUploadsResult: the unfinished uploaded parts info result
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) BasicListMultipartUploads(bucket string) (
|
|
|
*api.ListMultipartUploadsResult, error) {
|
|
|
return api.ListMultipartUploads(c, bucket, nil)
|
|
|
}
|
|
|
|
|
|
// UploadSuperFile - parallel upload the super file by using the multipart upload interface
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - fileName: the local full path filename of the super file
|
|
|
// - storageClass: the storage class to be set to the uploaded file
|
|
|
// RETURNS:
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) UploadSuperFile(bucket, object, fileName, storageClass string) error {
|
|
|
// Get the file size and check the size for multipart upload
|
|
|
file, fileErr := os.Open(fileName)
|
|
|
if fileErr != nil {
|
|
|
return fileErr
|
|
|
}
|
|
|
oldTimeout := c.Config.ConnectionTimeoutInMillis
|
|
|
c.Config.ConnectionTimeoutInMillis = 0
|
|
|
defer func() {
|
|
|
c.Config.ConnectionTimeoutInMillis = oldTimeout
|
|
|
file.Close()
|
|
|
}()
|
|
|
fileInfo, infoErr := file.Stat()
|
|
|
if infoErr != nil {
|
|
|
return infoErr
|
|
|
}
|
|
|
size := fileInfo.Size()
|
|
|
if size < MIN_MULTIPART_SIZE || c.MultipartSize < MIN_MULTIPART_SIZE {
|
|
|
return bce.NewBceClientError("multipart size should not be less than 1MB")
|
|
|
}
|
|
|
|
|
|
// Calculate part size and total part number
|
|
|
partSize := (c.MultipartSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN
|
|
|
partNum := (size + partSize - 1) / partSize
|
|
|
if partNum > MAX_PART_NUMBER {
|
|
|
partSize = (size + MAX_PART_NUMBER - 1) / MAX_PART_NUMBER
|
|
|
partSize = (partSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN
|
|
|
partNum = (size + partSize - 1) / partSize
|
|
|
}
|
|
|
log.Debugf("starting upload super file, total parts: %d, part size: %d", partNum, partSize)
|
|
|
|
|
|
// Inner wrapper function of parallel uploading each part to get the ETag of the part
|
|
|
uploadPart := func(bucket, object, uploadId string, partNumber int, body *bce.Body,
|
|
|
result chan *api.UploadInfoType, ret chan error, id int64, pool chan int64) {
|
|
|
etag, err := c.BasicUploadPart(bucket, object, uploadId, partNumber, body)
|
|
|
if err != nil {
|
|
|
result <- nil
|
|
|
ret <- err
|
|
|
} else {
|
|
|
result <- &api.UploadInfoType{partNumber, etag}
|
|
|
}
|
|
|
pool <- id
|
|
|
}
|
|
|
|
|
|
// Do the parallel multipart upload
|
|
|
resp, err := c.InitiateMultipartUpload(bucket, object, "",
|
|
|
&api.InitiateMultipartUploadArgs{StorageClass: storageClass})
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
uploadId := resp.UploadId
|
|
|
uploadedResult := make(chan *api.UploadInfoType, partNum)
|
|
|
retChan := make(chan error, partNum)
|
|
|
workerPool := make(chan int64, c.MaxParallel)
|
|
|
for i := int64(0); i < c.MaxParallel; i++ {
|
|
|
workerPool <- i
|
|
|
}
|
|
|
for partId := int64(1); partId <= partNum; partId++ {
|
|
|
uploadSize := partSize
|
|
|
offset := (partId - 1) * partSize
|
|
|
left := size - offset
|
|
|
if uploadSize > left {
|
|
|
uploadSize = left
|
|
|
}
|
|
|
partBody, _ := bce.NewBodyFromSectionFile(file, offset, uploadSize)
|
|
|
select { // wait until get a worker to upload
|
|
|
case workerId := <-workerPool:
|
|
|
go uploadPart(bucket, object, uploadId, int(partId), partBody,
|
|
|
uploadedResult, retChan, workerId, workerPool)
|
|
|
case uploadPartErr := <-retChan:
|
|
|
c.AbortMultipartUpload(bucket, object, uploadId)
|
|
|
return uploadPartErr
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Check the return of each part uploading, and decide to complete or abort it
|
|
|
completeArgs := &api.CompleteMultipartUploadArgs{
|
|
|
Parts: make([]api.UploadInfoType, partNum),
|
|
|
}
|
|
|
for i := partNum; i > 0; i-- {
|
|
|
uploaded := <-uploadedResult
|
|
|
if uploaded == nil { // error occurs and not be caught in `select' statement
|
|
|
c.AbortMultipartUpload(bucket, object, uploadId)
|
|
|
return <-retChan
|
|
|
}
|
|
|
completeArgs.Parts[uploaded.PartNumber-1] = *uploaded
|
|
|
log.Debugf("upload part %d success, etag: %s", uploaded.PartNumber, uploaded.ETag)
|
|
|
}
|
|
|
if _, err := c.CompleteMultipartUploadFromStruct(bucket, object,
|
|
|
uploadId, completeArgs); err != nil {
|
|
|
c.AbortMultipartUpload(bucket, object, uploadId)
|
|
|
return err
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// DownloadSuperFile - parallel download the super file using the get object with range
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the destination bucket name
|
|
|
// - object: the destination object name
|
|
|
// - fileName: the local full path filename to store the object
|
|
|
// RETURNS:
|
|
|
// - error: nil if ok otherwise the specific error
|
|
|
func (c *Client) DownloadSuperFile(bucket, object, fileName string) (err error) {
|
|
|
file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
oldTimeout := c.Config.ConnectionTimeoutInMillis
|
|
|
c.Config.ConnectionTimeoutInMillis = 0
|
|
|
defer func() {
|
|
|
c.Config.ConnectionTimeoutInMillis = oldTimeout
|
|
|
file.Close()
|
|
|
if err != nil {
|
|
|
os.Remove(fileName)
|
|
|
}
|
|
|
}()
|
|
|
|
|
|
meta, err := c.GetObjectMeta(bucket, object)
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
|
size := meta.ContentLength
|
|
|
partSize := (c.MultipartSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN
|
|
|
partNum := (size + partSize - 1) / partSize
|
|
|
log.Debugf("starting download super file, total parts: %d, part size: %d", partNum, partSize)
|
|
|
|
|
|
doneChan := make(chan struct{}, partNum)
|
|
|
abortChan := make(chan struct{})
|
|
|
|
|
|
// Set up multiple goroutine workers to download the object
|
|
|
workerPool := make(chan int64, c.MaxParallel)
|
|
|
for i := int64(0); i < c.MaxParallel; i++ {
|
|
|
workerPool <- i
|
|
|
}
|
|
|
for i := int64(0); i < partNum; i++ {
|
|
|
rangeStart := i * partSize
|
|
|
rangeEnd := (i+1)*partSize - 1
|
|
|
if rangeEnd > size-1 {
|
|
|
rangeEnd = size - 1
|
|
|
}
|
|
|
select {
|
|
|
case workerId := <-workerPool:
|
|
|
go func(rangeStart, rangeEnd, workerId int64) {
|
|
|
res, rangeGetErr := c.GetObject(bucket, object, nil, rangeStart, rangeEnd)
|
|
|
if rangeGetErr != nil {
|
|
|
log.Errorf("download object part(offset:%d, size:%d) failed: %v",
|
|
|
rangeStart, res.ContentLength, rangeGetErr)
|
|
|
abortChan <- struct{}{}
|
|
|
err = rangeGetErr
|
|
|
return
|
|
|
}
|
|
|
defer res.Body.Close()
|
|
|
log.Debugf("writing part %d with offset=%d, size=%d", rangeStart/partSize,
|
|
|
rangeStart, res.ContentLength)
|
|
|
buf := make([]byte, 4096)
|
|
|
offset := rangeStart
|
|
|
for {
|
|
|
n, e := res.Body.Read(buf)
|
|
|
if e != nil && e != io.EOF {
|
|
|
abortChan <- struct{}{}
|
|
|
err = e
|
|
|
return
|
|
|
}
|
|
|
if n == 0 {
|
|
|
break
|
|
|
}
|
|
|
if _, writeErr := file.WriteAt(buf[:n], offset); writeErr != nil {
|
|
|
abortChan <- struct{}{}
|
|
|
err = writeErr
|
|
|
return
|
|
|
}
|
|
|
offset += int64(n)
|
|
|
}
|
|
|
log.Debugf("writing part %d done", rangeStart/partSize)
|
|
|
workerPool <- workerId
|
|
|
doneChan <- struct{}{}
|
|
|
}(rangeStart, rangeEnd, workerId)
|
|
|
case <-abortChan: // abort range get if error occurs during downloading any part
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Wait for writing to local file done
|
|
|
for i := partNum; i > 0; i-- {
|
|
|
<-doneChan
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// GeneratePresignedUrl - generate an authorization url with expire time and optional arguments
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the target bucket name
|
|
|
// - object: the target object name
|
|
|
// - expireInSeconds: the expire time in seconds of the signed url
|
|
|
// - method: optional sign method, default is GET
|
|
|
// - headers: optional sign headers, default just set the Host
|
|
|
// - params: optional sign params, default is empty
|
|
|
// RETURNS:
|
|
|
// - string: the presigned url with authorization string
|
|
|
func (c *Client) GeneratePresignedUrl(bucket, object string, expireInSeconds int, method string,
|
|
|
headers, params map[string]string) string {
|
|
|
return api.GeneratePresignedUrl(c.Config, c.Signer, bucket, object,
|
|
|
expireInSeconds, method, headers, params)
|
|
|
}
|
|
|
|
|
|
func (c *Client) GeneratePresignedUrlPathStyle(bucket, object string, expireInSeconds int, method string,
|
|
|
headers, params map[string]string) string {
|
|
|
return api.GeneratePresignedUrlPathStyle(c.Config, c.Signer, bucket, object,
|
|
|
expireInSeconds, method, headers, params)
|
|
|
}
|
|
|
|
|
|
// BasicGeneratePresignedUrl - basic interface to generate an authorization url with expire time
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the target bucket name
|
|
|
// - object: the target object name
|
|
|
// - expireInSeconds: the expire time in seconds of the signed url
|
|
|
// RETURNS:
|
|
|
// - string: the presigned url with authorization string
|
|
|
func (c *Client) BasicGeneratePresignedUrl(bucket, object string, expireInSeconds int) string {
|
|
|
return api.GeneratePresignedUrl(c.Config, c.Signer, bucket, object,
|
|
|
expireInSeconds, "", nil, nil)
|
|
|
}
|
|
|
|
|
|
// PutObjectAcl - set the ACL of the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - aclBody: the acl json body stream
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAcl(bucket, object string, aclBody *bce.Body) error {
|
|
|
return api.PutObjectAcl(c, bucket, object, "", nil, nil, aclBody)
|
|
|
}
|
|
|
|
|
|
// PutObjectAclFromCanned - set the canned acl of the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - cannedAcl: the cannedAcl string
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAclFromCanned(bucket, object, cannedAcl string) error {
|
|
|
return api.PutObjectAcl(c, bucket, object, cannedAcl, nil, nil, nil)
|
|
|
}
|
|
|
|
|
|
// PutObjectAclGrantRead - set the canned grant read acl of the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - ids: the user id list to grant read for this object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAclGrantRead(bucket, object string, ids ...string) error {
|
|
|
return api.PutObjectAcl(c, bucket, object, "", ids, nil, nil)
|
|
|
}
|
|
|
|
|
|
// PutObjectAclGrantFullControl - set the canned grant full-control acl of the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - ids: the user id list to grant full-control for this object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAclGrantFullControl(bucket, object string, ids ...string) error {
|
|
|
return api.PutObjectAcl(c, bucket, object, "", nil, ids, nil)
|
|
|
}
|
|
|
|
|
|
// PutObjectAclFromFile - set the acl of the given object with acl json file name
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - aclFile: the acl file name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAclFromFile(bucket, object, aclFile string) error {
|
|
|
body, err := bce.NewBodyFromFile(aclFile)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutObjectAcl(c, bucket, object, "", nil, nil, body)
|
|
|
}
|
|
|
|
|
|
// PutObjectAclFromString - set the acl of the given object with acl json string
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - aclString: the acl string with json format
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAclFromString(bucket, object, aclString string) error {
|
|
|
body, err := bce.NewBodyFromString(aclString)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutObjectAcl(c, bucket, object, "", nil, nil, body)
|
|
|
}
|
|
|
|
|
|
// PutObjectAclFromStruct - set the acl of the given object with acl data structure
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - aclObj: the acl struct object
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutObjectAclFromStruct(bucket, object string, aclObj *api.PutObjectAclArgs) error {
|
|
|
jsonBytes, jsonErr := json.Marshal(aclObj)
|
|
|
if jsonErr != nil {
|
|
|
return jsonErr
|
|
|
}
|
|
|
body, err := bce.NewBodyFromBytes(jsonBytes)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
return api.PutObjectAcl(c, bucket, object, "", nil, nil, body)
|
|
|
}
|
|
|
|
|
|
// GetObjectAcl - get the acl of the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// RETURNS:
|
|
|
// - *api.GetObjectAclResult: the result of the object acl
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetObjectAcl(bucket, object string) (*api.GetObjectAclResult, error) {
|
|
|
return api.GetObjectAcl(c, bucket, object)
|
|
|
}
|
|
|
|
|
|
// DeleteObjectAcl - delete the acl of the given object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteObjectAcl(bucket, object string) error {
|
|
|
return api.DeleteObjectAcl(c, bucket, object)
|
|
|
}
|
|
|
|
|
|
// RestoreObject - restore the archive object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - restoreDays: the effective time of restore
|
|
|
// - restoreTier: the tier of restore
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) RestoreObject(bucket string, object string, restoreDays int, restoreTier string) error {
|
|
|
if _, ok := api.VALID_RESTORE_TIER[restoreTier]; !ok {
|
|
|
return errors.New("invalid restore tier")
|
|
|
}
|
|
|
|
|
|
if restoreDays <= 0 {
|
|
|
return errors.New("invalid restore days")
|
|
|
}
|
|
|
|
|
|
args := api.ArchiveRestoreArgs{
|
|
|
RestoreTier: restoreTier,
|
|
|
RestoreDays: restoreDays,
|
|
|
}
|
|
|
return api.RestoreObject(c, bucket, object, args)
|
|
|
}
|
|
|
|
|
|
// PutBucketTrash - put the bucket trash
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - trashReq: the trash request
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketTrash(bucket string, trashReq api.PutBucketTrashReq) error {
|
|
|
return api.PutBucketTrash(c, bucket, trashReq)
|
|
|
}
|
|
|
|
|
|
// GetBucketTrash - get the bucket trash
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - *api.GetBucketTrashResult,: the result of the bucket trash
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketTrash(bucket string) (*api.GetBucketTrashResult, error) {
|
|
|
return api.GetBucketTrash(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketTrash - delete the trash of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketTrash(bucket string) error {
|
|
|
return api.DeleteBucketTrash(c, bucket)
|
|
|
}
|
|
|
|
|
|
// PutBucketNotification - put the bucket notification
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - putBucketNotificationReq: the bucket notification request
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) PutBucketNotification(bucket string, putBucketNotificationReq api.PutBucketNotificationReq) error {
|
|
|
return api.PutBucketNotification(c, bucket, putBucketNotificationReq)
|
|
|
}
|
|
|
|
|
|
// GetBucketNotification - get the bucket notification
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - *api.PutBucketNotificationReq,: the result of the bucket notification
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) GetBucketNotification(bucket string) (*api.PutBucketNotificationReq, error) {
|
|
|
return api.GetBucketNotification(c, bucket)
|
|
|
}
|
|
|
|
|
|
// DeleteBucketNotification - delete the notification of the given bucket
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// RETURNS:
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) DeleteBucketNotification(bucket string) error {
|
|
|
return api.DeleteBucketNotification(c, bucket)
|
|
|
}
|
|
|
|
|
|
// ParallelUpload - auto multipart upload object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - filename: the filename
|
|
|
// - contentType: the content type default(application/octet-stream)
|
|
|
// - args: the bucket name nil using default
|
|
|
// RETURNS:
|
|
|
// - *api.CompleteMultipartUploadResult: multipart upload result
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) ParallelUpload(bucket string, object string, filename string, contentType string, args *api.InitiateMultipartUploadArgs) (*api.CompleteMultipartUploadResult, error) {
|
|
|
|
|
|
initiateMultipartUploadResult, err := api.InitiateMultipartUpload(c, bucket, object, contentType, args)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
partEtags, err := c.parallelPartUpload(bucket, object, filename, initiateMultipartUploadResult.UploadId)
|
|
|
if err != nil {
|
|
|
c.AbortMultipartUpload(bucket, object, initiateMultipartUploadResult.UploadId)
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
completeMultipartUploadResult, err := c.CompleteMultipartUploadFromStruct(bucket, object, initiateMultipartUploadResult.UploadId, &api.CompleteMultipartUploadArgs{Parts: partEtags})
|
|
|
if err != nil {
|
|
|
c.AbortMultipartUpload(bucket, object, initiateMultipartUploadResult.UploadId)
|
|
|
return nil, err
|
|
|
}
|
|
|
return completeMultipartUploadResult, nil
|
|
|
}
|
|
|
|
|
|
// parallelPartUpload - single part upload
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - filename: the uploadId
|
|
|
// - uploadId: the uploadId
|
|
|
// RETURNS:
|
|
|
// - []api.UploadInfoType: multipart upload result
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) parallelPartUpload(bucket string, object string, filename string, uploadId string) ([]api.UploadInfoType, error) {
|
|
|
file, err := os.Open(filename)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
defer file.Close()
|
|
|
// 分块大小按MULTIPART_ALIGN=1MB对齐
|
|
|
partSize := (c.MultipartSize +
|
|
|
MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN
|
|
|
|
|
|
// 获取文件大小,并计算分块数目,最大分块数MAX_PART_NUMBER=10000
|
|
|
fileInfo, _ := file.Stat()
|
|
|
fileSize := fileInfo.Size()
|
|
|
partNum := (fileSize + partSize - 1) / partSize
|
|
|
if partNum > MAX_PART_NUMBER { // 超过最大分块数,需调整分块大小
|
|
|
partSize = (fileSize + MAX_PART_NUMBER + 1) / MAX_PART_NUMBER
|
|
|
partSize = (partSize + MULTIPART_ALIGN - 1) / MULTIPART_ALIGN * MULTIPART_ALIGN
|
|
|
partNum = (fileSize + partSize - 1) / partSize
|
|
|
}
|
|
|
|
|
|
parallelChan := make(chan int, c.MaxParallel)
|
|
|
|
|
|
errChan := make(chan error, c.MaxParallel)
|
|
|
|
|
|
resultChan := make(chan api.UploadInfoType, partNum)
|
|
|
|
|
|
// 逐个分块上传
|
|
|
for i := int64(1); i <= partNum; i++ {
|
|
|
// 计算偏移offset和本次上传的大小uploadSize
|
|
|
uploadSize := partSize
|
|
|
offset := partSize * (i - 1)
|
|
|
left := fileSize - offset
|
|
|
if left < partSize {
|
|
|
uploadSize = left
|
|
|
}
|
|
|
|
|
|
// 创建指定偏移、指定大小的文件流
|
|
|
partBody, _ := bce.NewBodyFromSectionFile(file, offset, uploadSize)
|
|
|
|
|
|
select {
|
|
|
case err = <-errChan:
|
|
|
return nil, err
|
|
|
default:
|
|
|
select {
|
|
|
case err = <-errChan:
|
|
|
return nil, err
|
|
|
case parallelChan <- 1:
|
|
|
go c.singlePartUpload(bucket, object, uploadId, int(i), partBody, parallelChan, errChan, resultChan)
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
partEtags := make([]api.UploadInfoType, partNum)
|
|
|
for i := int64(0); i < partNum; i++ {
|
|
|
select {
|
|
|
case err := <-errChan:
|
|
|
return nil, err
|
|
|
case result := <-resultChan:
|
|
|
partEtags[result.PartNumber-1].PartNumber = result.PartNumber
|
|
|
partEtags[result.PartNumber-1].ETag = result.ETag
|
|
|
}
|
|
|
}
|
|
|
return partEtags, nil
|
|
|
}
|
|
|
|
|
|
// singlePartUpload - single part upload
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - pararelChan: the pararelChan
|
|
|
// - errChan: the error chan
|
|
|
// - result: the upload result chan
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - uploadId: the uploadId
|
|
|
// - partNumber: the part number of the object
|
|
|
// - content: the content of current part
|
|
|
func (c *Client) singlePartUpload(
|
|
|
bucket string, object string, uploadId string,
|
|
|
partNumber int, content *bce.Body,
|
|
|
parallelChan chan int, errChan chan error, result chan api.UploadInfoType) {
|
|
|
|
|
|
defer func() {
|
|
|
if r := recover(); r != nil {
|
|
|
log.Fatal("parallelPartUpload recovered in f:", r)
|
|
|
errChan <- errors.New("parallelPartUpload panic")
|
|
|
}
|
|
|
<-parallelChan
|
|
|
}()
|
|
|
|
|
|
var args api.UploadPartArgs
|
|
|
args.ContentMD5 = content.ContentMD5()
|
|
|
|
|
|
etag, err := api.UploadPart(c, bucket, object, uploadId, partNumber, content, &args)
|
|
|
if err != nil {
|
|
|
errChan <- err
|
|
|
log.Error("upload part fail,err:%v", err)
|
|
|
return
|
|
|
}
|
|
|
result <- api.UploadInfoType{PartNumber: partNumber, ETag: etag}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// ParallelCopy - auto multipart copy object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - srcBucketName: the src bucket name
|
|
|
// - srcObjectName: the src object name
|
|
|
// - destBucketName: the dest bucket name
|
|
|
// - destObjectName: the dest object name
|
|
|
// - args: the copy args
|
|
|
// - srcClient: the src region client
|
|
|
// RETURNS:
|
|
|
// - *api.CompleteMultipartUploadResult: multipart upload result
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) ParallelCopy(srcBucketName string, srcObjectName string,
|
|
|
destBucketName string, destObjectName string,
|
|
|
args *api.MultiCopyObjectArgs, srcClient *Client) (*api.CompleteMultipartUploadResult, error) {
|
|
|
|
|
|
if srcClient == nil {
|
|
|
srcClient = c
|
|
|
}
|
|
|
objectMeta, err := srcClient.GetObjectMeta(srcBucketName, srcObjectName)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
initArgs := api.InitiateMultipartUploadArgs{
|
|
|
CacheControl: objectMeta.CacheControl,
|
|
|
ContentDisposition: objectMeta.ContentDisposition,
|
|
|
Expires: objectMeta.Expires,
|
|
|
StorageClass: objectMeta.StorageClass,
|
|
|
}
|
|
|
if args != nil {
|
|
|
if len(args.StorageClass) != 0 {
|
|
|
initArgs.StorageClass = args.StorageClass
|
|
|
}
|
|
|
}
|
|
|
initiateMultipartUploadResult, err := api.InitiateMultipartUpload(c, destBucketName, destObjectName, objectMeta.ContentType, &initArgs)
|
|
|
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
source := fmt.Sprintf("/%s/%s", srcBucketName, srcObjectName)
|
|
|
partEtags, err := c.parallelPartCopy(*objectMeta, source, destBucketName, destObjectName, initiateMultipartUploadResult.UploadId)
|
|
|
|
|
|
if err != nil {
|
|
|
c.AbortMultipartUpload(destBucketName, destObjectName, initiateMultipartUploadResult.UploadId)
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
completeMultipartUploadResult, err := c.CompleteMultipartUploadFromStruct(destBucketName, destObjectName, initiateMultipartUploadResult.UploadId, &api.CompleteMultipartUploadArgs{Parts: partEtags})
|
|
|
if err != nil {
|
|
|
c.AbortMultipartUpload(destBucketName, destObjectName, initiateMultipartUploadResult.UploadId)
|
|
|
return nil, err
|
|
|
}
|
|
|
return completeMultipartUploadResult, nil
|
|
|
}
|
|
|
|
|
|
// parallelPartCopy - parallel part copy
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - srcMeta: the copy source object meta
|
|
|
// - source: the copy source
|
|
|
// - bucket: the dest bucket name
|
|
|
// - object: the dest object name
|
|
|
// - uploadId: the uploadId
|
|
|
// RETURNS:
|
|
|
// - []api.UploadInfoType: multipart upload result
|
|
|
// - error: nil if success otherwise the specific error
|
|
|
func (c *Client) parallelPartCopy(srcMeta api.GetObjectMetaResult, source string, bucket string, object string, uploadId string) ([]api.UploadInfoType, error) {
|
|
|
var err error
|
|
|
size := srcMeta.ContentLength
|
|
|
partSize := int64(DEFAULT_MULTIPART_SIZE)
|
|
|
|
|
|
partNum := (size + partSize - 1) / partSize
|
|
|
|
|
|
parallelChan := make(chan int, c.MaxParallel)
|
|
|
|
|
|
errChan := make(chan error, c.MaxParallel)
|
|
|
|
|
|
resultChan := make(chan api.UploadInfoType, partNum)
|
|
|
|
|
|
for i := int64(1); i <= partNum; i++ {
|
|
|
// 计算偏移offset和本次上传的大小uploadSize
|
|
|
uploadSize := partSize
|
|
|
offset := partSize * (i - 1)
|
|
|
left := size - offset
|
|
|
if left < partSize {
|
|
|
uploadSize = left
|
|
|
}
|
|
|
|
|
|
partCopyArgs := api.UploadPartCopyArgs{
|
|
|
SourceRange: fmt.Sprintf("bytes=%d-%d", (i-1)*partSize, (i-1)*partSize+uploadSize-1),
|
|
|
IfMatch: srcMeta.ETag,
|
|
|
}
|
|
|
|
|
|
select {
|
|
|
case err = <-errChan:
|
|
|
return nil, err
|
|
|
default:
|
|
|
select {
|
|
|
case err = <-errChan:
|
|
|
return nil, err
|
|
|
case parallelChan <- 1:
|
|
|
go c.singlePartCopy(source, bucket, object, uploadId, int(i), &partCopyArgs, parallelChan, errChan, resultChan)
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
partEtags := make([]api.UploadInfoType, partNum)
|
|
|
for i := int64(0); i < partNum; i++ {
|
|
|
select {
|
|
|
case err := <-errChan:
|
|
|
return nil, err
|
|
|
case result := <-resultChan:
|
|
|
partEtags[result.PartNumber-1].PartNumber = result.PartNumber
|
|
|
partEtags[result.PartNumber-1].ETag = result.ETag
|
|
|
}
|
|
|
}
|
|
|
return partEtags, nil
|
|
|
}
|
|
|
|
|
|
// singlePartCopy - single part copy
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - pararelChan: the pararelChan
|
|
|
// - errChan: the error chan
|
|
|
// - result: the upload result chan
|
|
|
// - source: the copy source
|
|
|
// - bucket: the bucket name
|
|
|
// - object: the object name
|
|
|
// - uploadId: the uploadId
|
|
|
// - partNumber: the part number of the object
|
|
|
// - args: the copy args
|
|
|
func (c *Client) singlePartCopy(source string, bucket string, object string, uploadId string,
|
|
|
partNumber int, args *api.UploadPartCopyArgs,
|
|
|
parallelChan chan int, errChan chan error, result chan api.UploadInfoType) {
|
|
|
|
|
|
defer func() {
|
|
|
if r := recover(); r != nil {
|
|
|
log.Fatal("parallelPartUpload recovered in f:", r)
|
|
|
errChan <- errors.New("parallelPartUpload panic")
|
|
|
}
|
|
|
<-parallelChan
|
|
|
}()
|
|
|
|
|
|
copyObjectResult, err := api.UploadPartCopy(c, bucket, object, source, uploadId, partNumber, args)
|
|
|
if err != nil {
|
|
|
errChan <- err
|
|
|
log.Error("upload part fail,err:%v", err)
|
|
|
return
|
|
|
}
|
|
|
result <- api.UploadInfoType{PartNumber: partNumber, ETag: copyObjectResult.ETag}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// PutSymlink - create symlink for exist target object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the object
|
|
|
// - symlinkKey: the name of the symlink
|
|
|
// - symlinkArgs: the optional arguments
|
|
|
// RETURNS:
|
|
|
// - error: the put error if any occurs
|
|
|
func (c *Client) PutSymlink(bucket string, object string, symlinkKey string, symlinkArgs *api.PutSymlinkArgs) error {
|
|
|
return api.PutObjectSymlink(c, bucket, object, symlinkKey, symlinkArgs)
|
|
|
}
|
|
|
|
|
|
// PutSymlink - create symlink for exist target object
|
|
|
//
|
|
|
// PARAMS:
|
|
|
// - bucket: the name of the bucket
|
|
|
// - object: the name of the symlink
|
|
|
// RETURNS:
|
|
|
// - string: the target of the symlink
|
|
|
// - error: the put error if any occurs
|
|
|
func (c *Client) GetSymlink(bucket string, object string) (string, error) {
|
|
|
return api.GetObjectSymlink(c, bucket, object)
|
|
|
}
|