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