1package containers
2
3import (
4	"encoding/json"
5	"fmt"
6	"strings"
7	"time"
8
9	"github.com/gophercloud/gophercloud"
10	"github.com/gophercloud/gophercloud/pagination"
11)
12
13// Container represents a container resource.
14type Container struct {
15	// The total number of bytes stored in the container.
16	Bytes int64 `json:"bytes"`
17
18	// The total number of objects stored in the container.
19	Count int64 `json:"count"`
20
21	// The name of the container.
22	Name string `json:"name"`
23}
24
25// ContainerPage is the page returned by a pager when traversing over a
26// collection of containers.
27type ContainerPage struct {
28	pagination.MarkerPageBase
29}
30
31//IsEmpty returns true if a ListResult contains no container names.
32func (r ContainerPage) IsEmpty() (bool, error) {
33	names, err := ExtractNames(r)
34	return len(names) == 0, err
35}
36
37// LastMarker returns the last container name in a ListResult.
38func (r ContainerPage) LastMarker() (string, error) {
39	names, err := ExtractNames(r)
40	if err != nil {
41		return "", err
42	}
43	if len(names) == 0 {
44		return "", nil
45	}
46	return names[len(names)-1], nil
47}
48
49// ExtractInfo is a function that takes a ListResult and returns the
50// containers' information.
51func ExtractInfo(r pagination.Page) ([]Container, error) {
52	var s []Container
53	err := (r.(ContainerPage)).ExtractInto(&s)
54	return s, err
55}
56
57// ExtractNames is a function that takes a ListResult and returns the
58// containers' names.
59func ExtractNames(page pagination.Page) ([]string, error) {
60	casted := page.(ContainerPage)
61	ct := casted.Header.Get("Content-Type")
62
63	switch {
64	case strings.HasPrefix(ct, "application/json"):
65		parsed, err := ExtractInfo(page)
66		if err != nil {
67			return nil, err
68		}
69
70		names := make([]string, 0, len(parsed))
71		for _, container := range parsed {
72			names = append(names, container.Name)
73		}
74		return names, nil
75	case strings.HasPrefix(ct, "text/plain"):
76		names := make([]string, 0, 50)
77
78		body := string(page.(ContainerPage).Body.([]uint8))
79		for _, name := range strings.Split(body, "\n") {
80			if len(name) > 0 {
81				names = append(names, name)
82			}
83		}
84
85		return names, nil
86	default:
87		return nil, fmt.Errorf("Cannot extract names from response with content-type: [%s]", ct)
88	}
89}
90
91// GetHeader represents the headers returned in the response from a Get request.
92type GetHeader struct {
93	AcceptRanges     string    `json:"Accept-Ranges"`
94	BytesUsed        int64     `json:"X-Container-Bytes-Used,string"`
95	ContentLength    int64     `json:"Content-Length,string"`
96	ContentType      string    `json:"Content-Type"`
97	Date             time.Time `json:"-"`
98	ObjectCount      int64     `json:"X-Container-Object-Count,string"`
99	Read             []string  `json:"-"`
100	TransID          string    `json:"X-Trans-Id"`
101	VersionsLocation string    `json:"X-Versions-Location"`
102	HistoryLocation  string    `json:"X-History-Location"`
103	Write            []string  `json:"-"`
104	StoragePolicy    string    `json:"X-Storage-Policy"`
105	TempURLKey       string    `json:"X-Container-Meta-Temp-URL-Key"`
106	TempURLKey2      string    `json:"X-Container-Meta-Temp-URL-Key-2"`
107}
108
109func (r *GetHeader) UnmarshalJSON(b []byte) error {
110	type tmp GetHeader
111	var s struct {
112		tmp
113		Write string                  `json:"X-Container-Write"`
114		Read  string                  `json:"X-Container-Read"`
115		Date  gophercloud.JSONRFC1123 `json:"Date"`
116	}
117	err := json.Unmarshal(b, &s)
118	if err != nil {
119		return err
120	}
121
122	*r = GetHeader(s.tmp)
123
124	r.Read = strings.Split(s.Read, ",")
125	r.Write = strings.Split(s.Write, ",")
126
127	r.Date = time.Time(s.Date)
128
129	return err
130}
131
132// GetResult represents the result of a get operation.
133type GetResult struct {
134	gophercloud.HeaderResult
135}
136
137// Extract will return a struct of headers returned from a call to Get.
138func (r GetResult) Extract() (*GetHeader, error) {
139	var s GetHeader
140	err := r.ExtractInto(&s)
141	return &s, err
142}
143
144// ExtractMetadata is a function that takes a GetResult (of type *http.Response)
145// and returns the custom metadata associated with the container.
146func (r GetResult) ExtractMetadata() (map[string]string, error) {
147	if r.Err != nil {
148		return nil, r.Err
149	}
150	metadata := make(map[string]string)
151	for k, v := range r.Header {
152		if strings.HasPrefix(k, "X-Container-Meta-") {
153			key := strings.TrimPrefix(k, "X-Container-Meta-")
154			metadata[key] = v[0]
155		}
156	}
157	return metadata, nil
158}
159
160// CreateHeader represents the headers returned in the response from a Create
161// request.
162type CreateHeader struct {
163	ContentLength int64     `json:"Content-Length,string"`
164	ContentType   string    `json:"Content-Type"`
165	Date          time.Time `json:"-"`
166	TransID       string    `json:"X-Trans-Id"`
167}
168
169func (r *CreateHeader) UnmarshalJSON(b []byte) error {
170	type tmp CreateHeader
171	var s struct {
172		tmp
173		Date gophercloud.JSONRFC1123 `json:"Date"`
174	}
175	err := json.Unmarshal(b, &s)
176	if err != nil {
177		return err
178	}
179
180	*r = CreateHeader(s.tmp)
181
182	r.Date = time.Time(s.Date)
183
184	return err
185}
186
187// CreateResult represents the result of a create operation. To extract the
188// the headers from the HTTP response, call its Extract method.
189type CreateResult struct {
190	gophercloud.HeaderResult
191}
192
193// Extract will return a struct of headers returned from a call to Create.
194// To extract the headers from the HTTP response, call its Extract method.
195func (r CreateResult) Extract() (*CreateHeader, error) {
196	var s CreateHeader
197	err := r.ExtractInto(&s)
198	return &s, err
199}
200
201// UpdateHeader represents the headers returned in the response from a Update
202// request.
203type UpdateHeader struct {
204	ContentLength int64     `json:"Content-Length,string"`
205	ContentType   string    `json:"Content-Type"`
206	Date          time.Time `json:"-"`
207	TransID       string    `json:"X-Trans-Id"`
208}
209
210func (r *UpdateHeader) UnmarshalJSON(b []byte) error {
211	type tmp UpdateHeader
212	var s struct {
213		tmp
214		Date gophercloud.JSONRFC1123 `json:"Date"`
215	}
216	err := json.Unmarshal(b, &s)
217	if err != nil {
218		return err
219	}
220
221	*r = UpdateHeader(s.tmp)
222
223	r.Date = time.Time(s.Date)
224
225	return err
226}
227
228// UpdateResult represents the result of an update operation. To extract the
229// the headers from the HTTP response, call its Extract method.
230type UpdateResult struct {
231	gophercloud.HeaderResult
232}
233
234// Extract will return a struct of headers returned from a call to Update.
235func (r UpdateResult) Extract() (*UpdateHeader, error) {
236	var s UpdateHeader
237	err := r.ExtractInto(&s)
238	return &s, err
239}
240
241// DeleteHeader represents the headers returned in the response from a Delete
242// request.
243type DeleteHeader struct {
244	ContentLength int64     `json:"Content-Length,string"`
245	ContentType   string    `json:"Content-Type"`
246	Date          time.Time `json:"-"`
247	TransID       string    `json:"X-Trans-Id"`
248}
249
250func (r *DeleteHeader) UnmarshalJSON(b []byte) error {
251	type tmp DeleteHeader
252	var s struct {
253		tmp
254		Date gophercloud.JSONRFC1123 `json:"Date"`
255	}
256	err := json.Unmarshal(b, &s)
257	if err != nil {
258		return err
259	}
260
261	*r = DeleteHeader(s.tmp)
262
263	r.Date = time.Time(s.Date)
264
265	return err
266}
267
268// DeleteResult represents the result of a delete operation. To extract the
269// headers from the HTTP response, call its Extract method.
270type DeleteResult struct {
271	gophercloud.HeaderResult
272}
273
274// Extract will return a struct of headers returned from a call to Delete.
275func (r DeleteResult) Extract() (*DeleteHeader, error) {
276	var s DeleteHeader
277	err := r.ExtractInto(&s)
278	return &s, err
279}
280
281type BulkDeleteResponse struct {
282	ResponseStatus string     `json:"Response Status"`
283	ResponseBody   string     `json:"Response Body"`
284	Errors         [][]string `json:"Errors"`
285	NumberDeleted  int        `json:"Number Deleted"`
286	NumberNotFound int        `json:"Number Not Found"`
287}
288
289// BulkDeleteResult represents the result of a bulk delete operation. To extract
290// the response object from the HTTP response, call its Extract method.
291type BulkDeleteResult struct {
292	gophercloud.Result
293}
294
295// Extract will return a BulkDeleteResponse struct returned from a BulkDelete
296// call.
297func (r BulkDeleteResult) Extract() (*BulkDeleteResponse, error) {
298	var s BulkDeleteResponse
299	err := r.ExtractInto(&s)
300	return &s, err
301}
302