blob: cab0dfbd01dfc9d3a9572ac28e126a6201444ce4 [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
48// DownloadResult is a *http.Response that is returned from a call to the Download function.
49type DownloadResult struct {
50 Resp *http.Response
51 Err error
52}
53
54// GetResult is a *http.Response that is returned from a call to the Get function.
55type GetResult struct {
56 Resp *http.Response
57 Err error
58}
59
60// ExtractInfo is a function that takes a page of objects and returns their full information.
61func ExtractInfo(page pagination.Page) ([]Object, error) {
62 untyped := page.(ObjectPage).Body.([]interface{})
63 results := make([]Object, len(untyped))
64 for index, each := range untyped {
Jon Perritt8aa40262014-09-29 15:41:32 -050065 object := each.(map[string]interface{})
Jon Perrittfdac6e52014-09-29 19:43:45 -050066 err := mapstructure.Decode(object, &results[index])
Jon Perritt8aa40262014-09-29 15:41:32 -050067 if err != nil {
68 return results, err
69 }
Jon Perritt8c93a302014-09-28 22:35:57 -050070 }
71 return results, nil
72}
73
74// ExtractNames is a function that takes a page of objects and returns only their names.
75func ExtractNames(page pagination.Page) ([]string, error) {
76 casted := page.(ObjectPage)
77 ct := casted.Header.Get("Content-Type")
Jon Perritt8c93a302014-09-28 22:35:57 -050078 switch {
79 case strings.HasPrefix(ct, "application/json"):
80 parsed, err := ExtractInfo(page)
81 if err != nil {
82 return nil, err
83 }
84
85 names := make([]string, 0, len(parsed))
86 for _, object := range parsed {
Jon Perritt8aa40262014-09-29 15:41:32 -050087 names = append(names, object.Name)
Jon Perritt8c93a302014-09-28 22:35:57 -050088 }
Jon Perrittfdac6e52014-09-29 19:43:45 -050089
Jon Perritt8c93a302014-09-28 22:35:57 -050090 return names, nil
91 case strings.HasPrefix(ct, "text/plain"):
92 names := make([]string, 0, 50)
93
94 body := string(page.(ObjectPage).Body.([]uint8))
95 for _, name := range strings.Split(body, "\n") {
96 if len(name) > 0 {
97 names = append(names, name)
98 }
99 }
100
101 return names, nil
Jon Perrittfdac6e52014-09-29 19:43:45 -0500102 case strings.HasPrefix(ct, "text/html"):
103 return []string{}, nil
Jon Perritt8c93a302014-09-28 22:35:57 -0500104 default:
105 return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
106 }
107}
108
109// ExtractContent is a function that takes a DownloadResult (of type *http.Response)
110// and returns the object's content.
111func (dr DownloadResult) ExtractContent() ([]byte, error) {
112 if dr.Err != nil {
113 return nil, nil
114 }
115 var body []byte
116 defer dr.Resp.Body.Close()
117 body, err := ioutil.ReadAll(dr.Resp.Body)
118 if err != nil {
119 return body, fmt.Errorf("Error trying to read DownloadResult body: %v", err)
120 }
121 return body, nil
122}
123
124// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
125// and returns the custom metadata associated with the object.
126func (gr GetResult) ExtractMetadata() (map[string]string, error) {
127 if gr.Err != nil {
128 return nil, gr.Err
129 }
130 metadata := make(map[string]string)
131 for k, v := range gr.Resp.Header {
132 if strings.HasPrefix(k, "X-Object-Meta-") {
133 key := strings.TrimPrefix(k, "X-Object-Meta-")
134 metadata[key] = v[0]
135 }
136 }
137 return metadata, nil
138}