# Tích hợp Object Storage với Go

## Giới thiệu <a href="#gi-i-thi-u" id="gi-i-thi-u"></a>

Tài liệu hướng dẫn sử dụng SDKs

Trong trang này sẽ bao gôm những ví dụ đơn giản nhất để tìm hiểu về chức năng của s3.

Các chức năng khi kết hợp với nhau sẽ giúp người dùng có được tính năng hay và thú vị.

## Cài đặt <a href="#cai-d-t" id="cai-d-t"></a>

```
go get "github.com/aws/aws-sdk-go/aws"
```

## Khởi tạo kết nối <a href="#kh-i-t-o-k-t-n-i" id="kh-i-t-o-k-t-n-i"></a>

API: <https://s3.xorcloud.net>

```
s3Config := &aws.Config{
    Credentials: credentials.NewStaticCredentials("<ACCESS_KEY_ID>", "<SECRET_KEY_ID>", ""),
    Endpoint:    aws.String("https://s3.xorcloud.net"),
    Region:      aws.String("hn"),
}
newSession := session.New(s3Config)
Client = s3.New(newSession)
```

Trong đó `<ACCESS_KEY_ID>` và `<SECRET_KEY_ID>` được lấy từ [giao diện quản lý API key](https://manage.vccloud.vn/account/security)

## Tính năng Secure Token <a href="#tinh-nang-secure-token" id="tinh-nang-secure-token"></a>

Mô tả : tính năng này giúp người dùng tạo ra các cặp key, secret đi kèm session token có thời hạn sử dụng (tối đa là 24 giờ). Việc sử dụng key, secret và session token có thể thực hiện tất cả các thao tác với bucket và file như sử dụng cặp key, secret bình thường.

Chức năng này rất có ích trong việc sử dụng frontend upload nhiều file liên tiếp hoặc đưa cho các ứng dụng sử dụng trong thời gian ngắn.

### Tạo các cặp key, secret tạm <a href="#t-o-cac-c-p-key-secret-t-m" id="t-o-cac-c-p-key-secret-t-m"></a>

Thực hiện việc tạo các cặp key, secret tạm.

```
Working on it.
```

### Sử dụng các cặp key, secret tạm <a href="#s-d-ng-cac-c-p-key-secret-t-m" id="s-d-ng-cac-c-p-key-secret-t-m"></a>

Sử dụng các cặp key, secret tạm

```
Working on it.
```

## Quản lý bucket <a href="#qu-n-ly-bucket" id="qu-n-ly-bucket"></a>

### Lấy, tạo mới, xoá <a href="#l-y-t-o-m-i-xoa" id="l-y-t-o-m-i-xoa"></a>

**Tham số**

`<BUCKET-NAME>` : tên bucket chỉ nên có các ký tự số (0->9), chữ thường (a->z), gạch ngang "-" để các bucket có thể truy cập từ đường link url không bị lỗi và các thao tác config không bị lỗi trong quá trình sử dụng.

> Lấy danh sách

```
buckets, _ := Client.ListBuckets(&s3.ListBucketsInput{})
```

> Ví dụ lấy bucket có tên là `bucket-01`

```
bucket, _ := Client.ListObjects(&s3.ListObjectsInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Tạo mới bucket

```
Client.CreateBucket(&s3.CreateBucketInput{
        Bucket: aws.String("<BUCKET-NAME>"),
    })
```

> Xoá

```
Client.DeleteBucket(&s3.DeleteBucketInput{
        Bucket: aws.String("<BUCKET-NAME>"),
    })
```

### Danh sách file <a href="#danh-sach-file" id="danh-sach-file"></a>

Lấy ra danh sách các file có trong bucket, mặc định sẽ trả về 1000 kết quả.

> Ví dụ lấy danh sách file trong thư mục `gach/` trong bucket `bucket-01`

```
listFile, _ := Client.ListObjects(&s3.ListObjectsInput{
        Bucket: aws.String("bucket-01"),
        Prefix: aws.String("gach/"),
    })
```

### Quản lý Bucket ACL <a href="#qu-n-ly-bucket-acl" id="qu-n-ly-bucket-acl"></a>

ACL - Access Control List: cho phép bạn quản lý truy cập vào bucket. Mỗi bucket có một ACL, nó định nghĩa người dùng hoặc nhóm người dùng nào có quyền truy cập gì vào bucket của bạn.

Khi tạo một bucket, một ACL mặc định (`FULL_CONTROL`) được đính vào bucket cho phép chủ sở hữu bucket có toàn quyền trên bucket đó.

> Get

```
acl, _ := Client.GetBucketAcl(&s3.GetBucketAclInput{
        Bucket: aws.String("bucket"),
    })
```

> Set

```
sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
        Config:            *s3Config,
    }))

svc := s3.New(sess)
result, _ := svc.GetBucketAcl(&s3.GetBucketAclInput{Bucket: aws.String("bucket-01")})

userType := "AmazonCustomerByEmail"
owner := *result.Owner.DisplayName
ownerId := *result.Owner.ID
grants := result.Grants
var newGrantee = s3.Grantee{EmailAddress: aws.String("email"), Type: &userType}
var newGrant = s3.Grant{Grantee: &newGrantee, Permission: aws.String("<CANNED_ACL>")}

grants = append(grants, &newGrant)
params := &s3.PutBucketAclInput{
    Bucket: aws.String("bucket-01"),
    AccessControlPolicy: &s3.AccessControlPolicy{
        Grants: grants,
        Owner: &s3.Owner{
            DisplayName: &owner,
            ID:          &ownerId,
        },
    },
}
svc.PutBucketAcl(params)
```

**Tham số**

`<CANNED_ACL>` thuộc một trong các giá trị sau:

`private` Chủ sở hữu có toàn quyền (FULL\_CONTROL), không ai khác có quyền truy cập (mặc định)

`public-read` Chủ sở hữu có toàn quyền (FULL\_CONTROL), Tất cả người dùng khác có quyền đọc (READ)

`public-read-write` Chủ sở hữu có toàn quyền (FULL\_CONTROL), Tất cả người dùng khác có quyền đọc (READ) và ghi (WRITE)

`authenticated-read` Chủ sở hữu có toàn quyền (FULL\_CONTROL), Tất cả người dùng đăng nhập khác có quyền đọc (READ)

### Quản lý Bucket Policy <a href="#qu-n-ly-bucket-policy" id="qu-n-ly-bucket-policy"></a>

Bucket Policy: cho phép phân quyền chi tiết cho từng người dùng cụ thể ở trong hệ thống S3 Storage của X-OR Cloud.

Chức năng này được sử dụng để thực hiện chia sẻ tài nguyên dùng chung giữa nhiều tài khoản khác nhau.

Kết hợp chức năng này với chức năng Payment Requester sẽ được sử dụng như là tính năng phân quyền cho từng người dùng và tính toán chi phí cho từng dự án (hay người) khác nhau.

> Get

```
policy, _ := Client.GetBucketPolicy(&s3.GetBucketPolicyInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Set

```
policy := map[string]interface{}{
        "Version": "2012-10-17",
        "Statement": []map[string]interface{}{
            {
                "Sid":       "AddPerm",
                "Effect":    "Allow",
                "Principal": "*",
                "Action": []string{
                    "s3:GetObject",
                },
                "Resource": []string{
                    fmt.Sprintf("arn:aws:s3:::%s/<BUCKET-NAME>", "bucket-01"),
                    fmt.Sprintf("arn:aws:s3:::%s/<BUCKET-NAME>/*", "bucket-01")
                },
            },
        },
    }
    out, _ := json.Marshal(policy)
    Client.PutBucketPolicy(&s3.PutBucketPolicyInput{
        Bucket: aws.String("bucket-01"),
        Policy: aws.String(string(out)),
    })
```

**Tham số**

Ví dụ về policy

```
{
        'Version': '2012-10-17',
        'Statement': [
            {
                'Effect': 'Allow',
                'Principal': {
                    'AWS': ['arn:aws:iam:::user/<USER-UID>']
                },
                'Action': [
                    's3:<ACTION-NAME>',
                ],
                'Resource': [
                    'arn:aws:s3:::<BUCKET-NAME>',
                    'arn:aws:s3:::<BUCKET-NAME>/*'
                ]
            },
            {
                'Effect': 'Deny',
                'Principal': {
                    'AWS': ['arn:aws:iam:::user/<USER-UID>']
                },
                'Action': [
                    's3:<ACTION-NAME>',
                    's3:<ACTION-NAME>'
                ],
                'Resource': [
                    'arn:aws:s3:::<BUCKET-NAME>',
                    'arn:aws:s3:::<BUCKET-NAME>/*'
                ]
            }
        ]
    }
```

Trong policy ở trên sẽ có phần

* `'Version': '2012-10-17'` : Đây là xác định version của policy, phần này không thể thay đổi
* `Statement` Đây là danh sách quyền truy cập vào các tài nguyên của bucket , ví dụ như được truy cập vào bucket A và không được truy cập vào bucket B, có thể có nhiều quyền truy cập trong 1 Statement

Trong 1 thành phần Statement thì sẽ có cách thành phần con như sau:

* `Effect` có thể là 1 trong 2 giá trị là `Allow` hoặc `Deny` sẽ quyết định có quyền truy cập vào tài nguyên
* `Principal` là định danh của người dùng được phân quyền trong phần `Effect` trong đó `<USER-UID>` là ID của người dùng được phân quyền
* `Action` là danh sách các thao tác được cho phép hoặc bị cấm tác động lên bucket hoặc file bởi người dùng ở phần `Principal`
  * Các action này có thể là 1 hoặc kết hợp nhiều action dưới đây :

`AbortMultipartUpload`, `CreateBucket`, `DeleteBucketPolicy`, `DeleteBucket`, `DeleteBucketWebsite`, `DeleteObject`, `DeleteObjectVersion`, `DeleteReplicationConfiguration`, `GetAccelerateConfiguration`, `GetBucketAcl`, `GetBucketCORS`, `GetBucketLocation`, `GetBucketLogging`, `GetBucketNotification`, `GetBucketPolicy`, `GetBucketRequestPayment`, `GetBucketTagging`, `GetBucketVersioning`, `GetBucketWebsite`, `GetLifecycleConfiguration`, `GetObjectAcl`, `GetObject`, `GetObjectTorrent`, `GetObjectVersionAcl`, `GetObjectVersion`, `GetObjectVersionTorrent`, `GetReplicationConfiguration`, `ListAllMyBuckets`, `ListBucketMultiPartUploads`, `ListBucket`, `ListBucketVersions`, `ListMultipartUploadParts`, `PutAccelerateConfiguration`, `PutBucketAcl`, `PutBucketCORS`, `PutBucketLogging`, `PutBucketNotification`, `PutBucketPolicy`, `PutBucketRequestPayment`, `PutBucketTagging`, `PutBucketVersioning`, `PutBucketWebsite`, `PutLifecycleConfiguration`, `PutObjectAcl`, `PutObject`, `PutObjectVersionAcl`, `PutReplicationConfiguration`, `RestoreObject`

* `Resource` là tài nguyên được chỉ định để thao tác
  * `arn:aws:s3:::<BUCKET-NAME>` resource là bucket thường đi kèm với các thao tác tác động tới Bucket như ListBucket, PutBucketAcl, PutBucketCORS ...
  * `arn:aws:s3:::<BUCKET-NAME>/*` resource này là tất cả các file trong bucket, ngoài ra có thể định cho một prefix nhất định của bucket như là `arn:aws:s3:::<BUCKET-NAME>/prefix1/*`, khi đó thì resource sẽ là những bucket có prefix là prefix1. Resource này thường được đi kèm với cả các action như GetObject, PutObject, PutBucketAcl, GetObjectAcl

Một số ví dụ cụ thể về bucket policy

* Policy cho phép user `a7d1e56edcac40d0896d2b97f414afc5` download file từ bucket `bucket-dev`

```
{
    'Version': '2012-10-17',
    'Statement': [
        {
            'Effect': 'Allow',
            'Principal': {
                'AWS': ['arn:aws:iam:::user/a7d1e56edcac40d0896d2b97f414afc5']
            },
            'Action': [
                's3:GetObject',
                's3:ListBucket'
            ],
            'Resource': [
                'arn:aws:s3:::bucket-dev',
                'arn:aws:s3:::bucket-dev/*'
            ]
        }
    ]
}
```

* Policy cho phép user `a7d1e56edcac40d0896d2b97f414afc5` upload file từ bucket `bucket-dev`, bao gồm cả các thao tác liên quan đến multi-part upload

```
{
    'Version': '2012-10-17',
    'Statement': [
        {
            'Effect': 'Allow',
            'Principal': {
                'AWS': ['arn:aws:iam:::user/a7d1e56edcac40d0896d2b97f414afc5']
            },
            'Action': [
                's3:PutObjectAcl',
                's3:PutObject',
                's3:PutObjectVersionAcl',
                's3:RestoreObject',
                's3:GetObjectAcl',
                's3:GetObjectTorrent',
                's3:GetObjectVersionAcl',
                's3:GetObjectVersion',
                's3:ListBucketMultipartUploads',
                's3:ListMultipartUploadParts',
                's3:ListBucket',
                's3:AbortMultipartUpload'
            ],
            'Resource': [
                'arn:aws:s3:::bucket-dev',
                'arn:aws:s3:::bucket-dev/*'
            ]
        }
    ]
}
```

> Delete

```
Client.DeleteBucketPolicy(&s3.DeleteBucketPolicyInput{
        Bucket: aws.String("bucket-01"),
    })
```

### Quản lý Bucket CORS <a href="#qu-n-ly-bucket-cors" id="qu-n-ly-bucket-cors"></a>

Bucket CORS - Cross-Origin Resource Sharing: là cơ chế cho phép các website với các tên miền khác nhau truy cập cùng một bucket và các resource bên trong. Xem thêm [CORS - Wikipedia](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)

> Get

```
cors, _ := Client.GetBucketCors(&s3.GetBucketCorsInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Ví dụ set bucket CORS cho trang `http://mysite.com`, với phương thức là GET, cho phép gửi và nhận bất cứ header nào, đồng thời set thời gian cache preflight response là 300 giây.

```
Client.PutBucketCors(&s3.PutBucketCorsInput{
        Bucket: aws.String("bucket-01"),
        CORSConfiguration: &s3.CORSConfiguration{
            CORSRules: []*s3.CORSRule{&s3.CORSRule{
                AllowedHeaders: aws.StringSlice([]string{"*"}),
                AllowedOrigins: aws.StringSlice([]string{"http://mysite.com"}),
                MaxAgeSeconds:  aws.Int64(300),
                AllowedMethods: aws.StringSlice([]string{"GET"}),
            }},
        },
    })
```

> Delete

```
Client.DeleteBucketCors(&s3.DeleteBucketCorsInput{
        Bucket: aws.String("bucket-01"),
    })
```

### Quản lý Bucket Versioning <a href="#qu-n-ly-bucket-versioning" id="qu-n-ly-bucket-versioning"></a>

Bucket Versioning: khi được bật VCCloud Simple Storage sẽ tự động tạo một phiên bản lưu trữ mỗi khi file bị ghi đè hoặc xoá, cho phép người dùng có thể khôi phục file về các trạng thái trước đó.

> Trạng thái hiện tại

```
Client.GetBucketVersioning(&s3.GetBucketVersioningInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Bật/Tắt bucket versioning

```
Client.PutBucketVersioning(&s3.PutBucketVersioningInput{
        Bucket: aws.String("bucket-01"),
        VersioningConfiguration: &s3.VersioningConfiguration{
            Status: aws.String("<STATUS>"),
        },
    })
```

**Tham số**

`<STATUS>` là `True` hoặc `False` tương ứng với trạng thái `Bật` hoặc `Tắt`

### Quản lý Bucket Website <a href="#qu-n-ly-bucket-website" id="qu-n-ly-bucket-website"></a>

Bucket Website: khi được bật VCCloud Simple Storage sẽ biến bucket đó thành 1 static hosting để chứa các file static (html,css,js,image ...).

Tính năng này rất phù hợp với các dạng trang làm landing page, các dạng code frontend generate ra HTML, CSS, JS.

> Kiểm tra cấu hình hiện tại

```
Client.GetBucketWebsite(&s3.GetBucketWebsiteInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Sửa cấu hình

```
Client.PutBucketWebsite(&s3.PutBucketWebsiteInput{
        Bucket: aws.String("bucket-01"),
        WebsiteConfiguration: &s3.WebsiteConfiguration{
            IndexDocument: &s3.IndexDocument{
                Suffix: aws.String("<SUFFIX>"),
            },
        },
    })
```

> Xoá

```
// Working on it...
```

### Quản lý Bucket Lifecycle <a href="#qu-n-ly-bucket-lifecycle" id="qu-n-ly-bucket-lifecycle"></a>

Bucket Lifecycle là tính năng giúp người dùng thực hiện các thao tác như sau :

* Tự động xóa các file sau một khoảng thời gian nhất định (ví dụ là 3 ngày, 1 tuần ), có thể sử dụng tính năng này biến bucket thành backup
* Tự động di chuyển object tới một storage class khác, nhằm đưa object vào archive hay đưa tới những storage class nơi yêu cầu truy suất cao hơn
* Tự động Abort Incomplete MultiPart Upload (tự động hủy các multi-part upload mà chưa hoàn thành), giúp dọn dẹp các object upload bị lỗi trong quá trình upload
* Tự động xóa các object version mà không phải object version mới nhất (NoncurrentVersionExpiration) sau n ngày
* Với tât cả các tính năng trên, người dùng có thể sử dụng để làm giảm bớt dung lượng không cần thiết.

> Kiểm tra cấu hình hiện tại

```
Lifecycle, _ := Client.GetBucketLifecycle(&s3.GetBucketLifecycleInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Sửa cấu hình

```
Client.PutBucketLifecycleConfiguration(&s3.PutBucketLifecycleConfigurationInput{
        Bucket: aws.String("<BUCKET-NAME>"),
        LifecycleConfiguration: &s3.BucketLifecycleConfiguration{
            Rules: []*s3.LifecycleRule{
                {
                    ID:     aws.String("testid"),
                    Filter: &s3.LifecycleRuleFilter{
                        Prefix: aws.String("<PREFIX>")
                    },
                    Expiration: &s3.LifecycleExpiration{
                        Days: aws.Int64(<EXPIRATION-IN-DAYS>)
                    },
                    NoncurrentVersionExpiration: &s3.NoncurrentVersionExpiration{
                        NoncurrentDays: aws.Int64(<NONCURRENT-VERSION-EXPIRATION-IN-DAYS>),
                    },
                    AbortIncompleteMultipartUpload: &s3.AbortIncompleteMultipartUpload{
                        DaysAfterInitiation: aws.Int64(<DAYS-AFTER-INITIATION>),
                    },
                    Status: aws.String("<STATUS>")
                }
            }
        }
    })
```

**Tham số**

`<PREFIX>` tiền tố xác định một hoặc nhiều object được áp dụng, ví dụ: `test.txt` hoặc `thumuc/` hoặc `ScreenShots/ScreenShot2018-`.

`<STATUS>` Trạng thái của lifecycle, thuộc một trong hai giá trị: `Enabled` (Bật) hoặc `Disabled` (Tắt)

`<EXPIRATION-IN-DAYS>` số ngày object đó sẽ được đánh dấu là hết hạn tính theo ngày ví dụ 5 (5 ngày).

`<NONCURRENT-VERSION-EXPIRATION-IN-DAYS>` khi bật tính năng versioning, tham số này sẽ set cho các object không phải là mới nhất sẽ hết hạn sau bao nhiêu ngày.

`<DAYS-AFTER-INITIATION>` khi sử dụng chức năng multi-part upload, các part upload mà không complete sẽ bị xóa xóa sau bao nhiêu ngày.

**Lưu ý**

* Các config sau : Expiration, AbortIncompleteMultipartUpload, NoncurrentVersionExpiration không bắt buộc phải đi cùng nhau, một bucket có thể có 1 hoặc tất cả các config trên.
* Có thể có nhiều rule (> 1) cho một bucket
* Khi bucket có nhiều rule, nếu 1 rule trong đó có prefix là rỗng khi config bucket lifecycle sẽ bị lỗi 400 (bad request)

> Xoá cấu hình

```
Client.DeleteBucketLifecycle(&s3.DeleteBucketLifecycleInput{
        Bucket: aws.String("<BUCKET-NAME>"),
    })
```

### Quản lý Bucket Payer <a href="#qu-n-ly-bucket-payer" id="qu-n-ly-bucket-payer"></a>

Về cơ bản chủ sở hữu bucket sẽ trả tiền cho việc lưu trữ và transfer dữ liệu bucket đó. Tuy nhiên chủ sở hữu có thể cài đặt bucket trở thành **Requester Pays Bucket**, tức là để cho người truy cập bucket trả tiền cho các request và transfer dữ liệu do họ sử dụng, chủ sở hữu bucket sẽ chỉ trả tiền cho việc lưu trữ dữ liệu.

Thông thường, **Requester Pays Bucket** được sử dụng khi bạn muốn chia sẻ dữ liệu , người được chia sẻ dữ liệu sẽ trả phí cho tất cả những gì mà người đó dùng.

Ví dụ sử dụng tài tính năng này. - Có 2 loại tài khoản dành cho 2 mục đích khác nhau: - Loại tài khoản đầu tiên sử dụng để lưu toàn bộ các file - Loại tài khoản thứ 2 được sử dụng để thực hiện thao tác health check hoặc dọn dẹp tài nguyên mà không bị lẫn sang việc download hay upload của tài khoản chính - Khi thực hiện payment request các tài nguyên thống kê sẽ được tính vào người thực hiện request.

> Kiểm tra cấu hình hiện tại

```
Payment, _ := Client.GetBucketRequestPayment(&s3.GetBucketRequestPaymentInput{
        Bucket: aws.String("bucket-01"),
    })
```

> Set bucket trở thành **Requester Pays Bucket**

```
Client.PutBucketRequestPayment(&s3.PutBucketRequestPaymentInput{
        Bucket: aws.String("<BUCKET-NAME>"),
        RequestPaymentConfiguration: &s3.RequestPaymentConfiguration{
            Payer: aws.String("Requester"),
        },
    })
```

> Set bucket trở về mặc định **Owner Pays Bucket**

```
Client.PutBucketRequestPayment(&s3.PutBucketRequestPaymentInput{
        Bucket: aws.String("bucket-01"),
        RequestPaymentConfiguration: &s3.RequestPaymentConfiguration{
            Payer: aws.String("BucketOwner"),
        },
    })
```

## Quản lý object (file) <a href="#qu-n-ly-object-file" id="qu-n-ly-object-file"></a>

### Upload <a href="#upload" id="upload"></a>

Upload file lên bucket.

Trong quá trình upload người dùng thể thêm vào metadata, tag cho object.

```
sess := session.New(&s3Config)
Client := s3manager.NewUploader(sess)
file, _ := os.Open("/path/to/local-file")
Client.Upload(&s3manager.UploadInput{
    Bucket: aws.String("bucket-01"),
    Key:    aws.String(filepath.Base("/path/to/file")),
    Body:   file,
    ACL: "public-read"
})
```

### Multipart upload <a href="#multipart-upload" id="multipart-upload"></a>

Chức năng này giúp người dùng quản lý việc upload các file lớn. Các file lớn sẽ được upload lên theo từng part, sau khi tất cả các part đã được upload lên file đó sẽ được nối lại.

Size của 1 part tối thiểu là 5MB.

```
MAX_PART_SIZE := int64(512 * 1000)
MAX_RETRIES := 3
f, _ := os.Open("<PATH-TO-LOCAL-FILE>")
fileInfo, _ := f.Stat()

size := fileInfo.Size()
buffer := make([]byte, size)
fileType := http.DetectContentType(buffer)
f.Read(buffer)

input := &s3.CreateMultipartUploadInput{
    Bucket:      aws.String("bucket-01"),
    Key:         aws.String("<KEY-NAME>"),
    ContentType: aws.String(fileType),
}

resp, _ := Client.CreateMultipartUpload(input)

var curr, partLength int64
var remaining = size
var completedParts []*s3.CompletedPart
partNumber := 1
for curr = 0; remaining != 0; curr += partLength {
    if remaining < MAX_PART_SIZE {
        partLength = remaining
    } else {
        partLength = MAX_PART_SIZE
    }

    tryNum := 1
    partInput := &s3.UploadPartInput{
        Body:          bytes.NewReader(buffer[curr : curr+partLength]),
        Bucket:        resp.Bucket,
        Key:           resp.Key,
        PartNumber:    aws.Int64(int64(partNumber)),
        UploadId:      resp.UploadId,
        ContentLength: aws.Int64(int64(len(buffer[curr : curr+partLength]))),
    }

    for tryNum <= MAX_RETRIES {
        Client.UploadPart(partInput)

    }

    remaining -= partLength
    partNumber++
}
```

**Tham số**

`<PATH-TO-LOCAL-FILE>` là đường dẫn đến file cần upload

`<KEY-NAME>` là đường dẫn lưu file trong bucket

### Download <a href="#download" id="download"></a>

Download object từ bucket thành file.

```
var s3Download *s3manager.Downloader
    s := session.New(s3Config)
    s3Download = s3manager.NewDownloader(s)
    f, _ := os.Create("path/to/file.txt")
    s3Download.Download(f,
        &s3.GetObjectInput{
            Bucket: aws.String("bucket"),
            Key:    aws.String("/downloads/file.txt"),
        })
```

**Tham số**

`<PATH-TO-LOCAL-FILE>` là đường dẫn lưu file

`<KEY-NAME>` là đường dẫn đến file trong bucket

### Lấy thông tin một object theo đường dẫn <a href="#l-y-thong-tin-m-t-object-theo-d-ng-d-n" id="l-y-thong-tin-m-t-object-theo-d-ng-d-n"></a>

> Ví dụ lấy thông tin file `smile.png` tại thư mục `emoji`

Lấy các thông tin của object như: name, content-type, last\_modified ...

```
file, _ := Client.GetObject(&s3.GetObjectInput{
        Bucket: aws.String("bucket-01"),
        Key:    aws.String("emoji/smile.png"),
    })
```

### Danh sách phiên bản của một object <a href="#danh-sach-phien-b-n-c-a-m-t-object" id="danh-sach-phien-b-n-c-a-m-t-object"></a>

Khi bucket bật chức năng versioning, người dùng có thể list ra tất cả các version của object.

```
Versions, _ := Client.ListObjectVersions(&s3.ListObjectVersionsInput{
        Bucket: aws.String("bucket-01"),
        Prefix: aws.String("test/1.txt"),
    })
```

### Xoá <a href="#xoa" id="xoa"></a>

**1. Xoá file thông thường**

**2. Xoá một version của file**

Áp dụng trong trường hợp bucket versioning được bật

**3. Xoá file sử dụng xác thực nhiều bước (Multi-Factor Authentication)**

Sử dụng trong trường hợp tính năng MFA Authentication được cài đặt. Khi thực hiện xoá file, cần cung cấp một MFA token hợp lệ được sinh ra bởi trình quản lý MFA token đã được cài đặt trên thiết bị của bạn trước đó.

> Xoá file thông thường

```
Client.DeleteObject(&s3.DeleteObjectInput{
        Bucket: aws.String("<BUCKET-NAME>"),
        Key:    aws.String("path/to/file"),
    })
```

> Xoá một version của file

```
Client.DeleteObject(&s3.DeleteObjectInput{
        Bucket:    aws.String("bucket-01"),
        Key:       aws.String("path/to/file"),
        VersionId: aws.String("<VERSION-ID>"),
    })
```

> Xoá file sử dụng xác thực nhiều bước

```
Client.DeleteObject(&s3.DeleteObjectInput{
        Bucket:    aws.String("bucket-01"),
        Key:       aws.String("path/to/file"),
        MFA:aws.String("MFA-TOKEN"),
    })
```

**Tham số**

`<VERSION-ID>` là version\_id của object

`<MFA-TOKEN>` là multi-factor token hợp lệ tại thời điểm xoá

### Sao chép <a href="#sao-chep" id="sao-chep"></a>

```
Client.CopyObject(&s3.CopyObjectInput{
        Bucket:     aws.String("<DST_OBJECT>"),
        CopySource: aws.String("<SRC_BUCKET>"),
        Key:        aws.String("<SRC_OBJECT>"),
    })
```

**Tham số**

`<DST_BUCKET>` là bucket đích muốn copy tới, bạn có thể copy file tới bucket khác hoặc cùng một bucket

`<DST_OBJECT>` là đường dẫn file đích muốn copy tới

`<SRC_OBJECT>` là đường dẫn file nguồn

`<SRC_BUCKET>` là tên bucket nguồn

giá trị `preserve_acl` là `True` để chỉ định file đích có ACL giống với file nguồn.

### Quản lý object ACL <a href="#qu-n-ly-object-acl" id="qu-n-ly-object-acl"></a>

> Get

```
acl, _ := Client.GetObjectAcl(&s3.GetObjectAclInput{
        Bucket: aws.String("bucket-01"),
        Key:    aws.String("key"),
    })
```

> Set

```
sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
        Config:            *s3Config,
    }))

    svc := s3.New(sess)
    acl, _ := svc.GetObjectAcl(&s3.GetObjectAclInput{
        Bucket: aws.String("bucket-01"),
        Key:    aws.String("key"),
    })

    userType := "AmazonCustomerByEmail"
    owner := *acl.Owner.DisplayName
    ownerId := *acl.Owner.ID
    grants := acl.Grants
    var newGrantee = s3.Grantee{EmailAddress: aws.String("email"), Type: &userType}
    var newGrant = s3.Grant{Grantee: &newGrantee, Permission: aws.String("<CANNED_ACL>")}

    grants = append(grants, &newGrant)
    params := &s3.PutObjectAclInput{
        Bucket: aws.String("bucket-01"),
        Key:    aws.String("key"),
        AccessControlPolicy: &s3.AccessControlPolicy{
            Grants: grants,
            Owner: &s3.Owner{
                DisplayName: &owner,
                ID:          &ownerId,
            },
        },
    }

    svc.PutObjectAcl(params)
```

**Tham số**

`<CANNED_ACL>` thuộc một trong các giá trị sau:

`private` Chủ sở hữu có toàn quyền (FULL\_CONTROL), không ai khác có quyền truy cập (mặc định)

`public-read` Chủ sở hữu có toàn quyền (FULL\_CONTROL), Tất cả người dùng khác có quyền đọc (READ)

`public-read-write` Chủ sở hữu có toàn quyền (FULL\_CONTROL), Tất cả người dùng khác có quyền đọc (READ) và ghi (WRITE)

`authenticated-read` Chủ sở hữu có toàn quyền (FULL\_CONTROL), Tất cả người dùng đăng nhập khác có quyền đọc (READ)

### Tagging <a href="#tagging" id="tagging"></a>

Với tagging, người dùng có thể sủ dụng gán các tag (thẻ) cho object. Khi cần có thể lọc, tìm kiếm, phần quyền dựa theo tag.

> Get tags hiện có

```
// Working on it...
```

> Đặt tags

```
// Working on it...
```

### Chia sẻ <a href="#chia-s" id="chia-s"></a>

Ví dụ tạo link chia sẻ file emoji/smile.png có hiệu lực trong 1 giờ (3600 giây)

```
req, _ := Client.GetObjectRequest(&s3.GetObjectInput{
        Bucket: aws.String("bucket-01"),
        Key:    aws.String("file"),
    })
    url, _ := req.Presign(60 * time.Minute)
```

### Tạo link file để client upload file <a href="#t-o-link-file-d-client-upload-file" id="t-o-link-file-d-client-upload-file"></a>

Người dùng sử dụng tính năng này để generate ra url trên server, sau đó client sử dụng link để thực hiện tao thác upload object lên SimpleStorage.

Khi đã có được link tạo ra từ server, các client có thể sử dụng thư viện hoặc câu lệnh để thực hiện việc upload. Ví dụ dưới đây sử dụng câu lệnh curl trên linux.

Với link không có metadata thì sử dụng lệnh duới đây

```
curl --request PUT --upload-file <đường dẫn đến file> "<url>"
```

Với link có metadata thì cần thêm header để đẩy thêm header lên server.

```
curl --request PUT --upload-file 1.jpg  -H 'Content-Type:image/jpeg' -H 'x-amz-acl:public-read' "<url>"
```

***

**Chú ý**

Khi sử dụng tính năng này, cần chú ý khi sử dụng presigned-url, số lượng header được sinh ra ở trong câu lệnh presigned-url sẽ phải có tương ứng với cả lượng header khi sử dựng các client để upload file lên server.

Ví dụ ở dưới khi gen code server, có 2 header là Content-Type và x-amz-acl thì khi sử dụng các client, ví dụ như ở trên là sử dụng lệnh curl thì cũng phải có 2 header đó là Content-Type và x-amz-acl.

Nếu không có header tương ứng giữa presigned-url và client khi upload lên sẽ có thể xảy ra 1 trong 2 trường hợp sau:

1. Sinh ra lỗi 400 bad request khi sử dụng 1 các tool client như curl
2. Sinh ra lỗi báo CORS ở trình duyệt đến domain s3.xorcloud.net khi sử dụng các sdk như javascript, nodejs

***

```
Working on it.
```

### Object Lock <a href="#object-lock" id="object-lock"></a>

* Đây là tính năng giúp bảo vệ dữ liệu trên hệ thống Simple Storage, tính năng này sẽ chống lại việc xóa dữ liệu. Kể cả trong trường hợp cố tình hay vô ý.
* Simple Storage cung cấp 2 cách để quản lý thời gian khóa Object
  * Retention period : là việc tạm thời khóa dữ liệu trong 1 khoảng thời gian chỉ định, khi qua khoảng thời gian này thì object sẽ có thể được xóa. Khoảng thời gian này có thể theo số lượng ngày hoặc năm
  * Legal hold : là việc khóa dữ liệu giống với retention period chỉ khác là không có giới hạn thời gian, trừ khi là muốn tự tay xóa retention
* Simple Storage cung cấp 2 mode để thực hiện object Lock trong Retention period
  * Governance : ở mode này có thể bảo vệ dữ liệu khỏi phần lớn người sử dụng khỏi việc xóa dữ liệu, tuy nhiên vẫn sẽ có một số người sử dụng với đặc quyền có thể xóa với việc cho phép người có quyền s3:BypassGovernanceRetention
  * Compliance : mở mode này không một ai có thể xóa được dữ liệu trong khoảng thời gian được chỉ định, kể cả với user có quyền cao nhất
* Điều kiện để sử dụng tính năng
  * Phải enable tính năng bucket versioning
  * Phải enable tính năng Object Lock khi tạo bucket , các bucket đã tạo rồi không thể enable tính năng này nữa
