Skip to content

Commit

Permalink
Refactor PutObject API calls to add context and additional metadata.
Browse files Browse the repository at this point in the history
Add additional Api calls PutObjectWithContext, GetObjectWithContext,
FPutObjectWithContext and FGetObjectWithContext to allow request cancellation.

Remove PutObjectWithSize,PutObjectStreaming,PutEncryptedObject,PutObjectWithMetadata
calls and fold into a single PutObject call which accepts a pointer to PutObjectOptions
struct. PutObjectOptions struct allows user to enter custom metadata, Content-Encoding,
Cache-Control, Content-Type and Content-Disposition headers, configure number of threads
for multipart PutObject calls, and set Encryption materials module to encrypt data.

Pass pointer to PutObjectOptions struct as argument to FPutObject call.
  • Loading branch information
poornas committed Sep 5, 2017
1 parent 84539d7 commit 322f364
Show file tree
Hide file tree
Showing 38 changed files with 1,512 additions and 316 deletions.
10 changes: 8 additions & 2 deletions README.md
Expand Up @@ -152,10 +152,13 @@ The full API Reference is available here.
### API Reference : File Object Operations
* [`FPutObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject)
* [`FGetObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject)
* [`FPutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FPutObjectWithContext)
* [`FGetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FGetObjectWithContext)
### API Reference : Object Operations
* [`GetObject`](https://docs.minio.io/docs/golang-client-api-reference#GetObject)
* [`PutObject`](https://docs.minio.io/docs/golang-client-api-reference#PutObject)
* [`GetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#GetObjectWithContext)
* [`PutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectWithContext)
* [`PutObjectStreaming`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectStreaming)
* [`StatObject`](https://docs.minio.io/docs/golang-client-api-reference#StatObject)
* [`CopyObject`](https://docs.minio.io/docs/golang-client-api-reference#CopyObject)
Expand Down Expand Up @@ -204,10 +207,13 @@ The full API Reference is available here.
### Full Examples : File Object Operations
* [fputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject.go)
* [fgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject.go)
* [fputobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject-context.go)
* [fgetobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject-context.go)
### Full Examples : Object Operations
* [putobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject.go)
* [getobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject.go)
* [putobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject-context.go)
* [getobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject-context.go)
* [statobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/statobject.go)
* [copyobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/copyobject.go)
* [removeobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobject.go)
Expand Down
15 changes: 8 additions & 7 deletions api-compose-object.go
Expand Up @@ -17,6 +17,7 @@
package minio

import (
"context"
"encoding/base64"
"fmt"
"net/http"
Expand Down Expand Up @@ -268,7 +269,7 @@ func (s *SourceInfo) getProps(c Client) (size int64, etag string, userMeta map[s
// uploadPartCopy - helper function to create a part in a multipart
// upload via an upload-part-copy request
// https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html
func (c Client) uploadPartCopy(bucket, object, uploadID string, partNumber int,
func (c Client) uploadPartCopy(ctx context.Context, bucket, object, uploadID string, partNumber int,
headers http.Header) (p CompletePart, err error) {

// Build query parameters
Expand All @@ -277,7 +278,7 @@ func (c Client) uploadPartCopy(bucket, object, uploadID string, partNumber int,
urlValues.Set("uploadId", uploadID)

// Send upload-part-copy request
resp, err := c.executeMethod("PUT", requestMetadata{
resp, err := c.executeMethod(ctx, "PUT", requestMetadata{
bucketName: bucket,
objectName: object,
customHeader: headers,
Expand Down Expand Up @@ -311,7 +312,7 @@ func (c Client) ComposeObject(dst DestinationInfo, srcs []SourceInfo) error {
if len(srcs) < 1 || len(srcs) > maxPartsCount {
return ErrInvalidArgument("There must be as least one and up to 10000 source objects.")
}

ctx := context.Background()
srcSizes := make([]int64, len(srcs))
var totalSize, size, totalParts int64
var srcUserMeta map[string]string
Expand Down Expand Up @@ -396,7 +397,7 @@ func (c Client) ComposeObject(dst DestinationInfo, srcs []SourceInfo) error {
}

// Send copy request
resp, err := c.executeMethod("PUT", requestMetadata{
resp, err := c.executeMethod(ctx, "PUT", requestMetadata{
bucketName: dst.bucket,
objectName: dst.object,
customHeader: h,
Expand Down Expand Up @@ -430,7 +431,7 @@ func (c Client) ComposeObject(dst DestinationInfo, srcs []SourceInfo) error {
for k, v := range metaMap {
metaHeaders[k] = append(metaHeaders[k], v)
}
uploadID, err := c.newUploadID(dst.bucket, dst.object, metaHeaders)
uploadID, err := c.newUploadID(ctx, dst.bucket, dst.object, metaHeaders)
if err != nil {
return fmt.Errorf("Error creating new upload: %v", err)
}
Expand All @@ -457,7 +458,7 @@ func (c Client) ComposeObject(dst DestinationInfo, srcs []SourceInfo) error {
fmt.Sprintf("bytes=%d-%d", start, end))

// make upload-part-copy request
complPart, err := c.uploadPartCopy(dst.bucket,
complPart, err := c.uploadPartCopy(ctx, dst.bucket,
dst.object, uploadID, partIndex, h)
if err != nil {
return fmt.Errorf("Error in upload-part-copy - %v", err)
Expand All @@ -468,7 +469,7 @@ func (c Client) ComposeObject(dst DestinationInfo, srcs []SourceInfo) error {
}

// 3. Make final complete-multipart request.
_, err = c.completeMultipartUpload(dst.bucket, dst.object, uploadID,
_, err = c.completeMultipartUpload(ctx, dst.bucket, dst.object, uploadID,
completeMultipartUpload{Parts: objParts})
if err != nil {
err = fmt.Errorf("Error in complete-multipart request - %v", err)
Expand Down
24 changes: 24 additions & 0 deletions api-get-object-context.go
@@ -0,0 +1,24 @@
/*
* Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2017 Minio, 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.
*/

package minio

import "context"

// GetObjectWithContext - returns an seekable, readable object.
func (c Client) GetObjectWithContext(ctx context.Context, bucketName, objectName string) (*Object, error) {
return c.getObjectWithContext(ctx, bucketName, objectName)
}
24 changes: 24 additions & 0 deletions api-get-object-file-context.go
@@ -0,0 +1,24 @@
/*
* Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2017 Minio, 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.
*/

package minio

import "context"

// FGetObjectWithContext - download contents of an object to a local file.
func (c Client) FGetObjectWithContext(ctx context.Context, bucketName, objectName, filePath string) error {
return c.fGetObjectWithContext(ctx, bucketName, objectName, filePath)
}
9 changes: 8 additions & 1 deletion api-get-object-file.go
Expand Up @@ -21,11 +21,18 @@ import (
"os"
"path/filepath"

"context"

"github.com/minio/minio-go/pkg/s3utils"
)

// FGetObject - download contents of an object to a local file.
func (c Client) FGetObject(bucketName, objectName, filePath string) error {
return c.fGetObjectWithContext(context.Background(), bucketName, objectName, filePath)
}

// fGetObjectWithContext - fgetObject wrapper function with context
func (c Client) fGetObjectWithContext(ctx context.Context, bucketName, objectName, filePath string) error {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
Expand Down Expand Up @@ -88,7 +95,7 @@ func (c Client) FGetObject(bucketName, objectName, filePath string) error {
}

// Seek to current position for incoming reader.
objectReader, objectStat, err := c.getObject(bucketName, objectName, reqHeaders)
objectReader, objectStat, err := c.getObject(ctx, bucketName, objectName, reqHeaders)
if err != nil {
return err
}
Expand Down
18 changes: 12 additions & 6 deletions api-get-object.go
Expand Up @@ -17,6 +17,7 @@
package minio

import (
"context"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -57,6 +58,11 @@ func (c Client) GetEncryptedObject(bucketName, objectName string, encryptMateria

// GetObject - returns an seekable, readable object.
func (c Client) GetObject(bucketName, objectName string) (*Object, error) {
return c.getObjectWithContext(context.Background(), bucketName, objectName)
}

// GetObject wrapper function that accepts a request context
func (c Client) getObjectWithContext(ctx context.Context, bucketName, objectName string) (*Object, error) {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return nil, err
Expand Down Expand Up @@ -110,14 +116,14 @@ func (c Client) GetObject(bucketName, objectName string) (*Object, error) {
// Do not set objectInfo from the first readAt request because it will not get
// the whole object.
reqHeaders.SetRange(req.Offset, req.Offset+int64(len(req.Buffer))-1)
httpReader, objectInfo, err = c.getObject(bucketName, objectName, reqHeaders)
httpReader, objectInfo, err = c.getObject(ctx, bucketName, objectName, reqHeaders)
} else {
if req.Offset > 0 {
reqHeaders.SetRange(req.Offset, 0)
}

// First request is a Read request.
httpReader, objectInfo, err = c.getObject(bucketName, objectName, reqHeaders)
httpReader, objectInfo, err = c.getObject(ctx, bucketName, objectName, reqHeaders)
}
if err != nil {
resCh <- getResponse{
Expand Down Expand Up @@ -195,14 +201,14 @@ func (c Client) GetObject(bucketName, objectName string) (*Object, error) {
if req.isReadAt {
// Range is set with respect to the offset and length of the buffer requested.
reqHeaders.SetRange(req.Offset, req.Offset+int64(len(req.Buffer))-1)
httpReader, _, err = c.getObject(bucketName, objectName, reqHeaders)
httpReader, _, err = c.getObject(ctx, bucketName, objectName, reqHeaders)
} else {
// Range is set with respect to the offset.
if req.Offset > 0 {
reqHeaders.SetRange(req.Offset, 0)
}

httpReader, objectInfo, err = c.getObject(bucketName, objectName, reqHeaders)
httpReader, objectInfo, err = c.getObject(ctx, bucketName, objectName, reqHeaders)
}
if err != nil {
resCh <- getResponse{
Expand Down Expand Up @@ -626,7 +632,7 @@ func newObject(reqCh chan<- getRequest, resCh <-chan getResponse, doneCh chan<-
//
// For more information about the HTTP Range header.
// go to http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.
func (c Client) getObject(bucketName, objectName string, reqHeaders RequestHeaders) (io.ReadCloser, ObjectInfo, error) {
func (c Client) getObject(ctx context.Context, bucketName, objectName string, reqHeaders RequestHeaders) (io.ReadCloser, ObjectInfo, error) {
// Validate input arguments.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return nil, ObjectInfo{}, err
Expand All @@ -642,7 +648,7 @@ func (c Client) getObject(bucketName, objectName string, reqHeaders RequestHeade
}

// Execute GET on objectName.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(ctx, "GET", requestMetadata{
bucketName: bucketName,
objectName: objectName,
customHeader: customHeader,
Expand Down
3 changes: 2 additions & 1 deletion api-get-policy.go
Expand Up @@ -17,6 +17,7 @@
package minio

import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
Expand Down Expand Up @@ -79,7 +80,7 @@ func (c Client) getBucketPolicy(bucketName string) (policy.BucketAccessPolicy, e
urlValues.Set("policy", "")

// Execute GET on bucket to list objects.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down
11 changes: 6 additions & 5 deletions api-list.go
Expand Up @@ -17,6 +17,7 @@
package minio

import (
"context"
"errors"
"fmt"
"net/http"
Expand All @@ -38,7 +39,7 @@ import (
//
func (c Client) ListBuckets() ([]BucketInfo, error) {
// Execute GET on service.
resp, err := c.executeMethod("GET", requestMetadata{contentSHA256Bytes: emptySHA256})
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{contentSHA256Bytes: emptySHA256})
defer closeResponse(resp)
if err != nil {
return nil, err
Expand Down Expand Up @@ -215,7 +216,7 @@ func (c Client) listObjectsV2Query(bucketName, objectPrefix, continuationToken s
urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))

// Execute GET on bucket to list objects.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down Expand Up @@ -393,7 +394,7 @@ func (c Client) listObjectsQuery(bucketName, objectPrefix, objectMarker, delimit
urlValues.Set("max-keys", fmt.Sprintf("%d", maxkeys))

// Execute GET on bucket to list objects.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down Expand Up @@ -572,7 +573,7 @@ func (c Client) listMultipartUploadsQuery(bucketName, keyMarker, uploadIDMarker,
urlValues.Set("max-uploads", fmt.Sprintf("%d", maxUploads))

// Execute GET on bucketName to list multipart uploads.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down Expand Up @@ -690,7 +691,7 @@ func (c Client) listObjectPartsQuery(bucketName, objectName, uploadID string, pa
urlValues.Set("max-parts", fmt.Sprintf("%d", maxParts))

// Execute GET on objectName to get list of parts.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
Expand Down
5 changes: 3 additions & 2 deletions api-notification.go
Expand Up @@ -18,6 +18,7 @@ package minio

import (
"bufio"
"context"
"encoding/json"
"io"
"net/http"
Expand Down Expand Up @@ -46,7 +47,7 @@ func (c Client) getBucketNotification(bucketName string) (BucketNotification, er
urlValues.Set("notification", "")

// Execute GET on bucket to list objects.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down Expand Up @@ -170,7 +171,7 @@ func (c Client) ListenBucketNotification(bucketName, prefix, suffix string, even
urlValues["events"] = events

// Execute GET on bucket to list objects.
resp, err := c.executeMethod("GET", requestMetadata{
resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down
9 changes: 5 additions & 4 deletions api-put-bucket.go
Expand Up @@ -19,6 +19,7 @@ package minio

import (
"bytes"
"context"
"encoding/json"
"encoding/xml"
"fmt"
Expand Down Expand Up @@ -82,7 +83,7 @@ func (c Client) MakeBucket(bucketName string, location string) (err error) {
}

// Execute PUT to create a new bucket.
resp, err := c.executeMethod("PUT", reqMetadata)
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
Expand Down Expand Up @@ -170,7 +171,7 @@ func (c Client) putBucketPolicy(bucketName string, policyInfo policy.BucketAcces
}

// Execute PUT to upload a new bucket policy.
resp, err := c.executeMethod("PUT", reqMetadata)
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
Expand All @@ -195,7 +196,7 @@ func (c Client) removeBucketPolicy(bucketName string) error {
urlValues.Set("policy", "")

// Execute DELETE on objectName.
resp, err := c.executeMethod("DELETE", requestMetadata{
resp, err := c.executeMethod(context.Background(), "DELETE", requestMetadata{
bucketName: bucketName,
queryValues: urlValues,
contentSHA256Bytes: emptySHA256,
Expand Down Expand Up @@ -235,7 +236,7 @@ func (c Client) SetBucketNotification(bucketName string, bucketNotification Buck
}

// Execute PUT to upload a new bucket notification.
resp, err := c.executeMethod("PUT", reqMetadata)
resp, err := c.executeMethod(context.Background(), "PUT", reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
Expand Down

0 comments on commit 322f364

Please sign in to comment.