blob: 7524c43c960f3ca6f0ba45347b174aabfe868900 [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 Perritt10a7ec12014-10-27 11:29:33 -05007 "net/http"
Jon Perritt8c93a302014-09-28 22:35:57 -05008 "strings"
9
Ash Wilsonaf262872014-10-20 09:32:29 -040010 "github.com/rackspace/gophercloud"
Jon Perritt8c93a302014-09-28 22:35:57 -050011 "github.com/rackspace/gophercloud/pagination"
Jon Perrittea4e3012014-10-09 22:03:19 -050012
13 "github.com/mitchellh/mapstructure"
Jon Perritt8c93a302014-09-28 22:35:57 -050014)
15
16// Object is a structure that holds information related to a storage object.
Jon Perritt8aa40262014-09-29 15:41:32 -050017type Object struct {
Jon Perrittf3171c12014-09-30 17:39:31 -050018 Bytes int `json:"bytes" mapstructure:"bytes"`
19 ContentType string `json:"content_type" mapstructure:"content_type"`
20 Hash string `json:"hash" mapstructure:"hash"`
21 LastModified string `json:"last_modified" mapstructure:"last_modified"`
22 Name string `json:"name" mapstructure:"name"`
Jon Perritt8aa40262014-09-29 15:41:32 -050023}
Jon Perritt8c93a302014-09-28 22:35:57 -050024
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +020025// ObjectPage is a single page of objects that is returned from a call to the
26// List function.
Jon Perritt8c93a302014-09-28 22:35:57 -050027type ObjectPage struct {
28 pagination.MarkerPageBase
29}
30
31// IsEmpty returns true if a ListResult contains no object names.
32func (r ObjectPage) IsEmpty() (bool, error) {
33 names, err := ExtractNames(r)
34 if err != nil {
35 return true, err
36 }
37 return len(names) == 0, nil
38}
39
40// LastMarker returns the last object name in a ListResult.
41func (r ObjectPage) LastMarker() (string, error) {
42 names, err := ExtractNames(r)
43 if err != nil {
44 return "", err
45 }
46 if len(names) == 0 {
47 return "", nil
48 }
49 return names[len(names)-1], nil
50}
51
Jon Perritt8c93a302014-09-28 22:35:57 -050052// ExtractInfo is a function that takes a page of objects and returns their full information.
53func ExtractInfo(page pagination.Page) ([]Object, error) {
54 untyped := page.(ObjectPage).Body.([]interface{})
55 results := make([]Object, len(untyped))
56 for index, each := range untyped {
Jon Perritt8aa40262014-09-29 15:41:32 -050057 object := each.(map[string]interface{})
Jon Perrittfdac6e52014-09-29 19:43:45 -050058 err := mapstructure.Decode(object, &results[index])
Jon Perritt8aa40262014-09-29 15:41:32 -050059 if err != nil {
60 return results, err
61 }
Jon Perritt8c93a302014-09-28 22:35:57 -050062 }
63 return results, nil
64}
65
66// ExtractNames is a function that takes a page of objects and returns only their names.
67func ExtractNames(page pagination.Page) ([]string, error) {
68 casted := page.(ObjectPage)
Ash Wilson72e4d2c2014-10-20 10:27:30 -040069 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050070 switch {
71 case strings.HasPrefix(ct, "application/json"):
72 parsed, err := ExtractInfo(page)
73 if err != nil {
74 return nil, err
75 }
76
77 names := make([]string, 0, len(parsed))
78 for _, object := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050079 names = append(names, object.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050080 }
Jon Perrittfdac6e52014-09-29 19:43:45 -050081
Jon Perritt8c93a302014-09-28 22:35:57 -050082 return names, nil
83 case strings.HasPrefix(ct, "text/plain"):
84 names := make([]string, 0, 50)
85
86 body := string(page.(ObjectPage).Body.([]uint8))
87 for _, name := range strings.Split(body, "\n") {
88 if len(name) > 0 {
89 names = append(names, name)
90 }
91 }
92
93 return names, nil
Jon Perrittfdac6e52014-09-29 19:43:45 -050094 case strings.HasPrefix(ct, "text/html"):
95 return []string{}, nil
Jon Perritt8c93a302014-09-28 22:35:57 -050096 default:
97 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
98 }
99}
100
Jon Perritt10a7ec12014-10-27 11:29:33 -0500101type headerResult struct {
Jon Perritt2b36fa32014-10-24 15:44:23 -0500102 gophercloud.Result
103}
104
Jon Perritt10a7ec12014-10-27 11:29:33 -0500105func (hr headerResult) ExtractHeader() (http.Header, error) {
106 return hr.Header, hr.Err
107}
108
Jon Perritt5db08922014-09-30 21:32:48 -0500109// DownloadResult is a *http.Response that is returned from a call to the Download function.
110type DownloadResult struct {
Jon Perritt10a7ec12014-10-27 11:29:33 -0500111 headerResult
Jamie Hannaford2e784862014-10-27 10:40:27 +0100112 Body io.Reader
Jon Perritt5db08922014-09-30 21:32:48 -0500113}
114
Jamie Hannaford2e784862014-10-27 10:40:27 +0100115// ExtractContent is a function that takes a DownloadResult's io.Reader body
116// and reads all available data into a slice of bytes. Please be aware that due
117// the nature of io.Reader is forward-only - meaning that it can only be read
118// once and not rewound. You can recreate a reader from the output of this
119// function by using bytes.NewReader(downloadBytes)
Jon Perritt8c93a302014-09-28 22:35:57 -0500120func (dr DownloadResult) ExtractContent() ([]byte, error) {
121 if dr.Err != nil {
Ash Wilsonaf262872014-10-20 09:32:29 -0400122 return nil, dr.Err
Jon Perritt8c93a302014-09-28 22:35:57 -0500123 }
Jamie Hannaford2e784862014-10-27 10:40:27 +0100124 body, err := ioutil.ReadAll(dr.Body)
125 if err != nil {
126 return nil, err
127 }
128 return body, nil
Jon Perritt8c93a302014-09-28 22:35:57 -0500129}
130
Jon Perritt5db08922014-09-30 21:32:48 -0500131// GetResult is a *http.Response that is returned from a call to the Get function.
132type GetResult struct {
Jon Perritt10a7ec12014-10-27 11:29:33 -0500133 headerResult
Jon Perritt5db08922014-09-30 21:32:48 -0500134}
135
Jon Perritt8c93a302014-09-28 22:35:57 -0500136// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
137// and returns the custom metadata associated with the object.
138func (gr GetResult) ExtractMetadata() (map[string]string, error) {
139 if gr.Err != nil {
140 return nil, gr.Err
141 }
142 metadata := make(map[string]string)
Ash Wilson72e4d2c2014-10-20 10:27:30 -0400143 for k, v := range gr.Header {
Jon Perritt8c93a302014-09-28 22:35:57 -0500144 if strings.HasPrefix(k, "X-Object-Meta-") {
145 key := strings.TrimPrefix(k, "X-Object-Meta-")
146 metadata[key] = v[0]
147 }
148 }
149 return metadata, nil
150}
Jon Perritt5db08922014-09-30 21:32:48 -0500151
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200152// CreateResult represents the result of a create operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500153type CreateResult struct {
Jon Perritt10a7ec12014-10-27 11:29:33 -0500154 headerResult
Jon Perritt5db08922014-09-30 21:32:48 -0500155}
156
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200157// UpdateResult represents the result of an update operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500158type UpdateResult struct {
Jon Perritt10a7ec12014-10-27 11:29:33 -0500159 headerResult
Jon Perritt5db08922014-09-30 21:32:48 -0500160}
161
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200162// DeleteResult represents the result of a delete operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500163type DeleteResult struct {
Jon Perritt10a7ec12014-10-27 11:29:33 -0500164 headerResult
Jon Perritt5db08922014-09-30 21:32:48 -0500165}
166
Jamie Hannafordc9cdc8f2014-10-06 16:32:56 +0200167// CopyResult represents the result of a copy operation.
Jon Perritt5db08922014-09-30 21:32:48 -0500168type CopyResult struct {
Jon Perritt10a7ec12014-10-27 11:29:33 -0500169 headerResult
Jon Perritt5db08922014-09-30 21:32:48 -0500170}