blob: aaeb040b5b5ebae8e097db38871f4419f5a309b4 [file] [log] [blame]
Jon Perritt8c93a302014-09-28 22:35:57 -05001package objects
2
3import (
4 "fmt"
5 "io/ioutil"
6 "net/http"
7 "strings"
8
Jon Perritt8aa40262014-09-29 15:41:32 -05009 "github.com/mitchellh/mapstructure"
Jon Perritt8c93a302014-09-28 22:35:57 -050010 "github.com/rackspace/gophercloud/pagination"
11)
12
13// Object is a structure that holds information related to a storage object.
Jon Perritt8aa40262014-09-29 15:41:32 -050014type Object struct {
Jon Perrittf3171c12014-09-30 17:39:31 -050015 Bytes int `json:"bytes" mapstructure:"bytes"`
16 ContentType string `json:"content_type" mapstructure:"content_type"`
17 Hash string `json:"hash" mapstructure:"hash"`
18 LastModified string `json:"last_modified" mapstructure:"last_modified"`
19 Name string `json:"name" mapstructure:"name"`
Jon Perritt8aa40262014-09-29 15:41:32 -050020}
Jon Perritt8c93a302014-09-28 22:35:57 -050021
22// ListResult is a single page of objects that is returned from a call to the List function.
23type ObjectPage struct {
24 pagination.MarkerPageBase
25}
26
27// IsEmpty returns true if a ListResult contains no object names.
28func (r ObjectPage) IsEmpty() (bool, error) {
29 names, err := ExtractNames(r)
30 if err != nil {
31 return true, err
32 }
33 return len(names) == 0, nil
34}
35
36// LastMarker returns the last object name in a ListResult.
37func (r ObjectPage) LastMarker() (string, error) {
38 names, err := ExtractNames(r)
39 if err != nil {
40 return "", err
41 }
42 if len(names) == 0 {
43 return "", nil
44 }
45 return names[len(names)-1], nil
46}
47
Jon Perritt8c93a302014-09-28 22:35:57 -050048// ExtractInfo is a function that takes a page of objects and returns their full information.
49func ExtractInfo(page pagination.Page) ([]Object, error) {
50 untyped := page.(ObjectPage).Body.([]interface{})
51 results := make([]Object, len(untyped))
52 for index, each := range untyped {
Jon Perritt8aa40262014-09-29 15:41:32 -050053 object := each.(map[string]interface{})
Jon Perrittfdac6e52014-09-29 19:43:45 -050054 err := mapstructure.Decode(object, &results[index])
Jon Perritt8aa40262014-09-29 15:41:32 -050055 if err != nil {
56 return results, err
57 }
Jon Perritt8c93a302014-09-28 22:35:57 -050058 }
59 return results, nil
60}
61
62// ExtractNames is a function that takes a page of objects and returns only their names.
63func ExtractNames(page pagination.Page) ([]string, error) {
64 casted := page.(ObjectPage)
65 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050066 switch {
67 case strings.HasPrefix(ct, "application/json"):
68 parsed, err := ExtractInfo(page)
69 if err != nil {
70 return nil, err
71 }
72
73 names := make([]string, 0, len(parsed))
74 for _, object := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050075 names = append(names, object.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050076 }
Jon Perrittfdac6e52014-09-29 19:43:45 -050077
Jon Perritt8c93a302014-09-28 22:35:57 -050078 return names, nil
79 case strings.HasPrefix(ct, "text/plain"):
80 names := make([]string, 0, 50)
81
82 body := string(page.(ObjectPage).Body.([]uint8))
83 for _, name := range strings.Split(body, "\n") {
84 if len(name) > 0 {
85 names = append(names, name)
86 }
87 }
88
89 return names, nil
Jon Perrittfdac6e52014-09-29 19:43:45 -050090 case strings.HasPrefix(ct, "text/html"):
91 return []string{}, nil
Jon Perritt8c93a302014-09-28 22:35:57 -050092 default:
93 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
94 }
95}
96
Jon Perritt5db08922014-09-30 21:32:48 -050097// DownloadResult is a *http.Response that is returned from a call to the Download function.
98type DownloadResult struct {
99 commonResult
100}
101
Jon Perritt8c93a302014-09-28 22:35:57 -0500102// ExtractContent is a function that takes a DownloadResult (of type *http.Response)
103// and returns the object's content.
104func (dr DownloadResult) ExtractContent() ([]byte, error) {
105 if dr.Err != nil {
106 return nil, nil
107 }
108 var body []byte
109 defer dr.Resp.Body.Close()
110 body, err := ioutil.ReadAll(dr.Resp.Body)
111 if err != nil {
112 return body, fmt.Errorf("Error trying to read DownloadResult body: %v", err)
113 }
114 return body, nil
115}
116
Jon Perritt5db08922014-09-30 21:32:48 -0500117// GetResult is a *http.Response that is returned from a call to the Get function.
118type GetResult struct {
119 commonResult
120}
121
Jon Perritt8c93a302014-09-28 22:35:57 -0500122// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
123// and returns the custom metadata associated with the object.
124func (gr GetResult) ExtractMetadata() (map[string]string, error) {
125 if gr.Err != nil {
126 return nil, gr.Err
127 }
128 metadata := make(map[string]string)
129 for k, v := range gr.Resp.Header {
130 if strings.HasPrefix(k, "X-Object-Meta-") {
131 key := strings.TrimPrefix(k, "X-Object-Meta-")
132 metadata[key] = v[0]
133 }
134 }
135 return metadata, nil
136}
Jon Perritt5db08922014-09-30 21:32:48 -0500137
138type commonResult struct {
139 Resp *http.Response
140 Err error
141}
142
143func (cr commonResult) ExtractHeaders() (http.Header, error) {
144 var headers http.Header
145 if cr.Err != nil {
146 return headers, cr.Err
147 }
148
149 return cr.Resp.Header, nil
150}
151
152type CreateResult struct {
153 commonResult
154}
155
156type UpdateResult struct {
157 commonResult
158}
159
160type DeleteResult struct {
161 commonResult
162}
163
164type CopyResult struct {
165 commonResult
166}