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