OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /// This library provides access to Google Cloud Storage. |
| 6 /// |
| 7 /// Google Cloud Storage is an object store for binary objects. Each |
| 8 /// object has a set of metadata attached to it. For more information on |
| 9 /// Google Cloud Sorage see https://developers.google.com/storage/. |
| 10 /// |
| 11 /// There are two main concepts in Google Cloud Storage: Buckets and Objects. |
| 12 /// A bucket is a container for objects and objects are the actual binary |
| 13 /// objects. |
| 14 /// |
| 15 /// The API has two main classes for dealing with buckets and objects. |
| 16 /// |
| 17 /// The class `Storage` is the main API class providing access to working |
| 18 /// with buckets. This is the 'bucket service' interface. |
| 19 /// |
| 20 /// The class `Bucket` provide access to working with objcts in a specific |
| 21 /// bucket. This is the 'object service' interface. |
| 22 /// |
| 23 /// Both buckets have objects, have names. The bucket namespace is flat and |
| 24 /// global across all projects. This means that a bucket is always |
| 25 /// addressable using its name without requiring further context. |
| 26 /// |
| 27 /// Within buckets the object namespace is also flat. Object are *not* |
| 28 /// organized hierachical. However, as object names allow the slash `/` |
| 29 /// character this is often used to simulate a hierachical structure |
| 30 /// based on common prefixes. |
| 31 /// |
| 32 /// This package uses relative and absolute names to refer to objects. A |
| 33 /// relative name is just the object name within a bucket, and requires the |
| 34 /// context of a bucket to be used. A relative name just looks like this: |
| 35 /// |
| 36 /// object_name |
| 37 /// |
| 38 /// An absolute name includes the bucket name and uses the `gs://` prefix |
| 39 /// also used by the `gsutil` tool. An absolute name looks like this. |
| 40 /// |
| 41 /// gs://bucket_name/object_name |
| 42 /// |
| 43 /// In most cases relative names are used. Absolute names are typically |
| 44 /// only used for operations involving objects in different buckets. |
| 45 /// |
| 46 /// For most of the APIs in ths library which take instances of other classes |
| 47 /// from this library it is the assumption that the actual implementations |
| 48 /// provided here are used. |
| 49 library gcloud.storage; |
| 50 |
| 51 import 'dart:async'; |
| 52 import 'dart:collection' show UnmodifiableListView, UnmodifiableMapView; |
| 53 |
| 54 import 'package:http/http.dart' as http; |
| 55 |
| 56 import 'package:crypto/crypto.dart' as crypto; |
| 57 import 'package:googleapis/storage/v1.dart' as storage_api; |
| 58 import 'package:googleapis/common/common.dart' as common; |
| 59 |
| 60 import 'service_scope.dart' as ss; |
| 61 |
| 62 import 'common.dart'; |
| 63 export 'common.dart'; |
| 64 |
| 65 part 'src/storage_impl.dart'; |
| 66 |
| 67 const Symbol _storageKey = #_gcloud.storage; |
| 68 |
| 69 /// Access the [Storage] object available in the current service scope. |
| 70 /// |
| 71 /// The returned object will be the one which was previously registered with |
| 72 /// [registerStorageService] within the current (or a parent) service scope. |
| 73 /// |
| 74 /// Accessing this getter outside of a service scope will result in an error. |
| 75 /// See the `package:gcloud/service_scope.dart` library for more information. |
| 76 Storage get storageService => ss.lookup(_storageKey); |
| 77 |
| 78 /// Registers the [storage] object within the current service scope. |
| 79 /// |
| 80 /// The provided `storage` object will be avilable via the top-level `storage` |
| 81 /// getter. |
| 82 /// |
| 83 /// Calling this function outside of a service scope will result in an error. |
| 84 /// Calling this function more than once inside the same service scope is not |
| 85 /// allowed. |
| 86 void registerStorageService(Storage storage) { |
| 87 ss.register(_storageKey, storage); |
| 88 } |
| 89 |
| 90 int _jenkinsHash(List e) { |
| 91 const _HASH_MASK = 0x3fffffff; |
| 92 int hash = 0; |
| 93 for (int i = 0; i < e.length; i++) { |
| 94 int c = e[i].hashCode; |
| 95 hash = (hash + c) & _HASH_MASK; |
| 96 hash = (hash + (hash << 10)) & _HASH_MASK; |
| 97 hash ^= (hash >> 6); |
| 98 } |
| 99 hash = (hash + (hash << 3)) & _HASH_MASK; |
| 100 hash ^= (hash >> 11); |
| 101 hash = (hash + (hash << 15)) & _HASH_MASK; |
| 102 return hash; |
| 103 } |
| 104 |
| 105 /// An ACL (Access Control List) describes access rights to buckets and |
| 106 /// objects. |
| 107 /// |
| 108 /// An ACL is a prioritized sequence of access control specifications, |
| 109 /// which individually prevent or grant access. |
| 110 /// The access controls are described by [AclEntry] objects. |
| 111 class Acl { |
| 112 final List<AclEntry> _entries; |
| 113 int _cachedHashCode; |
| 114 |
| 115 /// The entries in the ACL. |
| 116 List<AclEntry> get entries => new UnmodifiableListView<AclEntry>(_entries); |
| 117 |
| 118 /// Create a new ACL with a list of ACL entries. |
| 119 Acl(Iterable<AclEntry> entries) : _entries = new List.from(entries); |
| 120 |
| 121 Acl._fromBucketAcl(storage_api.Bucket bucket) |
| 122 : _entries = new List(bucket.acl == null ? 0 : bucket.acl.length) { |
| 123 if (bucket.acl != null) { |
| 124 for (int i = 0; i < bucket.acl.length; i++) { |
| 125 _entries[i] = new AclEntry(_aclScopeFromEntity(bucket.acl[i].entity), |
| 126 _aclPermissionFromRole(bucket.acl[i].role)); |
| 127 } |
| 128 } |
| 129 } |
| 130 |
| 131 Acl._fromObjectAcl(storage_api.Object object) |
| 132 : _entries = new List(object.acl == null ? 0 : object.acl.length) { |
| 133 if (object.acl != null) { |
| 134 for (int i = 0; i < object.acl.length; i++) { |
| 135 _entries[i] = new AclEntry(_aclScopeFromEntity(object.acl[i].entity), |
| 136 _aclPermissionFromRole(object.acl[i].role)); |
| 137 } |
| 138 } |
| 139 } |
| 140 |
| 141 AclScope _aclScopeFromEntity(String entity) { |
| 142 if (entity.startsWith('user-')) { |
| 143 String tmp = entity.substring(5); |
| 144 int at = tmp.indexOf('@'); |
| 145 if (at != -1) { |
| 146 return new AccountScope(tmp); |
| 147 } else { |
| 148 return new StorageIdScope(tmp); |
| 149 } |
| 150 } else if (entity.startsWith('group-')) { |
| 151 return new GroupScope(entity.substring(6)); |
| 152 } else if (entity.startsWith('domain-')) { |
| 153 return new DomainScope(entity.substring(7)); |
| 154 } else if (entity.startsWith('allAuthenticatedUsers-')) { |
| 155 return AclScope.allAuthenticated; |
| 156 } else if (entity.startsWith('allUsers-')) { |
| 157 return AclScope.allUsers; |
| 158 } else if (entity.startsWith('project-')) { |
| 159 String tmp = entity.substring(8); |
| 160 int dash = tmp.indexOf('-'); |
| 161 if (dash != -1) { |
| 162 return new ProjectScope(tmp.substring(dash + 1), |
| 163 tmp.substring(0, dash)); |
| 164 } |
| 165 } |
| 166 return new OpaqueScope(entity); |
| 167 } |
| 168 |
| 169 AclPermission _aclPermissionFromRole(String role) { |
| 170 if (role == 'READER') return AclPermission.READ; |
| 171 if (role == 'WRITER') return AclPermission.WRITE; |
| 172 if (role == 'OWNER') return AclPermission.FULL_CONTROL; |
| 173 throw new UnsupportedError( |
| 174 "Server returned a unsupported permission role '$role'"); |
| 175 } |
| 176 |
| 177 List<storage_api.BucketAccessControl> _toBucketAccessControlList() { |
| 178 return _entries.map((entry) => entry._toBucketAccessControl()).toList(); |
| 179 } |
| 180 |
| 181 List<storage_api.ObjectAccessControl> _toObjectAccessControlList() { |
| 182 return _entries.map((entry) => entry._toObjectAccessControl()).toList(); |
| 183 } |
| 184 |
| 185 int get hashCode { |
| 186 return _cachedHashCode != null |
| 187 ? _cachedHashCode |
| 188 : _cachedHashCode = _jenkinsHash(_entries); |
| 189 } |
| 190 |
| 191 bool operator==(Object other) { |
| 192 if (other is Acl) { |
| 193 List entries = _entries; |
| 194 List otherEntries = other._entries; |
| 195 if (entries.length != otherEntries.length) return false; |
| 196 for (int i = 0; i < entries.length; i++) { |
| 197 if (entries[i] != otherEntries[i]) return false; |
| 198 } |
| 199 return true; |
| 200 } else { |
| 201 return false; |
| 202 } |
| 203 } |
| 204 |
| 205 String toString() => 'Acl($_entries)'; |
| 206 } |
| 207 |
| 208 /// An ACL entry specifies that an entity has a specific access permission. |
| 209 /// |
| 210 /// A permission grants a specific permission to the entity. |
| 211 class AclEntry { |
| 212 final AclScope scope; |
| 213 final AclPermission permission; |
| 214 int _cachedHashCode; |
| 215 |
| 216 AclEntry(this.scope, this.permission); |
| 217 |
| 218 storage_api.BucketAccessControl _toBucketAccessControl() { |
| 219 var acl = new storage_api.BucketAccessControl(); |
| 220 acl.entity = scope._storageEntity; |
| 221 acl.role = permission._storageBucketRole; |
| 222 return acl; |
| 223 } |
| 224 |
| 225 storage_api.ObjectAccessControl _toObjectAccessControl() { |
| 226 var acl = new storage_api.ObjectAccessControl(); |
| 227 acl.entity = scope._storageEntity; |
| 228 acl.role = permission._storageObjectRole; |
| 229 return acl; |
| 230 } |
| 231 |
| 232 int get hashCode { |
| 233 return _cachedHashCode != null |
| 234 ? _cachedHashCode |
| 235 : _cachedHashCode = _jenkinsHash([scope, permission]); |
| 236 } |
| 237 |
| 238 bool operator==(Object other) { |
| 239 return other is AclEntry && |
| 240 scope == other.scope && |
| 241 permission == other.permission; |
| 242 } |
| 243 |
| 244 String toString() => 'AclEntry($scope, $permission)'; |
| 245 } |
| 246 |
| 247 /// An ACL scope specifies an entity for which a permission applies. |
| 248 /// |
| 249 /// A scope can be one of: |
| 250 /// |
| 251 /// * Google Storage ID |
| 252 /// * Google account email address |
| 253 /// * Google group email address |
| 254 /// * Google Apps domain |
| 255 /// * Special identifier for all Google account holders |
| 256 /// * Special identifier for all users |
| 257 /// |
| 258 /// See https://cloud.google.com/storage/docs/accesscontrol for more details. |
| 259 abstract class AclScope { |
| 260 int _cachedHashCode; |
| 261 |
| 262 /// ACL type for scope representing a Google Storage id. |
| 263 static const int _TYPE_STORAGE_ID = 0; |
| 264 |
| 265 /// ACL type for scope representing a project entity. |
| 266 static const int _TYPE_PROJECT = 1; |
| 267 |
| 268 /// ACL type for scope representing an account holder. |
| 269 static const int _TYPE_ACCOUNT = 2; |
| 270 |
| 271 /// ACL type for scope representing a group. |
| 272 static const int _TYPE_GROUP = 3; |
| 273 |
| 274 /// ACL type for scope representing a domain. |
| 275 static const int _TYPE_DOMAIN = 4; |
| 276 |
| 277 /// ACL type for scope representing all authenticated users. |
| 278 static const int _TYPE_ALL_AUTHENTICATED = 5; |
| 279 |
| 280 /// ACL type for scope representing all users. |
| 281 static const int _TYPE_ALL_USERS = 6; |
| 282 |
| 283 /// ACL type for scope representing an unsupported scope. |
| 284 static const int _TYPE_OPAQUE = 7; |
| 285 |
| 286 /// The id of the actual entity this ACL scope represents. The actual values |
| 287 /// are set in the different subclasses. |
| 288 final String _id; |
| 289 |
| 290 /// The type of this acope this ACL scope represents. |
| 291 final int _type; |
| 292 |
| 293 /// ACL scope for all authenticated users. |
| 294 static AllAuthenticatedScope allAuthenticated = new AllAuthenticatedScope(); |
| 295 |
| 296 /// ACL scope for all users. |
| 297 static AllUsersScope allUsers = new AllUsersScope(); |
| 298 |
| 299 AclScope._(this._type, this._id); |
| 300 |
| 301 int get hashCode { |
| 302 return _cachedHashCode != null |
| 303 ? _cachedHashCode |
| 304 : _cachedHashCode = _jenkinsHash([_type, _id]); |
| 305 } |
| 306 |
| 307 bool operator==(Object other) { |
| 308 return other is AclScope && _type == other._type && _id == other._id; |
| 309 } |
| 310 |
| 311 String toString() => 'AclScope($_storageEntity)'; |
| 312 |
| 313 String get _storageEntity; |
| 314 } |
| 315 |
| 316 /// An ACL scope for an entity identified by a 'Google Storage ID'. |
| 317 /// |
| 318 /// The [storageId] is a string of 64 hexadecimal digits that identifies a |
| 319 /// specific Google account holder or a specific Google group. |
| 320 class StorageIdScope extends AclScope { |
| 321 StorageIdScope(String storageId) |
| 322 : super._(AclScope._TYPE_STORAGE_ID, storageId); |
| 323 |
| 324 /// Google Storage ID. |
| 325 String get storageId => _id; |
| 326 |
| 327 String get _storageEntity => 'user-$_id'; |
| 328 } |
| 329 |
| 330 /// An ACL scope for an entity identified by an individual email address. |
| 331 class AccountScope extends AclScope { |
| 332 AccountScope(String email): super._(AclScope._TYPE_ACCOUNT, email); |
| 333 |
| 334 /// Email address. |
| 335 String get email => _id; |
| 336 |
| 337 String get _storageEntity => 'user-$_id'; |
| 338 } |
| 339 |
| 340 /// An ACL scope for an entity identified by an Google Groups email. |
| 341 class GroupScope extends AclScope { |
| 342 GroupScope(String group): super._(AclScope._TYPE_GROUP, group); |
| 343 |
| 344 /// Group name. |
| 345 String get group => _id; |
| 346 |
| 347 String get _storageEntity => 'group-$_id'; |
| 348 } |
| 349 |
| 350 /// An ACL scope for an entity identified by a domain name. |
| 351 class DomainScope extends AclScope { |
| 352 DomainScope(String domain): super._(AclScope._TYPE_DOMAIN, domain); |
| 353 |
| 354 /// Domain name. |
| 355 String get domain => _id; |
| 356 |
| 357 String get _storageEntity => 'domain-$_id'; |
| 358 } |
| 359 |
| 360 /// An ACL scope for an project related entity. |
| 361 class ProjectScope extends AclScope { |
| 362 /// Project role. |
| 363 /// |
| 364 /// Possible values are `owners`, `editors` and `viewers`. |
| 365 final String role; |
| 366 |
| 367 ProjectScope(String project, String this.role) |
| 368 : super._(AclScope._TYPE_PROJECT, project); |
| 369 |
| 370 /// Project ID. |
| 371 String get project => _id; |
| 372 |
| 373 String get _storageEntity => 'project-$role-$_id'; |
| 374 } |
| 375 |
| 376 /// An ACL scope for an unsupported scope. |
| 377 class OpaqueScope extends AclScope { |
| 378 OpaqueScope(String id) : super._(AclScope._TYPE_OPAQUE, id); |
| 379 |
| 380 String get _storageEntity => _id; |
| 381 } |
| 382 |
| 383 /// ACL scope for a all authenticated users. |
| 384 class AllAuthenticatedScope extends AclScope { |
| 385 AllAuthenticatedScope() |
| 386 : super._(AclScope._TYPE_ALL_AUTHENTICATED, null); |
| 387 |
| 388 String get _storageEntity => 'allAuthenticatedUsers'; |
| 389 } |
| 390 |
| 391 /// ACL scope for a all users. |
| 392 class AllUsersScope extends AclScope { |
| 393 AllUsersScope(): super._(AclScope._TYPE_ALL_USERS, null); |
| 394 |
| 395 String get _storageEntity => 'allUsers'; |
| 396 } |
| 397 |
| 398 /// Permissions for individual scopes in an ACL. |
| 399 class AclPermission { |
| 400 /// Provide read access. |
| 401 static const READ = const AclPermission._('READER'); |
| 402 |
| 403 /// Provide write access. |
| 404 /// |
| 405 /// For objects this permission is the same as [FULL_CONTROL]. |
| 406 static const WRITE = const AclPermission._('WRITER'); |
| 407 |
| 408 /// Provide full control. |
| 409 /// |
| 410 /// For objects this permission is the same as [WRITE]. |
| 411 static const FULL_CONTROL = const AclPermission._('OWNER'); |
| 412 |
| 413 final String _id; |
| 414 |
| 415 const AclPermission._(this._id); |
| 416 |
| 417 String get _storageBucketRole => _id; |
| 418 |
| 419 String get _storageObjectRole => this == WRITE ? FULL_CONTROL._id : _id; |
| 420 |
| 421 int get hashCode => _id.hashCode; |
| 422 |
| 423 bool operator==(Object other) { |
| 424 return other is AclPermission && _id == other._id; |
| 425 } |
| 426 |
| 427 String toString() => 'AclPermission($_id)'; |
| 428 } |
| 429 |
| 430 /// Definition of predefined ACLs. |
| 431 /// |
| 432 /// There is a convenient way of referring to number of _predefined_ ACLs. These |
| 433 /// predefined ACLs have explicit names, and can _only_ be used to set an ACL, |
| 434 /// when either creating or updating a bucket or object. This set of predefined |
| 435 /// ACLs are expanded on the server to their actual list of [AclEntry] objects. |
| 436 /// When information is retreived on a bucket or object, this expanded list will |
| 437 /// be present. For a description of these predefined ACLs see: |
| 438 /// https://cloud.google.com/storage/docs/accesscontrol#extension. |
| 439 class PredefinedAcl { |
| 440 final String _name; |
| 441 const PredefinedAcl._(this._name); |
| 442 |
| 443 /// Predefined ACL for the 'authenticated-read' ACL. Applies to both buckets |
| 444 /// and objects. |
| 445 static const PredefinedAcl authenticatedRead = |
| 446 const PredefinedAcl._('authenticatedRead'); |
| 447 |
| 448 /// Predefined ACL for the 'private' ACL. Applies to both buckets |
| 449 /// and objects. |
| 450 static const PredefinedAcl private = const PredefinedAcl._('private'); |
| 451 |
| 452 /// Predefined ACL for the 'project-private' ACL. Applies to both buckets |
| 453 /// and objects. |
| 454 static const PredefinedAcl projectPrivate = |
| 455 const PredefinedAcl._('projectPrivate'); |
| 456 |
| 457 /// Predefined ACL for the 'public-read' ACL. Applies to both buckets |
| 458 /// and objects. |
| 459 static const PredefinedAcl publicRead = const PredefinedAcl._('publicRead'); |
| 460 |
| 461 /// Predefined ACL for the 'public-read-write' ACL. Applies only to buckets. |
| 462 static const PredefinedAcl publicReadWrite = |
| 463 const PredefinedAcl._('publicReadWrite'); |
| 464 |
| 465 /// Predefined ACL for the 'bucket-owner-full-control' ACL. Applies only to |
| 466 /// objects. |
| 467 static const PredefinedAcl bucketOwnerFullControl = |
| 468 const PredefinedAcl._('bucketOwnerFullControl'); |
| 469 |
| 470 /// Predefined ACL for the 'bucket-owner-read' ACL. Applies only to |
| 471 /// objects. |
| 472 static const PredefinedAcl bucketOwnerRead = |
| 473 const PredefinedAcl._('bucketOwnerRead'); |
| 474 |
| 475 String toString() => 'PredefinedAcl($_name)'; |
| 476 } |
| 477 |
| 478 /// Information on a bucket. |
| 479 abstract class BucketInfo { |
| 480 /// Name of the bucket. |
| 481 String get bucketName; |
| 482 |
| 483 /// Entity tag for the bucket. |
| 484 String get etag; |
| 485 |
| 486 /// When this bucket was created. |
| 487 DateTime get created; |
| 488 |
| 489 /// Bucket ID. |
| 490 String get id; |
| 491 |
| 492 /// Acl of the bucket. |
| 493 Acl get acl; |
| 494 } |
| 495 |
| 496 /// Access to Cloud Storage |
| 497 abstract class Storage { |
| 498 /// List of required OAuth2 scopes for Cloud Storage operation. |
| 499 static const List<String> SCOPES = |
| 500 const <String>[storage_api.StorageApi.DevstorageFullControlScope]; |
| 501 |
| 502 /// Initializes access to cloud storage. |
| 503 factory Storage(http.Client client, String project) = _StorageImpl; |
| 504 |
| 505 /// Create a cloud storage bucket. |
| 506 /// |
| 507 /// Creates a cloud storage bucket named [bucketName]. |
| 508 /// |
| 509 /// The bucket ACL can be set by passing [predefinedAcl] or [acl]. If both |
| 510 /// are passed the entries from [acl] with be followed by the expansion of |
| 511 /// [predefinedAcl]. |
| 512 /// |
| 513 /// Returns a [Future] which completes when the bucket has been created. |
| 514 Future createBucket(String bucketName, |
| 515 {PredefinedAcl predefinedAcl, Acl acl}); |
| 516 |
| 517 /// Delete a cloud storage bucket. |
| 518 /// |
| 519 /// Deletes the cloud storage bucket named [bucketName]. |
| 520 /// |
| 521 /// If the bucket is not empty the operation will fail. |
| 522 /// |
| 523 /// The returned [Future] completes when the operation is finished. |
| 524 Future deleteBucket(String bucketName); |
| 525 |
| 526 /// Access bucket object operations. |
| 527 /// |
| 528 /// Instantiates a `Bucket` object refering to the bucket named [bucketName]. |
| 529 /// |
| 530 /// When an object is created using the resulting `Bucket` an ACL will always |
| 531 /// be set. If the object creation does not pass any explicit ACL information |
| 532 /// a default ACL will be used. |
| 533 /// |
| 534 /// If the arguments [defaultPredefinedObjectAcl] or [defaultObjectAcl] are |
| 535 /// passed they define the default ACL. If both are passed the entries from |
| 536 /// [defaultObjectAcl] with be followed by the expansion of |
| 537 /// [defaultPredefinedObjectAcl] when an object is created. |
| 538 /// |
| 539 /// Otherwise the default object ACL attached to the bucket will be used. |
| 540 /// |
| 541 /// Returns a `Bucket` instance. |
| 542 Bucket bucket(String bucketName, |
| 543 {PredefinedAcl defaultPredefinedObjectAcl, |
| 544 Acl defaultObjectAcl}); |
| 545 |
| 546 /// Check whether a cloud storage bucket exists. |
| 547 /// |
| 548 /// Checks whether the bucket named [bucketName] exists. |
| 549 /// |
| 550 /// Returns a [Future] which completes with `true` if the bucket exists. |
| 551 Future<bool> bucketExists(String bucketName); |
| 552 |
| 553 /// Get information on a bucket |
| 554 /// |
| 555 /// Provide metadata information for bucket named [bucketName]. |
| 556 /// |
| 557 /// Returns a [Future] which completes with a `BuckerInfo` object. |
| 558 Future<BucketInfo> bucketInfo(String bucketName); |
| 559 |
| 560 /// List names of all buckets. |
| 561 /// |
| 562 /// Returns a [Stream] of bucket names. |
| 563 Stream<String> listBucketNames(); |
| 564 |
| 565 /// Start paging through names of all buckets. |
| 566 /// |
| 567 /// The maximum number of buckets in each page is specified in [pageSize]. |
| 568 /// |
| 569 /// Returns a [Future] which completes with a `Page` object holding the |
| 570 /// first page. Use the `Page` object to move to the next page of buckets. |
| 571 Future<Page<String>> pageBucketNames({int pageSize: 50}); |
| 572 |
| 573 /// Copy an object. |
| 574 /// |
| 575 /// Copy object [src] to object [dest]. |
| 576 /// |
| 577 /// The names of [src] and [dest] must be absolute. |
| 578 Future copyObject(String src, String dest); |
| 579 } |
| 580 |
| 581 /// Information on a specific object. |
| 582 /// |
| 583 /// This class provides access to information on an object. This includes |
| 584 /// both the properties which are provided by Cloud Storage (such as the |
| 585 /// MD5 hash) and the properties which can be changed (such as content type). |
| 586 /// |
| 587 /// The properties provided by Cloud Storage are direct properties on this |
| 588 /// object. |
| 589 /// |
| 590 /// The mutable properties are properties on the `metadata` property. |
| 591 abstract class ObjectInfo { |
| 592 /// Name of the object. |
| 593 String get name; |
| 594 |
| 595 /// Length of the data. |
| 596 int get length; |
| 597 |
| 598 /// When this object was updated. |
| 599 DateTime get updated; |
| 600 |
| 601 /// Entity tag for the object. |
| 602 String get etag; |
| 603 |
| 604 /// MD5 hash of the object. |
| 605 List<int> get md5Hash; |
| 606 |
| 607 /// CRC32c checksum, as described in RFC 4960. |
| 608 int get crc32CChecksum; |
| 609 |
| 610 /// URL for direct download. |
| 611 Uri get downloadLink; |
| 612 |
| 613 /// Object generation. |
| 614 ObjectGeneration get generation; |
| 615 |
| 616 /// Additional metadata. |
| 617 ObjectMetadata get metadata; |
| 618 } |
| 619 |
| 620 /// Generational information on an object. |
| 621 class ObjectGeneration { |
| 622 /// Object generation. |
| 623 final String objectGeneration; |
| 624 |
| 625 /// Metadata generation. |
| 626 final int metaGeneration; |
| 627 |
| 628 const ObjectGeneration(this.objectGeneration, this.metaGeneration); |
| 629 } |
| 630 |
| 631 /// Access to object metadata. |
| 632 abstract class ObjectMetadata { |
| 633 factory ObjectMetadata({Acl acl, String contentType, String contentEncoding, |
| 634 String cacheControl, String contentDisposition, String contentLanguage, |
| 635 Map<String, String> custom}) = _ObjectMetadata; |
| 636 /// ACL. |
| 637 Acl get acl; |
| 638 |
| 639 /// `Content-Type` for this object. |
| 640 String get contentType; |
| 641 |
| 642 /// `Content-Encoding` for this object. |
| 643 String get contentEncoding; |
| 644 |
| 645 /// `Cache-Control` for this object. |
| 646 String get cacheControl; |
| 647 |
| 648 /// `Content-Disposition` for this object. |
| 649 String get contentDisposition; |
| 650 |
| 651 /// `Content-Language` for this object. |
| 652 /// |
| 653 /// The value of this field must confirm to RFC 3282. |
| 654 String get contentLanguage; |
| 655 |
| 656 /// Custom metadata. |
| 657 Map<String, String> get custom; |
| 658 |
| 659 /// Create a copy of this object with some values replaced. |
| 660 /// |
| 661 // TODO: This cannot be used to set values to null. |
| 662 ObjectMetadata replace({Acl acl, String contentType, String contentEncoding, |
| 663 String cacheControl, String contentDisposition, String contentLanguage, |
| 664 Map<String, String> custom}); |
| 665 } |
| 666 |
| 667 /// Result from List objects in a bucket. |
| 668 /// |
| 669 /// Listing operate like a directory listing, despite the object |
| 670 /// namespace being flat. |
| 671 /// |
| 672 /// See [Bucket.list] for information on how the hierarchical structure |
| 673 /// is determined. |
| 674 class BucketEntry { |
| 675 /// Whether this is information on an object. |
| 676 final bool isObject; |
| 677 |
| 678 /// Name of object or directory. |
| 679 final String name; |
| 680 |
| 681 BucketEntry._object(this.name) : isObject = true; |
| 682 |
| 683 BucketEntry._directory(this.name) : isObject = false; |
| 684 |
| 685 /// Whether this is a prefix. |
| 686 bool get isDirectory => !isObject; |
| 687 } |
| 688 |
| 689 /// Access to operations on a specific cloud storage buket. |
| 690 abstract class Bucket { |
| 691 /// Name of this bucket. |
| 692 String get bucketName; |
| 693 |
| 694 /// Absolute name of an object in this bucket. This includes the gs:// prefix. |
| 695 String absoluteObjectName(String objectName); |
| 696 |
| 697 /// Create a new object. |
| 698 /// |
| 699 /// Create an object named [objectName] in the bucket. |
| 700 /// |
| 701 /// If an object named [objectName] already exists this object will be |
| 702 /// replaced. |
| 703 /// |
| 704 /// If the length of the data to write is known in advance this can be passed |
| 705 /// as [length]. This can help to optimize the upload process. |
| 706 /// |
| 707 /// Additional metadata on the object can be passed either through the |
| 708 /// `metadata` argument or through the specific named arguments |
| 709 /// (such as `contentType`). Values passed through the specific named |
| 710 /// arguments takes precedence over the values in `metadata`. |
| 711 /// |
| 712 /// If [contentType] is not passed the default value of |
| 713 /// `application/octet-stream` will be used. |
| 714 /// |
| 715 /// It is possible to at one of the predefined ACLs on the created object |
| 716 /// using the [predefinedAcl] argument. If the [metadata] argument contain a |
| 717 /// ACL as well, this ACL with be followed by the expansion of |
| 718 /// [predefinedAcl]. |
| 719 /// |
| 720 /// Returns a `StreamSink` where the object content can be written. When |
| 721 /// The object content has been written the `StreamSink` completes with |
| 722 /// an `ObjectInfo` instance with the information on the object created. |
| 723 StreamSink<List<int>> write(String objectName, |
| 724 {int length, ObjectMetadata metadata, |
| 725 Acl acl, PredefinedAcl predefinedAcl, String contentType}); |
| 726 |
| 727 /// Create an new object in the bucket with specified content. |
| 728 /// |
| 729 /// Writes [bytes] to the created object. |
| 730 /// |
| 731 /// See [write] for more information on the additional arguments. |
| 732 /// |
| 733 /// Returns a `Future` which completes with an `ObjectInfo` instance when |
| 734 /// the object is written. |
| 735 Future<ObjectInfo> writeBytes(String name, List<int> bytes, |
| 736 {ObjectMetadata metadata, |
| 737 Acl acl, PredefinedAcl predefinedAcl, String contentType}); |
| 738 |
| 739 /// Read object content. |
| 740 /// |
| 741 // TODO: More documentation |
| 742 Stream<List<int>> read(String objectName, {int offset: 0, int length}); |
| 743 |
| 744 /// Lookup object metadata. |
| 745 /// |
| 746 // TODO: More documentation |
| 747 Future<ObjectInfo> info(String name); |
| 748 |
| 749 /// Delete an object. |
| 750 /// |
| 751 // TODO: More documentation |
| 752 Future delete(String name); |
| 753 |
| 754 /// Update object metadata. |
| 755 /// |
| 756 // TODO: More documentation |
| 757 Future updateMetadata(String objectName, ObjectMetadata metadata); |
| 758 |
| 759 /// List objects in the bucket. |
| 760 /// |
| 761 /// Listing operates like a directory listing, despite the object |
| 762 /// namespace being flat. The character `/` is being used to separate |
| 763 /// object names into directory components. |
| 764 /// |
| 765 /// Retrieves a list of objects and directory components starting |
| 766 /// with [prefix]. |
| 767 /// |
| 768 /// Returns a [Stream] of [BucketEntry]. Each element of the stream |
| 769 /// represents either an object or a directory component. |
| 770 Stream<BucketEntry> list({String prefix}); |
| 771 |
| 772 /// Start paging through objects in the bucket. |
| 773 /// |
| 774 /// The maximum number of objects in each page is specified in [pageSize]. |
| 775 /// |
| 776 /// See [list] for more information on the other arguments. |
| 777 /// |
| 778 /// Returns a `Future` which completes with a `Page` object holding the |
| 779 /// first page. Use the `Page` object to move to the next page. |
| 780 Future<Page<BucketEntry>> page({String prefix, int pageSize: 50}); |
| 781 } |
OLD | NEW |