~netlandish/gobwebs

c7bf12be0312c91467ced6a3562da9e7b2041093 — Peter Sanchez 13 days ago 9805490 v0.1.0
Adding `ReadSizer` interface for use in the storage module.

This will allow backends to stream data versus copying the entire blob
into memory just to get the size of the data.

Adjusted the s3 storage backend to check for ReadSizer and use it if
present.
2 files changed, 45 insertions(+), 7 deletions(-)

M storage/s3.go
M storage/storage.go
M storage/s3.go => storage/s3.go +20 -7
@@ 132,22 132,35 @@ func (s *S3Service) GetObject(ctx context.Context, path string) (*Object, error)

// PutObject uploads an object to Amazon S3 compat bucket, at prefix
func (s *S3Service) PutObject(ctx context.Context, path string, content io.Reader) error {
	var data bytes.Buffer
	var (
		data io.Reader
		size int64
	)
	fullpath := pathutil.Join(s.Prefix, path)
	meta := make(map[string]string)
	if s.perm != "" {
		meta["x-amz-acl"] = s.perm
	}
	_, err := io.Copy(&data, content)
	if err != nil {
		return err

	if sizer, ok := content.(ReadSizer); ok {
		size = sizer.Size()
		data = content
	} else {
		var bufData bytes.Buffer
		_, err := io.Copy(&bufData, content)
		if err != nil {
			return err
		}
		data = &bufData
		size = int64(bufData.Len())
	}
	_, err = s.Client.PutObject(

	_, err := s.Client.PutObject(
		ctx,
		s.Bucket,
		fullpath,
		&data,
		int64(data.Len()),
		data,
		size,
		minio.PutObjectOptions{UserMetadata: meta, ContentType: guessMimeType(path)},
	)
	return err

M storage/storage.go => storage/storage.go +25 -0
@@ 21,6 21,12 @@ type (
		LastModified time.Time
	}

	// ObjectWrap is a simple type to implement the ReadSizer interface
	ObjectWrap struct {
		file io.Reader
		size int64
	}

	// Service is a generic interface for storage backends
	Service interface {
		ListObjects(ctx context.Context, prefix string) ([]*Object, error)


@@ 28,6 34,13 @@ type (
		PutObject(ctx context.Context, path string, content io.Reader) error
		DeleteObject(ctx context.Context, path string) error
	}

	// ReadSizer is just a helper interface to determine content length, mainly for
	// PutObject method of the Service interface
	ReadSizer interface {
		Read(p []byte) (n int, err error)
		Size() int64
	}
)

// HasExtension determines whether or not an object contains a file extension


@@ 69,3 82,15 @@ func guessMimeType(fname string) string {
	}
	return ctype
}

func (o *ObjectWrap) Read(b []byte) (n int, err error) {
	return o.file.Read(b)
}

func (o *ObjectWrap) Size() int64 {
	return o.size
}

func NewObjectWrap(content io.Reader, size int64) *ObjectWrap {
	return &ObjectWrap{content, size}
}

Do not follow this link