blob: f7ee75c36f07361a9eb478f37aa75f41a65bca92 [file] [log] [blame]
Jon Perritt8c93a302014-09-28 22:35:57 -05001package objects
2
3import (
4 "fmt"
Jamie Hannaford2e784862014-10-27 10:40:27 +01005 "io"
6 "io/ioutil"
Jon Perritt8c93a302014-09-28 22:35:57 -05007 "strings"
8
Ash Wilsonaf262872014-10-20 09:32:29 -04009 "github.com/rackspace/gophercloud"
Jon Perritt8c93a302014-09-28 22:35:57 -050010 "github.com/rackspace/gophercloud/pagination"
Jon Perrittea4e3012014-10-09 22:03:19 -050011
12 "github.com/mitchellh/mapstructure"
Jon Perritt8c93a302014-09-28 22:35:57 -050013)
14
15// Object is a structure that holds information related to a storage object.
Jon Perritt8aa40262014-09-29 15:41:32 -050016type Object struct {
Jon Perrittf3171c12014-09-30 17:39:31 -050017 Bytes int `json:"bytes" mapstructure:"bytes"`
18 ContentType string `json:"content_type" mapstructure:"content_type"`
19 Hash string `json:"hash" mapstructure:"hash"`
20 LastModified string `json:"last_modified" mapstructure:"last_modified"`
21 Name string `json:"name" mapstructure:"name"`
Jon Perritt8aa40262014-09-29 15:41:32 -050022}
Jon Perritt8c93a302014-09-28 22:35:57 -050023
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +020024// ObjectPage is a single page of objects that is returned from a call to the
25// List function.
Jon Perritt8c93a302014-09-28 22:35:57 -050026type ObjectPage struct {
27 pagination.MarkerPageBase
28}
29
30// IsEmpty returns true if a ListResult contains no object names.
31func (r ObjectPage) IsEmpty() (bool, error) {
32 names, err := ExtractNames(r)
33 if err != nil {
34 return true, err
35 }
36 return len(names) == 0, nil
37}
38
39// LastMarker returns the last object name in a ListResult.
40func (r ObjectPage) LastMarker() (string, error) {
41 names, err := ExtractNames(r)
42 if err != nil {
43 return "", err
44 }
45 if len(names) == 0 {
46 return "", nil
47 }
48 return names[len(names)-1], nil
49}
50
Jon Perritt8c93a302014-09-28 22:35:57 -050051// ExtractInfo is a function that takes a page of objects and returns their full information.
52func ExtractInfo(page pagination.Page) ([]Object, error) {
53 untyped := page.(ObjectPage).Body.([]interface{})
54 results := make([]Object, len(untyped))
55 for index, each := range untyped {
Jon Perritt8aa40262014-09-29 15:41:32 -050056 object := each.(map[string]interface{})
Jon Perrittfdac6e52014-09-29 19:43:45 -050057 err := mapstructure.Decode(object, &results[index])
Jon Perritt8aa40262014-09-29 15:41:32 -050058 if err != nil {
59 return results, err
60 }
Jon Perritt8c93a302014-09-28 22:35:57 -050061 }
62 return results, nil
63}
64
65// ExtractNames is a function that takes a page of objects and returns only their names.
66func ExtractNames(page pagination.Page) ([]string, error) {
67 casted := page.(ObjectPage)
Ash Wilson72e4d2c2014-10-20 10:27:30 -040068 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050069 switch {
70 case strings.HasPrefix(ct, "application/json"):
71 parsed, err := ExtractInfo(page)
72 if err != nil {
73 return nil, err
74 }
75
76 names := make([]string, 0, len(parsed))
77 for _, object := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050078 names = append(names, object.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050079 }
Jon Perrittfdac6e52014-09-29 19:43:45 -050080
Jon Perritt8c93a302014-09-28 22:35:57 -050081 return names, nil
82 case strings.HasPrefix(ct, "text/plain"):
83 names := make([]string, 0, 50)
84
85 body := string(page.(ObjectPage).Body.([]uint8))
86 for _, name := range strings.Split(body, "\n") {
87 if len(name) > 0 {
88 names = append(names, name)
89 }
90 }
91
92 return names, nil
Jon Perrittfdac6e52014-09-29 19:43:45 -050093 case strings.HasPrefix(ct, "text/html"):
94 return []string{}, nil
Jon Perritt8c93a302014-09-28 22:35:57 -050095 default:
96 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
97 }
98}
99
Jon Perritt2b36fa32014-10-24 15:44:23 -0500100type commonResult struct {
101 gophercloud.Result
102}
103
Jon Perritt5db08922014-09-30 21:32:48 -0500104// DownloadResult is a *http.Response that is returned from a call to the Download function.
105type DownloadResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500106 commonResult
Jamie Hannafordee115552014-10-27 16:11:05 +0100107 Body io.ReadCloser
Jon Perritt5db08922014-09-30 21:32:48 -0500108}
109
Jamie Hannaford2e784862014-10-27 10:40:27 +0100110// ExtractContent is a function that takes a DownloadResult's io.Reader body
111// and reads all available data into a slice of bytes. Please be aware that due
112// the nature of io.Reader is forward-only - meaning that it can only be read
113// once and not rewound. You can recreate a reader from the output of this
114// function by using bytes.NewReader(downloadBytes)
Jon Perritt8c93a302014-09-28 22:35:57 -0500115func (dr DownloadResult) ExtractContent() ([]byte, error) {
116 if dr.Err != nil {
Ash Wilsonaf262872014-10-20 09:32:29 -0400117 return nil, dr.Err
Jon Perritt8c93a302014-09-28 22:35:57 -0500118 }
Jamie Hannaford2e784862014-10-27 10:40:27 +0100119 body, err := ioutil.ReadAll(dr.Body)
120 if err != nil {
121 return nil, err
122 }
Jamie Hannafordee115552014-10-27 16:11:05 +0100123 dr.Body.Close()
Jamie Hannaford2e784862014-10-27 10:40:27 +0100124 return body, nil
Jon Perritt8c93a302014-09-28 22:35:57 -0500125}
126
Jon Perritt5db08922014-09-30 21:32:48 -0500127// GetResult is a *http.Response that is returned from a call to the Get function.
128type GetResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500129 commonResult
Jon Perritt5db08922014-09-30 21:32:48 -0500130}
131
Jon Perritt8c93a302014-09-28 22:35:57 -0500132// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
133// and returns the custom metadata associated with the object.
134func (gr GetResult) ExtractMetadata() (map[string]string, error) {
135 if gr.Err != nil {
136 return nil, gr.Err
137 }
138 metadata := make(map[string]string)
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400139 for k, v := range gr.Header {
Jon Perritt8c93a302014-09-28 22:35:57 -0500140 if strings.HasPrefix(k, "X-Object-Meta-") {
141 key := strings.TrimPrefix(k, "X-Object-Meta-")
142 metadata[key] = v[0]
143 }
144 }
145 return metadata, nil
146}
Jon Perritt5db08922014-09-30 21:32:48 -0500147
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200148// CreateResult represents the result of a create operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500149type CreateResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500150 commonResult
Jon Perritt5db08922014-09-30 21:32:48 -0500151}
152
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200153// UpdateResult represents the result of an update operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500154type UpdateResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500155 commonResult
Jon Perritt5db08922014-09-30 21:32:48 -0500156}
157
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200158// DeleteResult represents the result of a delete operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500159type DeleteResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500160 commonResult
Jon Perritt5db08922014-09-30 21:32:48 -0500161}
162
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200163// CopyResult represents the result of a copy operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500164type CopyResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500165 commonResult
Jon Perritt5db08922014-09-30 21:32:48 -0500166}