Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement stream wrapper for gs:// #323

Merged
merged 67 commits into from
Feb 22, 2017
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
98cf841
Create Storage\StreamWrapper implementation that handles reads.
chingor13 Jan 20, 2017
5bff096
Fix php style guideline errors
chingor13 Jan 24, 2017
40ae470
Fix the remaining php coding standard errors.
chingor13 Jan 24, 2017
a9a5d08
Fix php 5.6 errors
chingor13 Jan 24, 2017
9f109ce
Fix travis errors
chingor13 Jan 24, 2017
e596ca9
Remove variadic from StreamableUploader. It is not compatible with ph…
chingor13 Jan 24, 2017
1e8f14c
Throw a RuntimeException instead of dying if the StreamWrapper fails …
chingor13 Jan 24, 2017
9e41cc3
Fix throwing of RuntimeException
chingor13 Jan 24, 2017
4dc989c
Move Storage namespaced functions to static methods on StorageClient.
chingor13 Jan 24, 2017
f8a3f19
Use static functions on StorageClient to get/set the default client.
chingor13 Jan 25, 2017
45a4641
StreamWrapper will maintain its default StorageClient as a static var…
chingor13 Jan 25, 2017
77d0d6e
Implement StorageClient#registerAsStreamWrapper().
chingor13 Jan 25, 2017
09a4ffe
Add documentation do StreamWrapper public functions
chingor13 Jan 25, 2017
18be73d
Catch ServiceExceptions instead of all GoogleExceptions
chingor13 Jan 25, 2017
41fcb84
Pass the original exception to the re-raised GoogleException when a s…
chingor13 Jan 25, 2017
2456d51
Fix stream wrapper checking array key for options
chingor13 Jan 25, 2017
435cc1e
check array_key_exists on reading options
chingor13 Jan 25, 2017
ba65eec
move codingStandardsIgnoreStart before the documentation for the stre…
chingor13 Jan 25, 2017
819e8b9
Fix documentation on registering a StorageClient as a stream wrapper.
chingor13 Jan 25, 2017
0c6944c
Fix building of docs for StreamWrapper class
chingor13 Jan 25, 2017
d86565b
Fix StreamWrapper loading of options from stream context in hhvm.
chingor13 Jan 25, 2017
52da349
Register the StorageClient with the protocol when registering a strea…
chingor13 Jan 26, 2017
0d7c111
Fix documentation for StreamWrapper getClient() and register()
chingor13 Jan 26, 2017
afa9463
Fix RuntimeException namespace
chingor13 Jan 26, 2017
54331aa
Remove getOption() which is no longer needed
chingor13 Jan 26, 2017
0947bcc
Declare StreamableUploader constructor parameters.
chingor13 Jan 26, 2017
22afe3d
Can't use string type hints with defaults for php5 and hhvm
chingor13 Jan 26, 2017
1f98977
Stream the read when using the StreamWrapper
chingor13 Jan 26, 2017
8547f8c
Fix code standard for test
chingor13 Jan 26, 2017
0adaa6c
Improve description of possible types for StreamableUploader#write()
chingor13 Jan 26, 2017
9d15b16
Fix README registerStreamWrapper()
chingor13 Jan 27, 2017
e06f6b5
Removing type hints for non-object types
chingor13 Feb 2, 2017
1bb0d3e
No need to lazy load or store options from context. Just read it once…
chingor13 Feb 2, 2017
06239b8
Namespace fixes to clean up code
chingor13 Feb 2, 2017
443cbf6
Implement mkdir, rmdir, unlink, url_stat callbacks. Adding tests for …
chingor13 Feb 3, 2017
6d9a37d
Need to get the size of the stream since we are streaming our reads f…
chingor13 Feb 3, 2017
0f99982
We don't need to implement stream_cast for now. It doesn't seem to ma…
chingor13 Feb 3, 2017
d3285bd
Implement the directory callbacks and seek
chingor13 Feb 3, 2017
dafddee
Implement rename
chingor13 Feb 4, 2017
4cccbe1
Fix CS for naming conventions
chingor13 Feb 4, 2017
9f08da9
Fix tests for rewinding a directory
chingor13 Feb 7, 2017
ab3a844
Handle the stream_open option flags. Add documentation about the allo…
chingor13 Feb 8, 2017
78ee793
Wrap download stream in a CachingStream if it must be seekable (getim…
chingor13 Feb 13, 2017
54adf94
Fix reference to debugging stream
chingor13 Feb 13, 2017
85da2f3
Fix code style for isSeekable
chingor13 Feb 13, 2017
082dfc3
Implement url_stat
chingor13 Feb 14, 2017
890f55d
Split buffering from the StreamableUploader into a WriteStream class …
chingor13 Feb 15, 2017
cd8ebfb
Add system tests for stream wrapper operations
chingor13 Feb 15, 2017
e0d4ea6
Fix image test
chingor13 Feb 15, 2017
a8c405a
Cannot use an array for constants
chingor13 Feb 15, 2017
5953f81
Fix unit tests to reflect mocks for refactored streams
chingor13 Feb 15, 2017
dd5ace8
Fixing system tests for url_stat for a directory without any files
chingor13 Feb 15, 2017
e520ba5
Fix codestyle indentation issues.
chingor13 Feb 15, 2017
9aa563d
Force our ReadStream to return the number of bytes requested.
chingor13 Feb 15, 2017
67f19f0
Documentation updates. Group private functions together.
chingor13 Feb 16, 2017
9d2cfd4
Add custom phpcs ruleset.
chingor13 Feb 16, 2017
c1b5371
Merge remote-tracking branch 'upstream/master' into gcs_stream_wrapper
chingor13 Feb 16, 2017
2fb8bb6
Updating docs for comments
chingor13 Feb 21, 2017
2b78220
ReadStream documentation updates
chingor13 Feb 21, 2017
7591391
Handle Service exceptions when listing directories
chingor13 Feb 21, 2017
f66c80a
rmdir now will attempt to delete the bucket if the path is '/'
chingor13 Feb 21, 2017
201d95f
Fix redefinition of method
chingor13 Feb 21, 2017
c2e8375
Put the rename function back which was accidentally stomped
chingor13 Feb 21, 2017
4826581
StreamWrapper can create the bucket and respect the specified mode.
chingor13 Feb 21, 2017
1b2654c
Handle service exceptions when renaming files/directories
chingor13 Feb 21, 2017
7bd960c
Can specify the chunkSize of the streaming upload via stream context.
chingor13 Feb 21, 2017
937541e
Bucket->isWritable will now expect a 403 access denied.
chingor13 Feb 22, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,21 @@ $object = $bucket->object('file_backup.txt');
$object->downloadToFile('/data/file_backup.txt');
```

#### Stream Wrapper

```php
require 'vendor/autoload.php';

use Google\Cloud\Storage\StorageClient;

$storage = new StorageClient([
'projectId' => 'my_project'

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

]);
$storage->registerAsStreamWrapper();

This comment was marked as spam.

This comment was marked as spam.


$contents = file_get_contents('gs://my_bucket/file_backup.txt');
```

## Google Cloud Translation (Alpha)

- [API Documentation](http://googlecloudplatform.github.io/google-cloud-php/#/docs/latest/translate/translateclient)
Expand Down
68 changes: 68 additions & 0 deletions src/Storage/Bucket.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,74 @@ public function getResumableUploader($data, array $options = [])
);
}

/**
* Get a streamable uploader which can provide greater control over the
* upload process. This is useful for generating large files and uploading
* the contents in chunks.
*
* Example:
* ```
* $uploader = $bucket->getStreamableUploader(
* "initial contents",

This comment was marked as spam.

* ['name' => 'data.txt']
* );
*
* $uploader->write('some line');

This comment was marked as spam.

* $uploader->write('more data');
* // finish uploading the item
* $uploader->upload();
* ```
*
* @see https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable Learn more about resumable
* uploads.
* @see https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects insert API documentation.
*
* @param string|resource|StreamInterface $data The data to be uploaded.
* @param array $options [optional] {
* Configuration options.
*
* @type string $name The name of the destination.
* @type bool $validate Indicates whether or not validation will be
* applied using md5 hashing functionality. If true and the
* calculated hash does not match that of the upstream server the
* upload will be rejected.
* @type int $chunkSize If provided the upload will be done in chunks.

This comment was marked as spam.

* The size must be in multiples of 262144 bytes. With chunking
* you have increased reliability at the risk of higher overhead.
* It is recommended to not use chunking.
* @type string $predefinedAcl Predefined ACL to apply to the object.
* Acceptable values include `"authenticatedRead`",
* `"bucketOwnerFullControl`", `"bucketOwnerRead`", `"private`",
* `"projectPrivate`", and `"publicRead"`.
* @type array $metadata The available options for metadata are outlined
* at the [JSON API docs](https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request-body).
* @type string $encryptionKey A base64 encoded AES-256 customer-supplied
* encryption key.
* @type string $encryptionKeySHA256 Base64 encoded SHA256 hash of the
* customer-supplied encryption key. This value will be calculated
* from the `encryptionKey` on your behalf if not provided, but
* for best performance it is recommended to pass in a cached
* version of the already calculated SHA.
* }
* @return StreamableUploader

This comment was marked as spam.

* @throws \InvalidArgumentException
*/
public function getStreamableUploader($data, array $options = [])
{
if (is_string($data) && !isset($options['name'])) {
throw new \InvalidArgumentException('A name is required when data is of type string.');
}

return $this->connection->insertObject(
$this->formatEncryptionHeaders($options) + [
'bucket' => $this->identity['bucket'],
'data' => $data,
'streamable' => true,
'validate' => false
]
);
}

/**
* Lazily instantiates an object. There are no network requests made at this
* point. To see the operations that can be performed on an object please
Expand Down
27 changes: 13 additions & 14 deletions src/Storage/Connection/Rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Google\Cloud\Upload\AbstractUploader;
use Google\Cloud\Upload\MultipartUploader;
use Google\Cloud\Upload\ResumableUploader;
use Google\Cloud\Upload\StreamableUploader;
use Google\Cloud\UriTrait;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Request;
Expand Down Expand Up @@ -230,10 +231,16 @@ public function downloadObject(array $args = [])
public function insertObject(array $args = [])
{
$args = $this->resolveUploadOptions($args);
$isResumable = $args['resumable'];
$uploadType = $isResumable
? AbstractUploader::UPLOAD_TYPE_RESUMABLE
: AbstractUploader::UPLOAD_TYPE_MULTIPART;

$uploadType = AbstractUploader::UPLOAD_TYPE_RESUMABLE;
if ($args['streamable']) {
$uploaderClass = StreamableUploader::class;
} elseif ($args['resumable']) {
$uploaderClass = ResumableUploader::class;
} else {
$uploaderClass = MultipartUploader::class;
$uploadType = AbstractUploader::UPLOAD_TYPE_MULTIPART;
}

$uriParams = [
'bucket' => $args['bucket'],
Expand All @@ -243,16 +250,7 @@ public function insertObject(array $args = [])
]
];

if ($isResumable) {
return new ResumableUploader(
$this->requestWrapper,
$args['data'],
$this->expandUri(self::UPLOAD_URI, $uriParams),
$args['uploaderOptions']
);
}

return new MultipartUploader(
return new $uploaderClass(
$this->requestWrapper,
$args['data'],
$this->expandUri(self::UPLOAD_URI, $uriParams),
Expand All @@ -270,6 +268,7 @@ private function resolveUploadOptions(array $args)
'name' => null,
'validate' => true,
'resumable' => null,
'streamable' => null,
'predefinedAcl' => null,
'metadata' => []
];
Expand Down
28 changes: 28 additions & 0 deletions src/Storage/StorageClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,32 @@ public function createBucket($name, array $options = [])
$response = $this->connection->insertBucket($options + ['name' => $name, 'project' => $this->projectId]);
return new Bucket($this->connection, $name, $response);
}

/**
* Registers this StorageClient as the handler for stream reading/writing.
*
* @param string $protocol The name of the protocol to use. Defaults to

This comment was marked as spam.

* 'gs'.
* @throws \RuntimeException
*/
public function registerAsStreamWrapper(string $protocol = null)

This comment was marked as spam.

{
if (StreamWrapper::register($protocol)) {

This comment was marked as spam.

This comment was marked as spam.

StreamWrapper::setClient($this);
return true;
}
return false;
}

/**
* Unregisters the SteamWrapper
*
* @param string $protocol The name of the protocol to unregister. Defaults
* to 'gs'.
*/
public function unregisterAsStreamWrapper(string $protocol = null)
{
StreamWrapper::unregister($protocol);
StreamWrapper::setClient(null);
}
}
Loading