Index: pkg/gcloud/lib/storage.dart |
diff --git a/pkg/gcloud/lib/storage.dart b/pkg/gcloud/lib/storage.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..35f7a85d1c351752ec92ca195897ec904de014a3 |
--- /dev/null |
+++ b/pkg/gcloud/lib/storage.dart |
@@ -0,0 +1,781 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+/// This library provides access to Google Cloud Storage. |
+/// |
+/// Google Cloud Storage is an object store for binary objects. Each |
+/// object has a set of metadata attached to it. For more information on |
+/// Google Cloud Sorage see https://developers.google.com/storage/. |
+/// |
+/// There are two main concepts in Google Cloud Storage: Buckets and Objects. |
+/// A bucket is a container for objects and objects are the actual binary |
+/// objects. |
+/// |
+/// The API has two main classes for dealing with buckets and objects. |
+/// |
+/// The class `Storage` is the main API class providing access to working |
+/// with buckets. This is the 'bucket service' interface. |
+/// |
+/// The class `Bucket` provide access to working with objcts in a specific |
+/// bucket. This is the 'object service' interface. |
+/// |
+/// Both buckets have objects, have names. The bucket namespace is flat and |
+/// global across all projects. This means that a bucket is always |
+/// addressable using its name without requiring further context. |
+/// |
+/// Within buckets the object namespace is also flat. Object are *not* |
+/// organized hierachical. However, as object names allow the slash `/` |
+/// character this is often used to simulate a hierachical structure |
+/// based on common prefixes. |
+/// |
+/// This package uses relative and absolute names to refer to objects. A |
+/// relative name is just the object name within a bucket, and requires the |
+/// context of a bucket to be used. A relative name just looks like this: |
+/// |
+/// object_name |
+/// |
+/// An absolute name includes the bucket name and uses the `gs://` prefix |
+/// also used by the `gsutil` tool. An absolute name looks like this. |
+/// |
+/// gs://bucket_name/object_name |
+/// |
+/// In most cases relative names are used. Absolute names are typically |
+/// only used for operations involving objects in different buckets. |
+/// |
+/// For most of the APIs in ths library which take instances of other classes |
+/// from this library it is the assumption that the actual implementations |
+/// provided here are used. |
+library gcloud.storage; |
+ |
+import 'dart:async'; |
+import 'dart:collection' show UnmodifiableListView, UnmodifiableMapView; |
+ |
+import 'package:http/http.dart' as http; |
+ |
+import 'package:crypto/crypto.dart' as crypto; |
+import 'package:googleapis/storage/v1.dart' as storage_api; |
+import 'package:googleapis/common/common.dart' as common; |
+ |
+import 'service_scope.dart' as ss; |
+ |
+import 'common.dart'; |
+export 'common.dart'; |
+ |
+part 'src/storage_impl.dart'; |
+ |
+const Symbol _storageKey = #_gcloud.storage; |
+ |
+/// Access the [Storage] object available in the current service scope. |
+/// |
+/// The returned object will be the one which was previously registered with |
+/// [registerStorageService] within the current (or a parent) service scope. |
+/// |
+/// Accessing this getter outside of a service scope will result in an error. |
+/// See the `package:gcloud/service_scope.dart` library for more information. |
+Storage get storageService => ss.lookup(_storageKey); |
+ |
+/// Registers the [storage] object within the current service scope. |
+/// |
+/// The provided `storage` object will be avilable via the top-level `storage` |
+/// getter. |
+/// |
+/// Calling this function outside of a service scope will result in an error. |
+/// Calling this function more than once inside the same service scope is not |
+/// allowed. |
+void registerStorageService(Storage storage) { |
+ ss.register(_storageKey, storage); |
+} |
+ |
+int _jenkinsHash(List e) { |
+ const _HASH_MASK = 0x3fffffff; |
+ int hash = 0; |
+ for (int i = 0; i < e.length; i++) { |
+ int c = e[i].hashCode; |
+ hash = (hash + c) & _HASH_MASK; |
+ hash = (hash + (hash << 10)) & _HASH_MASK; |
+ hash ^= (hash >> 6); |
+ } |
+ hash = (hash + (hash << 3)) & _HASH_MASK; |
+ hash ^= (hash >> 11); |
+ hash = (hash + (hash << 15)) & _HASH_MASK; |
+ return hash; |
+} |
+ |
+/// An ACL (Access Control List) describes access rights to buckets and |
+/// objects. |
+/// |
+/// An ACL is a prioritized sequence of access control specifications, |
+/// which individually prevent or grant access. |
+/// The access controls are described by [AclEntry] objects. |
+class Acl { |
+ final List<AclEntry> _entries; |
+ int _cachedHashCode; |
+ |
+ /// The entries in the ACL. |
+ List<AclEntry> get entries => new UnmodifiableListView<AclEntry>(_entries); |
+ |
+ /// Create a new ACL with a list of ACL entries. |
+ Acl(Iterable<AclEntry> entries) : _entries = new List.from(entries); |
+ |
+ Acl._fromBucketAcl(storage_api.Bucket bucket) |
+ : _entries = new List(bucket.acl == null ? 0 : bucket.acl.length) { |
+ if (bucket.acl != null) { |
+ for (int i = 0; i < bucket.acl.length; i++) { |
+ _entries[i] = new AclEntry(_aclScopeFromEntity(bucket.acl[i].entity), |
+ _aclPermissionFromRole(bucket.acl[i].role)); |
+ } |
+ } |
+ } |
+ |
+ Acl._fromObjectAcl(storage_api.Object object) |
+ : _entries = new List(object.acl == null ? 0 : object.acl.length) { |
+ if (object.acl != null) { |
+ for (int i = 0; i < object.acl.length; i++) { |
+ _entries[i] = new AclEntry(_aclScopeFromEntity(object.acl[i].entity), |
+ _aclPermissionFromRole(object.acl[i].role)); |
+ } |
+ } |
+ } |
+ |
+ AclScope _aclScopeFromEntity(String entity) { |
+ if (entity.startsWith('user-')) { |
+ String tmp = entity.substring(5); |
+ int at = tmp.indexOf('@'); |
+ if (at != -1) { |
+ return new AccountScope(tmp); |
+ } else { |
+ return new StorageIdScope(tmp); |
+ } |
+ } else if (entity.startsWith('group-')) { |
+ return new GroupScope(entity.substring(6)); |
+ } else if (entity.startsWith('domain-')) { |
+ return new DomainScope(entity.substring(7)); |
+ } else if (entity.startsWith('allAuthenticatedUsers-')) { |
+ return AclScope.allAuthenticated; |
+ } else if (entity.startsWith('allUsers-')) { |
+ return AclScope.allUsers; |
+ } else if (entity.startsWith('project-')) { |
+ String tmp = entity.substring(8); |
+ int dash = tmp.indexOf('-'); |
+ if (dash != -1) { |
+ return new ProjectScope(tmp.substring(dash + 1), |
+ tmp.substring(0, dash)); |
+ } |
+ } |
+ return new OpaqueScope(entity); |
+ } |
+ |
+ AclPermission _aclPermissionFromRole(String role) { |
+ if (role == 'READER') return AclPermission.READ; |
+ if (role == 'WRITER') return AclPermission.WRITE; |
+ if (role == 'OWNER') return AclPermission.FULL_CONTROL; |
+ throw new UnsupportedError( |
+ "Server returned a unsupported permission role '$role'"); |
+ } |
+ |
+ List<storage_api.BucketAccessControl> _toBucketAccessControlList() { |
+ return _entries.map((entry) => entry._toBucketAccessControl()).toList(); |
+ } |
+ |
+ List<storage_api.ObjectAccessControl> _toObjectAccessControlList() { |
+ return _entries.map((entry) => entry._toObjectAccessControl()).toList(); |
+ } |
+ |
+ int get hashCode { |
+ return _cachedHashCode != null |
+ ? _cachedHashCode |
+ : _cachedHashCode = _jenkinsHash(_entries); |
+ } |
+ |
+ bool operator==(Object other) { |
+ if (other is Acl) { |
+ List entries = _entries; |
+ List otherEntries = other._entries; |
+ if (entries.length != otherEntries.length) return false; |
+ for (int i = 0; i < entries.length; i++) { |
+ if (entries[i] != otherEntries[i]) return false; |
+ } |
+ return true; |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
+ String toString() => 'Acl($_entries)'; |
+} |
+ |
+/// An ACL entry specifies that an entity has a specific access permission. |
+/// |
+/// A permission grants a specific permission to the entity. |
+class AclEntry { |
+ final AclScope scope; |
+ final AclPermission permission; |
+ int _cachedHashCode; |
+ |
+ AclEntry(this.scope, this.permission); |
+ |
+ storage_api.BucketAccessControl _toBucketAccessControl() { |
+ var acl = new storage_api.BucketAccessControl(); |
+ acl.entity = scope._storageEntity; |
+ acl.role = permission._storageBucketRole; |
+ return acl; |
+ } |
+ |
+ storage_api.ObjectAccessControl _toObjectAccessControl() { |
+ var acl = new storage_api.ObjectAccessControl(); |
+ acl.entity = scope._storageEntity; |
+ acl.role = permission._storageObjectRole; |
+ return acl; |
+ } |
+ |
+ int get hashCode { |
+ return _cachedHashCode != null |
+ ? _cachedHashCode |
+ : _cachedHashCode = _jenkinsHash([scope, permission]); |
+ } |
+ |
+ bool operator==(Object other) { |
+ return other is AclEntry && |
+ scope == other.scope && |
+ permission == other.permission; |
+ } |
+ |
+ String toString() => 'AclEntry($scope, $permission)'; |
+} |
+ |
+/// An ACL scope specifies an entity for which a permission applies. |
+/// |
+/// A scope can be one of: |
+/// |
+/// * Google Storage ID |
+/// * Google account email address |
+/// * Google group email address |
+/// * Google Apps domain |
+/// * Special identifier for all Google account holders |
+/// * Special identifier for all users |
+/// |
+/// See https://cloud.google.com/storage/docs/accesscontrol for more details. |
+abstract class AclScope { |
+ int _cachedHashCode; |
+ |
+ /// ACL type for scope representing a Google Storage id. |
+ static const int _TYPE_STORAGE_ID = 0; |
+ |
+ /// ACL type for scope representing a project entity. |
+ static const int _TYPE_PROJECT = 1; |
+ |
+ /// ACL type for scope representing an account holder. |
+ static const int _TYPE_ACCOUNT = 2; |
+ |
+ /// ACL type for scope representing a group. |
+ static const int _TYPE_GROUP = 3; |
+ |
+ /// ACL type for scope representing a domain. |
+ static const int _TYPE_DOMAIN = 4; |
+ |
+ /// ACL type for scope representing all authenticated users. |
+ static const int _TYPE_ALL_AUTHENTICATED = 5; |
+ |
+ /// ACL type for scope representing all users. |
+ static const int _TYPE_ALL_USERS = 6; |
+ |
+ /// ACL type for scope representing an unsupported scope. |
+ static const int _TYPE_OPAQUE = 7; |
+ |
+ /// The id of the actual entity this ACL scope represents. The actual values |
+ /// are set in the different subclasses. |
+ final String _id; |
+ |
+ /// The type of this acope this ACL scope represents. |
+ final int _type; |
+ |
+ /// ACL scope for all authenticated users. |
+ static AllAuthenticatedScope allAuthenticated = new AllAuthenticatedScope(); |
+ |
+ /// ACL scope for all users. |
+ static AllUsersScope allUsers = new AllUsersScope(); |
+ |
+ AclScope._(this._type, this._id); |
+ |
+ int get hashCode { |
+ return _cachedHashCode != null |
+ ? _cachedHashCode |
+ : _cachedHashCode = _jenkinsHash([_type, _id]); |
+ } |
+ |
+ bool operator==(Object other) { |
+ return other is AclScope && _type == other._type && _id == other._id; |
+ } |
+ |
+ String toString() => 'AclScope($_storageEntity)'; |
+ |
+ String get _storageEntity; |
+} |
+ |
+/// An ACL scope for an entity identified by a 'Google Storage ID'. |
+/// |
+/// The [storageId] is a string of 64 hexadecimal digits that identifies a |
+/// specific Google account holder or a specific Google group. |
+class StorageIdScope extends AclScope { |
+ StorageIdScope(String storageId) |
+ : super._(AclScope._TYPE_STORAGE_ID, storageId); |
+ |
+ /// Google Storage ID. |
+ String get storageId => _id; |
+ |
+ String get _storageEntity => 'user-$_id'; |
+} |
+ |
+/// An ACL scope for an entity identified by an individual email address. |
+class AccountScope extends AclScope { |
+ AccountScope(String email): super._(AclScope._TYPE_ACCOUNT, email); |
+ |
+ /// Email address. |
+ String get email => _id; |
+ |
+ String get _storageEntity => 'user-$_id'; |
+} |
+ |
+/// An ACL scope for an entity identified by an Google Groups email. |
+class GroupScope extends AclScope { |
+ GroupScope(String group): super._(AclScope._TYPE_GROUP, group); |
+ |
+ /// Group name. |
+ String get group => _id; |
+ |
+ String get _storageEntity => 'group-$_id'; |
+} |
+ |
+/// An ACL scope for an entity identified by a domain name. |
+class DomainScope extends AclScope { |
+ DomainScope(String domain): super._(AclScope._TYPE_DOMAIN, domain); |
+ |
+ /// Domain name. |
+ String get domain => _id; |
+ |
+ String get _storageEntity => 'domain-$_id'; |
+} |
+ |
+/// An ACL scope for an project related entity. |
+class ProjectScope extends AclScope { |
+ /// Project role. |
+ /// |
+ /// Possible values are `owners`, `editors` and `viewers`. |
+ final String role; |
+ |
+ ProjectScope(String project, String this.role) |
+ : super._(AclScope._TYPE_PROJECT, project); |
+ |
+ /// Project ID. |
+ String get project => _id; |
+ |
+ String get _storageEntity => 'project-$role-$_id'; |
+} |
+ |
+/// An ACL scope for an unsupported scope. |
+class OpaqueScope extends AclScope { |
+ OpaqueScope(String id) : super._(AclScope._TYPE_OPAQUE, id); |
+ |
+ String get _storageEntity => _id; |
+} |
+ |
+/// ACL scope for a all authenticated users. |
+class AllAuthenticatedScope extends AclScope { |
+ AllAuthenticatedScope() |
+ : super._(AclScope._TYPE_ALL_AUTHENTICATED, null); |
+ |
+ String get _storageEntity => 'allAuthenticatedUsers'; |
+} |
+ |
+/// ACL scope for a all users. |
+class AllUsersScope extends AclScope { |
+ AllUsersScope(): super._(AclScope._TYPE_ALL_USERS, null); |
+ |
+ String get _storageEntity => 'allUsers'; |
+} |
+ |
+/// Permissions for individual scopes in an ACL. |
+class AclPermission { |
+ /// Provide read access. |
+ static const READ = const AclPermission._('READER'); |
+ |
+ /// Provide write access. |
+ /// |
+ /// For objects this permission is the same as [FULL_CONTROL]. |
+ static const WRITE = const AclPermission._('WRITER'); |
+ |
+ /// Provide full control. |
+ /// |
+ /// For objects this permission is the same as [WRITE]. |
+ static const FULL_CONTROL = const AclPermission._('OWNER'); |
+ |
+ final String _id; |
+ |
+ const AclPermission._(this._id); |
+ |
+ String get _storageBucketRole => _id; |
+ |
+ String get _storageObjectRole => this == WRITE ? FULL_CONTROL._id : _id; |
+ |
+ int get hashCode => _id.hashCode; |
+ |
+ bool operator==(Object other) { |
+ return other is AclPermission && _id == other._id; |
+ } |
+ |
+ String toString() => 'AclPermission($_id)'; |
+} |
+ |
+/// Definition of predefined ACLs. |
+/// |
+/// There is a convenient way of referring to number of _predefined_ ACLs. These |
+/// predefined ACLs have explicit names, and can _only_ be used to set an ACL, |
+/// when either creating or updating a bucket or object. This set of predefined |
+/// ACLs are expanded on the server to their actual list of [AclEntry] objects. |
+/// When information is retreived on a bucket or object, this expanded list will |
+/// be present. For a description of these predefined ACLs see: |
+/// https://cloud.google.com/storage/docs/accesscontrol#extension. |
+class PredefinedAcl { |
+ final String _name; |
+ const PredefinedAcl._(this._name); |
+ |
+ /// Predefined ACL for the 'authenticated-read' ACL. Applies to both buckets |
+ /// and objects. |
+ static const PredefinedAcl authenticatedRead = |
+ const PredefinedAcl._('authenticatedRead'); |
+ |
+ /// Predefined ACL for the 'private' ACL. Applies to both buckets |
+ /// and objects. |
+ static const PredefinedAcl private = const PredefinedAcl._('private'); |
+ |
+ /// Predefined ACL for the 'project-private' ACL. Applies to both buckets |
+ /// and objects. |
+ static const PredefinedAcl projectPrivate = |
+ const PredefinedAcl._('projectPrivate'); |
+ |
+ /// Predefined ACL for the 'public-read' ACL. Applies to both buckets |
+ /// and objects. |
+ static const PredefinedAcl publicRead = const PredefinedAcl._('publicRead'); |
+ |
+ /// Predefined ACL for the 'public-read-write' ACL. Applies only to buckets. |
+ static const PredefinedAcl publicReadWrite = |
+ const PredefinedAcl._('publicReadWrite'); |
+ |
+ /// Predefined ACL for the 'bucket-owner-full-control' ACL. Applies only to |
+ /// objects. |
+ static const PredefinedAcl bucketOwnerFullControl = |
+ const PredefinedAcl._('bucketOwnerFullControl'); |
+ |
+ /// Predefined ACL for the 'bucket-owner-read' ACL. Applies only to |
+ /// objects. |
+ static const PredefinedAcl bucketOwnerRead = |
+ const PredefinedAcl._('bucketOwnerRead'); |
+ |
+ String toString() => 'PredefinedAcl($_name)'; |
+} |
+ |
+/// Information on a bucket. |
+abstract class BucketInfo { |
+ /// Name of the bucket. |
+ String get bucketName; |
+ |
+ /// Entity tag for the bucket. |
+ String get etag; |
+ |
+ /// When this bucket was created. |
+ DateTime get created; |
+ |
+ /// Bucket ID. |
+ String get id; |
+ |
+ /// Acl of the bucket. |
+ Acl get acl; |
+} |
+ |
+/// Access to Cloud Storage |
+abstract class Storage { |
+ /// List of required OAuth2 scopes for Cloud Storage operation. |
+ static const List<String> SCOPES = |
+ const <String>[storage_api.StorageApi.DevstorageFullControlScope]; |
+ |
+ /// Initializes access to cloud storage. |
+ factory Storage(http.Client client, String project) = _StorageImpl; |
+ |
+ /// Create a cloud storage bucket. |
+ /// |
+ /// Creates a cloud storage bucket named [bucketName]. |
+ /// |
+ /// The bucket ACL can be set by passing [predefinedAcl] or [acl]. If both |
+ /// are passed the entries from [acl] with be followed by the expansion of |
+ /// [predefinedAcl]. |
+ /// |
+ /// Returns a [Future] which completes when the bucket has been created. |
+ Future createBucket(String bucketName, |
+ {PredefinedAcl predefinedAcl, Acl acl}); |
+ |
+ /// Delete a cloud storage bucket. |
+ /// |
+ /// Deletes the cloud storage bucket named [bucketName]. |
+ /// |
+ /// If the bucket is not empty the operation will fail. |
+ /// |
+ /// The returned [Future] completes when the operation is finished. |
+ Future deleteBucket(String bucketName); |
+ |
+ /// Access bucket object operations. |
+ /// |
+ /// Instantiates a `Bucket` object refering to the bucket named [bucketName]. |
+ /// |
+ /// When an object is created using the resulting `Bucket` an ACL will always |
+ /// be set. If the object creation does not pass any explicit ACL information |
+ /// a default ACL will be used. |
+ /// |
+ /// If the arguments [defaultPredefinedObjectAcl] or [defaultObjectAcl] are |
+ /// passed they define the default ACL. If both are passed the entries from |
+ /// [defaultObjectAcl] with be followed by the expansion of |
+ /// [defaultPredefinedObjectAcl] when an object is created. |
+ /// |
+ /// Otherwise the default object ACL attached to the bucket will be used. |
+ /// |
+ /// Returns a `Bucket` instance. |
+ Bucket bucket(String bucketName, |
+ {PredefinedAcl defaultPredefinedObjectAcl, |
+ Acl defaultObjectAcl}); |
+ |
+ /// Check whether a cloud storage bucket exists. |
+ /// |
+ /// Checks whether the bucket named [bucketName] exists. |
+ /// |
+ /// Returns a [Future] which completes with `true` if the bucket exists. |
+ Future<bool> bucketExists(String bucketName); |
+ |
+ /// Get information on a bucket |
+ /// |
+ /// Provide metadata information for bucket named [bucketName]. |
+ /// |
+ /// Returns a [Future] which completes with a `BuckerInfo` object. |
+ Future<BucketInfo> bucketInfo(String bucketName); |
+ |
+ /// List names of all buckets. |
+ /// |
+ /// Returns a [Stream] of bucket names. |
+ Stream<String> listBucketNames(); |
+ |
+ /// Start paging through names of all buckets. |
+ /// |
+ /// The maximum number of buckets in each page is specified in [pageSize]. |
+ /// |
+ /// Returns a [Future] which completes with a `Page` object holding the |
+ /// first page. Use the `Page` object to move to the next page of buckets. |
+ Future<Page<String>> pageBucketNames({int pageSize: 50}); |
+ |
+ /// Copy an object. |
+ /// |
+ /// Copy object [src] to object [dest]. |
+ /// |
+ /// The names of [src] and [dest] must be absolute. |
+ Future copyObject(String src, String dest); |
+} |
+ |
+/// Information on a specific object. |
+/// |
+/// This class provides access to information on an object. This includes |
+/// both the properties which are provided by Cloud Storage (such as the |
+/// MD5 hash) and the properties which can be changed (such as content type). |
+/// |
+/// The properties provided by Cloud Storage are direct properties on this |
+/// object. |
+/// |
+/// The mutable properties are properties on the `metadata` property. |
+abstract class ObjectInfo { |
+ /// Name of the object. |
+ String get name; |
+ |
+ /// Length of the data. |
+ int get length; |
+ |
+ /// When this object was updated. |
+ DateTime get updated; |
+ |
+ /// Entity tag for the object. |
+ String get etag; |
+ |
+ /// MD5 hash of the object. |
+ List<int> get md5Hash; |
+ |
+ /// CRC32c checksum, as described in RFC 4960. |
+ int get crc32CChecksum; |
+ |
+ /// URL for direct download. |
+ Uri get downloadLink; |
+ |
+ /// Object generation. |
+ ObjectGeneration get generation; |
+ |
+ /// Additional metadata. |
+ ObjectMetadata get metadata; |
+} |
+ |
+/// Generational information on an object. |
+class ObjectGeneration { |
+ /// Object generation. |
+ final String objectGeneration; |
+ |
+ /// Metadata generation. |
+ final int metaGeneration; |
+ |
+ const ObjectGeneration(this.objectGeneration, this.metaGeneration); |
+} |
+ |
+/// Access to object metadata. |
+abstract class ObjectMetadata { |
+ factory ObjectMetadata({Acl acl, String contentType, String contentEncoding, |
+ String cacheControl, String contentDisposition, String contentLanguage, |
+ Map<String, String> custom}) = _ObjectMetadata; |
+ /// ACL. |
+ Acl get acl; |
+ |
+ /// `Content-Type` for this object. |
+ String get contentType; |
+ |
+ /// `Content-Encoding` for this object. |
+ String get contentEncoding; |
+ |
+ /// `Cache-Control` for this object. |
+ String get cacheControl; |
+ |
+ /// `Content-Disposition` for this object. |
+ String get contentDisposition; |
+ |
+ /// `Content-Language` for this object. |
+ /// |
+ /// The value of this field must confirm to RFC 3282. |
+ String get contentLanguage; |
+ |
+ /// Custom metadata. |
+ Map<String, String> get custom; |
+ |
+ /// Create a copy of this object with some values replaced. |
+ /// |
+ // TODO: This cannot be used to set values to null. |
+ ObjectMetadata replace({Acl acl, String contentType, String contentEncoding, |
+ String cacheControl, String contentDisposition, String contentLanguage, |
+ Map<String, String> custom}); |
+} |
+ |
+/// Result from List objects in a bucket. |
+/// |
+/// Listing operate like a directory listing, despite the object |
+/// namespace being flat. |
+/// |
+/// See [Bucket.list] for information on how the hierarchical structure |
+/// is determined. |
+class BucketEntry { |
+ /// Whether this is information on an object. |
+ final bool isObject; |
+ |
+ /// Name of object or directory. |
+ final String name; |
+ |
+ BucketEntry._object(this.name) : isObject = true; |
+ |
+ BucketEntry._directory(this.name) : isObject = false; |
+ |
+ /// Whether this is a prefix. |
+ bool get isDirectory => !isObject; |
+} |
+ |
+/// Access to operations on a specific cloud storage buket. |
+abstract class Bucket { |
+ /// Name of this bucket. |
+ String get bucketName; |
+ |
+ /// Absolute name of an object in this bucket. This includes the gs:// prefix. |
+ String absoluteObjectName(String objectName); |
+ |
+ /// Create a new object. |
+ /// |
+ /// Create an object named [objectName] in the bucket. |
+ /// |
+ /// If an object named [objectName] already exists this object will be |
+ /// replaced. |
+ /// |
+ /// If the length of the data to write is known in advance this can be passed |
+ /// as [length]. This can help to optimize the upload process. |
+ /// |
+ /// Additional metadata on the object can be passed either through the |
+ /// `metadata` argument or through the specific named arguments |
+ /// (such as `contentType`). Values passed through the specific named |
+ /// arguments takes precedence over the values in `metadata`. |
+ /// |
+ /// If [contentType] is not passed the default value of |
+ /// `application/octet-stream` will be used. |
+ /// |
+ /// It is possible to at one of the predefined ACLs on the created object |
+ /// using the [predefinedAcl] argument. If the [metadata] argument contain a |
+ /// ACL as well, this ACL with be followed by the expansion of |
+ /// [predefinedAcl]. |
+ /// |
+ /// Returns a `StreamSink` where the object content can be written. When |
+ /// The object content has been written the `StreamSink` completes with |
+ /// an `ObjectInfo` instance with the information on the object created. |
+ StreamSink<List<int>> write(String objectName, |
+ {int length, ObjectMetadata metadata, |
+ Acl acl, PredefinedAcl predefinedAcl, String contentType}); |
+ |
+ /// Create an new object in the bucket with specified content. |
+ /// |
+ /// Writes [bytes] to the created object. |
+ /// |
+ /// See [write] for more information on the additional arguments. |
+ /// |
+ /// Returns a `Future` which completes with an `ObjectInfo` instance when |
+ /// the object is written. |
+ Future<ObjectInfo> writeBytes(String name, List<int> bytes, |
+ {ObjectMetadata metadata, |
+ Acl acl, PredefinedAcl predefinedAcl, String contentType}); |
+ |
+ /// Read object content. |
+ /// |
+ // TODO: More documentation |
+ Stream<List<int>> read(String objectName, {int offset: 0, int length}); |
+ |
+ /// Lookup object metadata. |
+ /// |
+ // TODO: More documentation |
+ Future<ObjectInfo> info(String name); |
+ |
+ /// Delete an object. |
+ /// |
+ // TODO: More documentation |
+ Future delete(String name); |
+ |
+ /// Update object metadata. |
+ /// |
+ // TODO: More documentation |
+ Future updateMetadata(String objectName, ObjectMetadata metadata); |
+ |
+ /// List objects in the bucket. |
+ /// |
+ /// Listing operates like a directory listing, despite the object |
+ /// namespace being flat. The character `/` is being used to separate |
+ /// object names into directory components. |
+ /// |
+ /// Retrieves a list of objects and directory components starting |
+ /// with [prefix]. |
+ /// |
+ /// Returns a [Stream] of [BucketEntry]. Each element of the stream |
+ /// represents either an object or a directory component. |
+ Stream<BucketEntry> list({String prefix}); |
+ |
+ /// Start paging through objects in the bucket. |
+ /// |
+ /// The maximum number of objects in each page is specified in [pageSize]. |
+ /// |
+ /// See [list] for more information on the other arguments. |
+ /// |
+ /// Returns a `Future` which completes with a `Page` object holding the |
+ /// first page. Use the `Page` object to move to the next page. |
+ Future<Page<BucketEntry>> page({String prefix, int pageSize: 50}); |
+} |