aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2018-02-19 15:03:56 +0100
committerStefan Majewsky <majewsky@gmx.net>2018-02-19 15:03:56 +0100
commit502acc3c73e789e856a17b878889db4356fe898c (patch)
treef3d48ed5d6dd950bc2c3c4a9e2a6cc670a7c8034
parent1a84987c7e28094f4e65bfb0fa03fdf5059ef6cc (diff)
downloadgo-schwift-502acc3c73e789e856a17b878889db4356fe898c.tar.gz
add Object.Download(), DownloadedObject
-rw-r--r--download.go83
-rw-r--r--object.go32
2 files changed, 114 insertions, 1 deletions
diff --git a/download.go b/download.go
new file mode 100644
index 0000000..6515bbf
--- /dev/null
+++ b/download.go
@@ -0,0 +1,83 @@
+/******************************************************************************
+*
+* Copyright 2018 Stefan Majewsky <majewsky@gmx.net>
+*
+* 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 schwift
+
+import (
+ "io"
+ "io/ioutil"
+)
+
+//DownloadedObject is returned by Object.Download(). It wraps the io.ReadCloser
+//from http.Response.Body with convenience methods for collecting the contents
+//into a byte slice or string.
+//
+// var obj *swift.Object
+//
+// //Do NOT do this!
+// reader, err := obj.Download(nil, nil).AsReadCloser()
+// bytes, err := ioutil.ReadAll(reader)
+// err := reader.Close()
+// str := string(bytes)
+//
+// //Do this instead:
+// str, err := obj.Download(nil, nil).AsString()
+//
+//Since the AsByteSlice and AsString method consume only the unread portion of
+//the ReadCloser, and since they drain the ReadCloser irreversibly, the
+//idiomatic way of using DownloadedObject is to call one of its members
+//immediately, without storing the DownloadedObject instance in a variable
+//first.
+//
+// var obj *swift.Object
+//
+// //Do NOT do this!
+// downloaded := obj.Download(nil, nil)
+// reader, err := downloaded.AsReadCloser()
+//
+// //Do this instead:
+// reader, err := obj.Download(nil, nil).AsReadCloser()
+type DownloadedObject struct {
+ r io.ReadCloser
+ err error
+}
+
+//AsReadCloser returns an io.ReadCloser containing the contents of the
+//downloaded object.
+func (o DownloadedObject) AsReadCloser() (io.ReadCloser, error) {
+ return o.r, o.err
+}
+
+//AsByteSlice collects the contents of this downloaded object into a byte slice.
+func (o DownloadedObject) AsByteSlice() ([]byte, error) {
+ if o.err != nil {
+ return nil, o.err
+ }
+ slice, err := ioutil.ReadAll(o.r)
+ closeErr := o.r.Close()
+ if err == nil {
+ err = closeErr
+ }
+ return slice, closeErr
+}
+
+//AsString collects the contents of this downloaded object into a string.
+func (o DownloadedObject) AsString() (string, error) {
+ slice, err := o.AsByteSlice()
+ return string(slice), err
+}
diff --git a/object.go b/object.go
index a2a68e1..83ada1d 100644
--- a/object.go
+++ b/object.go
@@ -262,5 +262,35 @@ func (o *Object) Invalidate() {
o.headers = nil
}
-//TODO Object.Copy(), Object.Move(), Object.Download()
+//Download retrieves the object's contents using a GET request. This returns a
+//helper object which allows you to select whether you want an io.ReadCloser
+//for reading the object contents progressively, or whether you want the object
+//contents collected into a byte slice or string.
+//
+// reader, err := object.Download(nil, nil).AsReadCloser()
+//
+// buf, err := object.Download(nil, nil).AsByteSlice()
+//
+// str, err := object.Download(nil, nil).AsString()
+//
+func (o *Object) Download(headers ObjectHeaders, opts *RequestOptions) DownloadedObject {
+ resp, err := Request{
+ Method: "GET",
+ ContainerName: o.c.name,
+ ObjectName: o.name,
+ Headers: headersToHTTP(headers),
+ Options: opts,
+ ExpectStatusCodes: []int{200},
+ }.Do(o.c.a.client)
+ if err == nil {
+ headers := ObjectHeaders(headersFromHTTP(resp.Header))
+ err = headers.Validate()
+ if err == nil {
+ o.headers = &headers
+ }
+ }
+ return DownloadedObject{resp.Body, err}
+}
+
+//TODO Object.Copy(), Object.Move()
//TODO provide a companion to Object.Upload() to connect it with content-generating functions where an io.Writer needs to be given