github.com/thiagoyeds/go-cloud@v0.26.0/blob/driver/driver.go (about) 1 // Copyright 2018 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package driver defines interfaces to be implemented by blob drivers, which 16 // will be used by the blob package to interact with the underlying services. 17 // Application code should use package blob. 18 package driver // import "gocloud.dev/blob/driver" 19 20 import ( 21 "context" 22 "errors" 23 "io" 24 "strings" 25 "time" 26 27 "gocloud.dev/gcerrors" 28 ) 29 30 // ReaderOptions controls Reader behaviors. 31 type ReaderOptions struct { 32 // BeforeRead is a callback that must be called exactly once before 33 // any data is read, unless NewRangeReader returns an error before then, in 34 // which case it should not be called at all. 35 // asFunc allows drivers to expose driver-specific types; 36 // see Bucket.As for more details. 37 BeforeRead func(asFunc func(interface{}) bool) error 38 } 39 40 // Reader reads an object from the blob. 41 type Reader interface { 42 io.ReadCloser 43 44 // Attributes returns a subset of attributes about the blob. 45 // The portable type will not modify the returned ReaderAttributes. 46 Attributes() *ReaderAttributes 47 48 // As allows drivers to expose driver-specific types; 49 // see Bucket.As for more details. 50 As(interface{}) bool 51 } 52 53 // Writer writes an object to the blob. 54 type Writer interface { 55 io.WriteCloser 56 } 57 58 // WriterOptions controls behaviors of Writer. 59 type WriterOptions struct { 60 // BufferSize changes the default size in byte of the maximum part Writer can 61 // write in a single request, if supported. Larger objects will be split into 62 // multiple requests. 63 BufferSize int 64 // CacheControl specifies caching attributes that services may use 65 // when serving the blob. 66 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control 67 CacheControl string 68 // ContentDisposition specifies whether the blob content is expected to be 69 // displayed inline or as an attachment. 70 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition 71 ContentDisposition string 72 // ContentEncoding specifies the encoding used for the blob's content, if any. 73 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding 74 ContentEncoding string 75 // ContentLanguage specifies the language used in the blob's content, if any. 76 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language 77 ContentLanguage string 78 // ContentMD5 is used as a message integrity check. 79 // The portable type checks that the MD5 hash of the bytes written matches 80 // ContentMD5. 81 // If len(ContentMD5) > 0, driver implementations may pass it to their 82 // underlying network service to guarantee the integrity of the bytes in 83 // transit. 84 ContentMD5 []byte 85 // Metadata holds key/value strings to be associated with the blob. 86 // Keys are guaranteed to be non-empty and lowercased. 87 Metadata map[string]string 88 // BeforeWrite is a callback that must be called exactly once before 89 // any data is written, unless NewTypedWriter returns an error, in 90 // which case it should not be called. 91 // asFunc allows drivers to expose driver-specific types; 92 // see Bucket.As for more details. 93 BeforeWrite func(asFunc func(interface{}) bool) error 94 } 95 96 // CopyOptions controls options for Copy. 97 type CopyOptions struct { 98 // BeforeCopy is a callback that must be called before initiating the Copy. 99 // asFunc allows drivers to expose driver-specific types; 100 // see Bucket.As for more details. 101 BeforeCopy func(asFunc func(interface{}) bool) error 102 } 103 104 // ReaderAttributes contains a subset of attributes about a blob that are 105 // accessible from Reader. 106 type ReaderAttributes struct { 107 // ContentType is the MIME type of the blob object. It must not be empty. 108 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type 109 ContentType string 110 // ModTime is the time the blob object was last modified. 111 ModTime time.Time 112 // Size is the size of the object in bytes. 113 Size int64 114 } 115 116 // Attributes contains attributes about a blob. 117 type Attributes struct { 118 // CacheControl specifies caching attributes that services may use 119 // when serving the blob. 120 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control 121 CacheControl string 122 // ContentDisposition specifies whether the blob content is expected to be 123 // displayed inline or as an attachment. 124 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition 125 ContentDisposition string 126 // ContentEncoding specifies the encoding used for the blob's content, if any. 127 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding 128 ContentEncoding string 129 // ContentLanguage specifies the language used in the blob's content, if any. 130 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language 131 ContentLanguage string 132 // ContentType is the MIME type of the blob object. It must not be empty. 133 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type 134 ContentType string 135 // Metadata holds key/value pairs associated with the blob. 136 // Keys will be lowercased by the portable type before being returned 137 // to the user. If there are duplicate case-insensitive keys (e.g., 138 // "foo" and "FOO"), only one value will be kept, and it is undefined 139 // which one. 140 Metadata map[string]string 141 // CreateTime is the time the blob object was created. If not available, 142 // leave as the zero time. 143 CreateTime time.Time 144 // ModTime is the time the blob object was last modified. 145 ModTime time.Time 146 // Size is the size of the object in bytes. 147 Size int64 148 // MD5 is an MD5 hash of the blob contents or nil if not available. 149 MD5 []byte 150 // ETag for the blob; see https://en.wikipedia.org/wiki/HTTP_ETag. 151 ETag string 152 // AsFunc allows drivers to expose driver-specific types; 153 // see Bucket.As for more details. 154 // If not set, no driver-specific types are supported. 155 AsFunc func(interface{}) bool 156 } 157 158 // ListOptions sets options for listing objects in the bucket. 159 type ListOptions struct { 160 // Prefix indicates that only results with the given prefix should be 161 // returned. 162 Prefix string 163 // Delimiter sets the delimiter used to define a hierarchical namespace, 164 // like a filesystem with "directories". 165 // 166 // An empty delimiter means that the bucket is treated as a single flat 167 // namespace. 168 // 169 // A non-empty delimiter means that any result with the delimiter in its key 170 // after Prefix is stripped will be returned with ListObject.IsDir = true, 171 // ListObject.Key truncated after the delimiter, and zero values for other 172 // ListObject fields. These results represent "directories". Multiple results 173 // in a "directory" are returned as a single result. 174 Delimiter string 175 // PageSize sets the maximum number of objects to be returned. 176 // 0 means no maximum; driver implementations should choose a reasonable 177 // max. It is guaranteed to be >= 0. 178 PageSize int 179 // PageToken may be filled in with the NextPageToken from a previous 180 // ListPaged call. 181 PageToken []byte 182 // BeforeList is a callback that must be called exactly once during ListPaged, 183 // before the underlying service's list is executed. 184 // asFunc allows drivers to expose driver-specific types; 185 // see Bucket.As for more details. 186 BeforeList func(asFunc func(interface{}) bool) error 187 } 188 189 // ListObject represents a specific blob object returned from ListPaged. 190 type ListObject struct { 191 // Key is the key for this blob. 192 Key string 193 // ModTime is the time the blob object was last modified. 194 ModTime time.Time 195 // Size is the size of the object in bytes. 196 Size int64 197 // MD5 is an MD5 hash of the blob contents or nil if not available. 198 MD5 []byte 199 // IsDir indicates that this result represents a "directory" in the 200 // hierarchical namespace, ending in ListOptions.Delimiter. Key can be 201 // passed as ListOptions.Prefix to list items in the "directory". 202 // Fields other than Key and IsDir will not be set if IsDir is true. 203 IsDir bool 204 // AsFunc allows drivers to expose driver-specific types; 205 // see Bucket.As for more details. 206 // If not set, no driver-specific types are supported. 207 AsFunc func(interface{}) bool 208 } 209 210 // ListPage represents a page of results return from ListPaged. 211 type ListPage struct { 212 // Objects is the slice of objects found. If ListOptions.PageSize > 0, 213 // it should have at most ListOptions.PageSize entries. 214 // 215 // Objects should be returned in lexicographical order of UTF-8 encoded keys, 216 // including across pages. I.e., all objects returned from a ListPage request 217 // made using a PageToken from a previous ListPage request's NextPageToken 218 // should have Key >= the Key for all objects from the previous request. 219 Objects []*ListObject 220 // NextPageToken should be left empty unless there are more objects 221 // to return. The value may be returned as ListOptions.PageToken on a 222 // subsequent ListPaged call, to fetch the next page of results. 223 // It can be an arbitrary []byte; it need not be a valid key. 224 NextPageToken []byte 225 } 226 227 // Bucket provides read, write and delete operations on objects within it on the 228 // blob service. 229 type Bucket interface { 230 // ErrorCode should return a code that describes the error, which was returned by 231 // one of the other methods in this interface. 232 ErrorCode(error) gcerrors.ErrorCode 233 234 // As converts i to driver-specific types. 235 // See https://gocloud.dev/concepts/as/ for background information. 236 As(i interface{}) bool 237 238 // ErrorAs allows drivers to expose driver-specific types for returned 239 // errors. 240 // See https://gocloud.dev/concepts/as/ for background information. 241 ErrorAs(error, interface{}) bool 242 243 // Attributes returns attributes for the blob. If the specified object does 244 // not exist, Attributes must return an error for which ErrorCode returns 245 // gcerrors.NotFound. 246 // The portable type will not modify the returned Attributes. 247 Attributes(ctx context.Context, key string) (*Attributes, error) 248 249 // ListPaged lists objects in the bucket, in lexicographical order by 250 // UTF-8-encoded key, returning pages of objects at a time. 251 // Services are only required to be eventually consistent with respect 252 // to recently written or deleted objects. That is to say, there is no 253 // guarantee that an object that's been written will immediately be returned 254 // from ListPaged. 255 // opts is guaranteed to be non-nil. 256 ListPaged(ctx context.Context, opts *ListOptions) (*ListPage, error) 257 258 // NewRangeReader returns a Reader that reads part of an object, reading at 259 // most length bytes starting at the given offset. If length is negative, it 260 // will read until the end of the object. If the specified object does not 261 // exist, NewRangeReader must return an error for which ErrorCode returns 262 // gcerrors.NotFound. 263 // opts is guaranteed to be non-nil. 264 NewRangeReader(ctx context.Context, key string, offset, length int64, opts *ReaderOptions) (Reader, error) 265 266 // NewTypedWriter returns Writer that writes to an object associated with key. 267 // 268 // A new object will be created unless an object with this key already exists. 269 // Otherwise any previous object with the same key will be replaced. 270 // The object may not be available (and any previous object will remain) 271 // until Close has been called. 272 // 273 // contentType sets the MIME type of the object to be written. It must not be 274 // empty. opts is guaranteed to be non-nil. 275 // 276 // The caller must call Close on the returned Writer when done writing. 277 // 278 // Implementations should abort an ongoing write if ctx is later canceled, 279 // and do any necessary cleanup in Close. Close should then return ctx.Err(). 280 NewTypedWriter(ctx context.Context, key, contentType string, opts *WriterOptions) (Writer, error) 281 282 // Copy copies the object associated with srcKey to dstKey. 283 // 284 // If the source object does not exist, Copy must return an error for which 285 // ErrorCode returns gcerrors.NotFound. 286 // 287 // If the destination object already exists, it should be overwritten. 288 // 289 // opts is guaranteed to be non-nil. 290 Copy(ctx context.Context, dstKey, srcKey string, opts *CopyOptions) error 291 292 // Delete deletes the object associated with key. If the specified object does 293 // not exist, Delete must return an error for which ErrorCode returns 294 // gcerrors.NotFound. 295 Delete(ctx context.Context, key string) error 296 297 // SignedURL returns a URL that can be used to GET the blob for the duration 298 // specified in opts.Expiry. opts is guaranteed to be non-nil. 299 // If not supported, return an error for which ErrorCode returns 300 // gcerrors.Unimplemented. 301 SignedURL(ctx context.Context, key string, opts *SignedURLOptions) (string, error) 302 303 // Close cleans up any resources used by the Bucket. Once Close is called, 304 // there will be no method calls to the Bucket other than As, ErrorAs, and 305 // ErrorCode. There may be open readers or writers that will receive calls. 306 // It is up to the driver as to how these will be handled. 307 Close() error 308 } 309 310 // SignedURLOptions sets options for SignedURL. 311 type SignedURLOptions struct { 312 // Expiry sets how long the returned URL is valid for. It is guaranteed to be > 0. 313 Expiry time.Duration 314 315 // Method is the HTTP method that can be used on the URL; one of "GET", "PUT", 316 // or "DELETE". Drivers must implement all 3. 317 Method string 318 319 // ContentType specifies the Content-Type HTTP header the user agent is 320 // permitted to use in the PUT request. It must match exactly. See 321 // EnforceAbsentContentType for behavior when ContentType is the empty string. 322 // If this field is not empty and the bucket cannot enforce the Content-Type 323 // header, it must return an Unimplemented error. 324 // 325 // This field will not be set for any non-PUT requests. 326 ContentType string 327 328 // If EnforceAbsentContentType is true and ContentType is the empty string, 329 // then PUTing to the signed URL must fail if the Content-Type header is 330 // present or the implementation must return an error if it cannot enforce 331 // this. If EnforceAbsentContentType is false and ContentType is the empty 332 // string, implementations should validate the Content-Type header if possible. 333 // If EnforceAbsentContentType is true and the bucket cannot enforce the 334 // Content-Type header, it must return an Unimplemented error. 335 // 336 // This field will always be false for non-PUT requests. 337 EnforceAbsentContentType bool 338 339 // BeforeSign is a callback that will be called before each call to the 340 // the underlying service's sign functionality. 341 // asFunc converts its argument to driver-specific types. 342 // See https://gocloud.dev/concepts/as/ for background information. 343 BeforeSign func(asFunc func(interface{}) bool) error 344 } 345 346 // prefixedBucket implements Bucket by prepending prefix to all keys. 347 type prefixedBucket struct { 348 base Bucket 349 prefix string 350 } 351 352 // NewPrefixedBucket returns a Bucket based on b with all keys modified to have 353 // prefix. 354 func NewPrefixedBucket(b Bucket, prefix string) Bucket { 355 return &prefixedBucket{base: b, prefix: prefix} 356 } 357 358 func (b *prefixedBucket) ErrorCode(err error) gcerrors.ErrorCode { return b.base.ErrorCode(err) } 359 func (b *prefixedBucket) As(i interface{}) bool { return b.base.As(i) } 360 func (b *prefixedBucket) ErrorAs(err error, i interface{}) bool { return b.base.ErrorAs(err, i) } 361 func (b *prefixedBucket) Attributes(ctx context.Context, key string) (*Attributes, error) { 362 return b.base.Attributes(ctx, b.prefix+key) 363 } 364 func (b *prefixedBucket) ListPaged(ctx context.Context, opts *ListOptions) (*ListPage, error) { 365 var myopts ListOptions 366 if opts != nil { 367 myopts = *opts 368 } 369 myopts.Prefix = b.prefix + myopts.Prefix 370 page, err := b.base.ListPaged(ctx, &myopts) 371 if err != nil { 372 return nil, err 373 } 374 for _, p := range page.Objects { 375 p.Key = strings.TrimPrefix(p.Key, b.prefix) 376 } 377 return page, nil 378 } 379 func (b *prefixedBucket) NewRangeReader(ctx context.Context, key string, offset, length int64, opts *ReaderOptions) (Reader, error) { 380 return b.base.NewRangeReader(ctx, b.prefix+key, offset, length, opts) 381 } 382 func (b *prefixedBucket) NewTypedWriter(ctx context.Context, key, contentType string, opts *WriterOptions) (Writer, error) { 383 if key == "" { 384 return nil, errors.New("invalid key (empty string)") 385 } 386 return b.base.NewTypedWriter(ctx, b.prefix+key, contentType, opts) 387 } 388 func (b *prefixedBucket) Copy(ctx context.Context, dstKey, srcKey string, opts *CopyOptions) error { 389 return b.base.Copy(ctx, b.prefix+dstKey, b.prefix+srcKey, opts) 390 } 391 func (b *prefixedBucket) Delete(ctx context.Context, key string) error { 392 return b.base.Delete(ctx, b.prefix+key) 393 } 394 func (b *prefixedBucket) SignedURL(ctx context.Context, key string, opts *SignedURLOptions) (string, error) { 395 return b.base.SignedURL(ctx, b.prefix+key, opts) 396 } 397 func (b *prefixedBucket) Close() error { return b.base.Close() }