feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)

Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.

Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
  - Provider key: s3compatible
  - Reads user-configured endpoint URL from settings
  - Uses path-style URL access (required by most S3-compatible services)
  - Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
    AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
  - Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
2026-03-03 12:30:18 +01:00
commit 3248cbb029
2086 changed files with 359427 additions and 0 deletions

261
vendor/Gcp/google/gax/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,261 @@
# Changelog
## [1.29.1](https://github.com/googleapis/gax-php/compare/v1.29.0...v1.29.1) (2024-02-26)
### Bug Fixes
* Allow InsecureCredentialsWrapper::getAuthorizationHeaderCallback to return null ([#541](https://github.com/googleapis/gax-php/issues/541)) ([676f4f7](https://github.com/googleapis/gax-php/commit/676f4f7e3d8925d8aba00285616fdf89440b45f9))
## [1.29.0](https://github.com/googleapis/gax-php/compare/v1.28.1...v1.29.0) (2024-02-26)
### Features
* Add InsecureCredentialsWrapper for Emulator connection ([#538](https://github.com/googleapis/gax-php/issues/538)) ([b5dbeaf](https://github.com/googleapis/gax-php/commit/b5dbeaf33594b300a0c678ffc6a6946b09fce7dd))
## [1.28.1](https://github.com/googleapis/gax-php/compare/v1.28.0...v1.28.1) (2024-02-20)
### Bug Fixes
* Universe domain check for grpc transport ([#534](https://github.com/googleapis/gax-php/issues/534)) ([1026d8a](https://github.com/googleapis/gax-php/commit/1026d8aec73e0aad8949a86ee7575e3edb3d56be))
## [1.28.0](https://github.com/googleapis/gax-php/compare/v1.27.2...v1.28.0) (2024-02-15)
### Features
* Allow setting of universe domain in environment variable ([#520](https://github.com/googleapis/gax-php/issues/520)) ([6e6603b](https://github.com/googleapis/gax-php/commit/6e6603b03285f3f8d1072776cd206720e3990f50))
## [1.27.2](https://github.com/googleapis/gax-php/compare/v1.27.1...v1.27.2) (2024-02-14)
### Bug Fixes
* Typo in TransportOptions option name ([#530](https://github.com/googleapis/gax-php/issues/530)) ([6914fe0](https://github.com/googleapis/gax-php/commit/6914fe04554867bd827be6596fafc751a3d7621a))
## [1.27.1](https://github.com/googleapis/gax-php/compare/v1.27.0...v1.27.1) (2024-02-14)
### Bug Fixes
* Issues in Options classes ([#528](https://github.com/googleapis/gax-php/issues/528)) ([aa9ba3a](https://github.com/googleapis/gax-php/commit/aa9ba3a6bac9324ad894d9677da0e897497ebab2))
## [1.27.0](https://github.com/googleapis/gax-php/compare/v1.26.3...v1.27.0) (2024-02-07)
### Features
* Create ClientOptionsTrait ([#527](https://github.com/googleapis/gax-php/issues/527)) ([cfe2c60](https://github.com/googleapis/gax-php/commit/cfe2c60a36233f74259c96a6799d8492ed7c45d0))
* Implement ProjectIdProviderInterface in CredentialsWrapper ([#523](https://github.com/googleapis/gax-php/issues/523)) ([b56a463](https://github.com/googleapis/gax-php/commit/b56a4635abfeeec08895202da8218e9ba915413e))
* Update ArrayTrait to be consistent with Core ([#526](https://github.com/googleapis/gax-php/issues/526)) ([8e44185](https://github.com/googleapis/gax-php/commit/8e44185dd6f8f8f9ef5b136776cba61ec7a8b8f6))
### Bug Fixes
* Correct exception type for Guzzle promise ([#521](https://github.com/googleapis/gax-php/issues/521)) ([7129373](https://github.com/googleapis/gax-php/commit/712937339c134e1d92cab5fa736cfe1bbcd7f343))
## [1.26.3](https://github.com/googleapis/gax-php/compare/v1.26.2...v1.26.3) (2024-01-18)
### Bug Fixes
* CallOptions should use transportOptions ([#513](https://github.com/googleapis/gax-php/issues/513)) ([2d45ee1](https://github.com/googleapis/gax-php/commit/2d45ee187cdc3619b30c51b653b508718baf3af4))
## [1.26.2](https://github.com/googleapis/gax-php/compare/v1.26.1...v1.26.2) (2024-01-09)
### Bug Fixes
* Ensure modifyClientOptions is called for new surface clients ([#515](https://github.com/googleapis/gax-php/issues/515)) ([68231b8](https://github.com/googleapis/gax-php/commit/68231b896dec8efb86f8986aefba3d247d2a2d1c))
## [1.26.1](https://github.com/googleapis/gax-php/compare/v1.26.0...v1.26.1) (2024-01-04)
### Bug Fixes
* Widen google/longrunning version ([#511](https://github.com/googleapis/gax-php/issues/511)) ([b93096d](https://github.com/googleapis/gax-php/commit/b93096d0e10bde14c50480ea9f0423c292fbd5a6))
## [1.26.0](https://github.com/googleapis/gax-php/compare/v1.25.0...v1.26.0) (2024-01-03)
### Features
* Add support for universe domain ([#502](https://github.com/googleapis/gax-php/issues/502)) ([5a26fac](https://github.com/googleapis/gax-php/commit/5a26facad5c2e5c30945987c422bb78a3fffb9b1))
* Interface and methods for middleware stack ([#473](https://github.com/googleapis/gax-php/issues/473)) ([766da7b](https://github.com/googleapis/gax-php/commit/766da7b369409ec1b29376b533e7f22ee7f745f4))
### Bug Fixes
* Accept throwable for retry settings ([#509](https://github.com/googleapis/gax-php/issues/509)) ([5af9c3c](https://github.com/googleapis/gax-php/commit/5af9c3c650419c8f1a590783e954cd11dc1f0d56))
## [1.25.0](https://github.com/googleapis/gax-php/compare/v1.24.0...v1.25.0) (2023-11-02)
### Features
* Add custom retries ([#489](https://github.com/googleapis/gax-php/issues/489)) ([ef0789b](https://github.com/googleapis/gax-php/commit/ef0789b73ef28d79a08c354d1361a9ccc6206088))
## [1.24.0](https://github.com/googleapis/gax-php/compare/v1.23.0...v1.24.0) (2023-10-10)
### Features
* Ensure NewClientSurface works for consoldiated v2 clients ([#493](https://github.com/googleapis/gax-php/issues/493)) ([cb8706e](https://github.com/googleapis/gax-php/commit/cb8706ef9211a1e43f733d2c8f272a330c2fa792))
## [1.23.0](https://github.com/googleapis/gax-php/compare/v1.22.1...v1.23.0) (2023-09-14)
### Features
* Typesafety for new surface client options ([#450](https://github.com/googleapis/gax-php/issues/450)) ([21550c5](https://github.com/googleapis/gax-php/commit/21550c5bf07f178f2043b0630f3ac34fcc3a05e0))
## [1.22.1](https://github.com/googleapis/gax-php/compare/v1.22.0...v1.22.1) (2023-08-04)
### Bug Fixes
* Deprecation notice while GapicClientTrait->setClientOptions ([#483](https://github.com/googleapis/gax-php/issues/483)) ([1c66d34](https://github.com/googleapis/gax-php/commit/1c66d3445dca4d43831a2f4e26e59b9bd1cb76dd))
## [1.22.0](https://github.com/googleapis/gax-php/compare/v1.21.1...v1.22.0) (2023-07-31)
### Features
* Sets api headers for "gcloud-php-new" and "gcloud-php-legacy" surface versions ([#470](https://github.com/googleapis/gax-php/issues/470)) ([2d8ccff](https://github.com/googleapis/gax-php/commit/2d8ccff419a076ee2fe9d3dc7ecd5509c74afb4c))
## [1.21.1](https://github.com/googleapis/gax-php/compare/v1.21.0...v1.21.1) (2023-06-28)
### Bug Fixes
* Revert "chore: remove unnecessary api endpoint check" ([#476](https://github.com/googleapis/gax-php/issues/476)) ([13e773f](https://github.com/googleapis/gax-php/commit/13e773f5b09f9a99b8425835815746d37e9c1da3))
## [1.21.0](https://github.com/googleapis/gax-php/compare/v1.20.2...v1.21.0) (2023-06-09)
### Features
* Support guzzle/promises:v2 ([753eae9](https://github.com/googleapis/gax-php/commit/753eae9acf638f3356f8149acf84444eb399a699))
## [1.20.2](https://github.com/googleapis/gax-php/compare/v1.20.1...v1.20.2) (2023-05-12)
### Bug Fixes
* Ensure timeout set by RetryMiddleware is int not float ([#462](https://github.com/googleapis/gax-php/issues/462)) ([9d4c7fa](https://github.com/googleapis/gax-php/commit/9d4c7fa89445c63ec0bf4745ed9d98fd185ef51f))
## [1.20.1](https://github.com/googleapis/gax-php/compare/v1.20.0...v1.20.1) (2023-05-12)
### Bug Fixes
* Default value for error message in createFromRequestException ([#463](https://github.com/googleapis/gax-php/issues/463)) ([7552d22](https://github.com/googleapis/gax-php/commit/7552d22241c2f488606e9546efdd6edea356ee9a))
## [1.20.0](https://github.com/googleapis/gax-php/compare/v1.19.1...v1.20.0) (2023-05-01)
### Features
* **deps:** Support google/common-protos 4.0 ([af1db80](https://github.com/googleapis/gax-php/commit/af1db80c22307597f0dfcb9fafa86caf466588ba))
* **deps:** Support google/grpc-gcp 0.3 ([18edc2c](https://github.com/googleapis/gax-php/commit/18edc2ce6a1a615e3ea7c00ede313c32cec4b799))
## [1.19.1](https://github.com/googleapis/gax-php/compare/v1.19.0...v1.19.1) (2023-03-16)
### Bug Fixes
* Simplify ResourceHelperTrait registration ([#447](https://github.com/googleapis/gax-php/issues/447)) ([4949dc0](https://github.com/googleapis/gax-php/commit/4949dc0c4cd5e58af7933a1d2ecab90832c0b036))
## [1.19.0](https://github.com/googleapis/gax-php/compare/v1.18.2...v1.19.0) (2023-01-27)
### Features
* Ensure cache is used in calls to ADC::onGCE ([#441](https://github.com/googleapis/gax-php/issues/441)) ([64a4184](https://github.com/googleapis/gax-php/commit/64a4184ab69d13104d269b15a55d4b8b2515b5a6))
## [1.18.2](https://github.com/googleapis/gax-php/compare/v1.18.1...v1.18.2) (2023-01-06)
### Bug Fixes
* Ensure metadata return type is loaded into descriptor pool ([#439](https://github.com/googleapis/gax-php/issues/439)) ([a40cf8d](https://github.com/googleapis/gax-php/commit/a40cf8d87ac9aa45d18239456e2e4c96653f1a6c))
* Implicit conversion from float to int warning ([#438](https://github.com/googleapis/gax-php/issues/438)) ([1cb62ad](https://github.com/googleapis/gax-php/commit/1cb62ad3d92ace0518017abc972e912b339f1b56))
## [1.18.1](https://github.com/googleapis/gax-php/compare/v1.18.0...v1.18.1) (2022-12-06)
### Bug Fixes
* Message parameters in required querystring ([#430](https://github.com/googleapis/gax-php/issues/430)) ([77bc5e1](https://github.com/googleapis/gax-php/commit/77bc5e1cb8f347601d9237bf5164cf8b8ad8aa0f))
## [1.18.0](https://github.com/googleapis/gax-php/compare/v1.17.0...v1.18.0) (2022-12-05)
### Features
* Add ResourceHelperTrait ([#428](https://github.com/googleapis/gax-php/issues/428)) ([0439efa](https://github.com/googleapis/gax-php/commit/0439efa926865be5fea25b699469b0c1f8c1c768))
## [1.17.0](https://github.com/googleapis/gax-php/compare/v1.16.4...v1.17.0) (2022-09-08)
### Features
* Add startAsyncCall support ([#418](https://github.com/googleapis/gax-php/issues/418)) ([fc90693](https://github.com/googleapis/gax-php/commit/fc9069373c329183e07f8d174084c305b2308209))
## [1.16.4](https://github.com/googleapis/gax-php/compare/v1.16.3...v1.16.4) (2022-08-25)
### Bug Fixes
* use interfaceOverride instead of param ([#419](https://github.com/googleapis/gax-php/issues/419)) ([9dd5bc9](https://github.com/googleapis/gax-php/commit/9dd5bc91c4becfd2a0832288ab2406c3d224618e))
## [1.16.3](https://github.com/googleapis/gax-php/compare/v1.16.2...v1.16.3) (2022-08-23)
### Bug Fixes
* add eager threshold ([#416](https://github.com/googleapis/gax-php/issues/416)) ([99eb172](https://github.com/googleapis/gax-php/commit/99eb172280f301b117fde9dcc92079ca03aa28bd))
## [1.16.2](https://github.com/googleapis/gax-php/compare/v1.16.1...v1.16.2) (2022-08-16)
### Bug Fixes
* use responseType for custom operations ([#413](https://github.com/googleapis/gax-php/issues/413)) ([b643adf](https://github.com/googleapis/gax-php/commit/b643adfc44dd9fe82b0919e5b34edd00c7cdbb1f))
## [1.16.1](https://github.com/googleapis/gax-php/compare/v1.16.0...v1.16.1) (2022-08-11)
### Bug Fixes
* remove typehint from extended method ([#411](https://github.com/googleapis/gax-php/issues/411)) ([fb37f73](https://github.com/googleapis/gax-php/commit/fb37f7365e888465d84fca304ca83360ddbae6c3))
## [1.16.0](https://github.com/googleapis/gax-php/compare/v1.15.0...v1.16.0) (2022-08-10)
### Features
* additional typehinting ([#403](https://github.com/googleapis/gax-php/issues/403)) ([6597a07](https://github.com/googleapis/gax-php/commit/6597a07019665d91e07ea0a016c7d99c8a099cd2))
* drop support for PHP 5.6 ([#397](https://github.com/googleapis/gax-php/issues/397)) ([b888b24](https://github.com/googleapis/gax-php/commit/b888b24e0e223784e22dbbbe27fe0284cdcdfc35))
* introduce startApiCall ([#406](https://github.com/googleapis/gax-php/issues/406)) ([1cfeb62](https://github.com/googleapis/gax-php/commit/1cfeb628070c9c6e57b2dde854b0a973a888a2bc))
### Bug Fixes
* **deps:** update dependency google/longrunning to ^0.2 ([#407](https://github.com/googleapis/gax-php/issues/407)) ([54d4f32](https://github.com/googleapis/gax-php/commit/54d4f32ba5464d1f5da33e1c99a020174cae367c))
## [1.15.0](https://github.com/googleapis/gax-php/compare/v1.14.0...v1.15.0) (2022-08-02)
### Features
* move LongRunning classes to a standalone package ([#401](https://github.com/googleapis/gax-php/issues/401)) ([1747125](https://github.com/googleapis/gax-php/commit/1747125c84dcc6d42390de7e78d2e326884e1073))
## [1.14.0](https://github.com/googleapis/gax-php/compare/v1.13.0...v1.14.0) (2022-07-26)
### Features
* support requesting numeric enum rest encoding ([#395](https://github.com/googleapis/gax-php/issues/395)) ([0d74a48](https://github.com/googleapis/gax-php/commit/0d74a4877c5198cfaf534c4e55d7e418b50bc6ab))

View File

@@ -0,0 +1,43 @@
# Contributor Code of Conduct
As contributors and maintainers of this project,
and in the interest of fostering an open and welcoming community,
we pledge to respect all people who contribute through reporting issues,
posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.
We are committed to making participation in this project
a harassment-free experience for everyone,
regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information,
such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct.
By adopting this Code of Conduct,
project maintainers commit themselves to fairly and consistently
applying these principles to every aspect of managing this project.
Project maintainers who do not follow or enforce the Code of Conduct
may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior
may be reported by opening an issue
or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)

25
vendor/Gcp/google/gax/LICENSE vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright 2016, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

7
vendor/Gcp/google/gax/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,7 @@
# Security Policy
To report a security issue, please use [g.co/vulnz](https://g.co/vulnz).
The Google Security Team will respond within 5 working days of your report on g.co/vulnz.
We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue.

1
vendor/Gcp/google/gax/VERSION vendored Normal file
View File

@@ -0,0 +1 @@
1.29.1

View File

@@ -0,0 +1,5 @@
parameters:
treatPhpDocTypesAsCertain: false
level: 5
paths:
- src

13
vendor/Gcp/google/gax/phpunit.xml.dist vendored Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="tests/bootstrap.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" colors="true">
<coverage>
<include>
<directory suffix=".php">src/ApiCore</directory>
</include>
</coverage>
<testsuites>
<testsuite name="unit">
<directory>tests/Tests/Unit</directory>
</testsuite>
</testsuites>
</phpunit>

7
vendor/Gcp/google/gax/renovate.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"extends": [
"config:base",
":preserveSemverRanges",
":disableDependencyDashboard"
]
}

View File

@@ -0,0 +1,116 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Class containing functions used to build the Agent header.
*/
class AgentHeader
{
const AGENT_HEADER_KEY = 'x-goog-api-client';
const UNKNOWN_VERSION = '';
/**
* @param array $headerInfo {
* Optional.
*
* @type string $phpVersion the PHP version.
* @type string $libName the name of the client application.
* @type string $libVersion the version of the client application.
* @type string $gapicVersion the code generator version of the GAPIC library.
* @type string $apiCoreVersion the ApiCore version.
* @type string $grpcVersion the gRPC version.
* @type string $restVersion the REST transport version (typically same as the
* ApiCore version).
* @type string $protobufVersion the protobuf version in format 'x.y.z+a' where both 'x.y.z'
* and '+a' are optional, and where 'a' is a single letter representing the
* implementation type of the protobuf runtime. It is recommended to use 'c' for a C
* implementation, and 'n' for the native language implementation (PHP).
* }
* @return array Agent header array
*/
public static function buildAgentHeader(array $headerInfo)
{
$metricsHeaders = [];
// The ordering of the headers is important. We use the fact that $metricsHeaders is an
// ordered dict. The desired ordering is:
// - phpVersion (gl-php/)
// - clientName (e.g. gccl/)
// - gapicVersion (gapic/)
// - apiCoreVersion (gax/)
// - grpcVersion (grpc/)
// - restVersion (rest/)
// - protobufVersion (pb/)
$metricsHeaders['gl-php'] = $headerInfo['phpVersion'] ?? \phpversion();
if (isset($headerInfo['libName'])) {
$metricsHeaders[$headerInfo['libName']] = $headerInfo['libVersion'] ?? self::UNKNOWN_VERSION;
}
$apiCoreVersion = $headerInfo['apiCoreVersion'] ?? Version::getApiCoreVersion();
$metricsHeaders['gapic'] = $headerInfo['gapicVersion'] ?? self::UNKNOWN_VERSION;
$metricsHeaders['gax'] = $apiCoreVersion;
// Context on library type identification (between gRPC+REST and REST-only):
// This uses the gRPC extension's version if 'grpcVersion' is not set, so we
// cannot use the presence of 'grpcVersion' to determine whether or not a library
// is gRPC+REST or REST-only. However, we cannot use the extension's presence
// either, since some clients may have the extension installed but opt to use a
// REST-only library (e.g. GCE).
// TODO: Should we stop sending empty gRPC headers?
$metricsHeaders['grpc'] = $headerInfo['grpcVersion'] ?? \phpversion('grpc');
$metricsHeaders['rest'] = $headerInfo['restVersion'] ?? $apiCoreVersion;
// The native version is not set by default because it is complex and costly to retrieve.
// Users can override this default behavior if needed.
$metricsHeaders['pb'] = $headerInfo['protobufVersion'] ?? (\phpversion('protobuf') ? \phpversion('protobuf') . '+c' : '+n');
$metricsList = [];
foreach ($metricsHeaders as $key => $value) {
$metricsList[] = $key . "/" . $value;
}
return [self::AGENT_HEADER_KEY => [\implode(" ", $metricsList)]];
}
/**
* Reads the gapic version string from a VERSION file. In order to determine the file
* location, this method follows this procedure:
* - accepts a class name $callingClass
* - identifies the file defining that class
* - searches up the directory structure for the 'src' directory
* - looks in the directory above 'src' for a file named VERSION
*
* @param string $callingClass
* @return string the gapic version
* @throws \ReflectionException
*/
public static function readGapicVersionFromFile(string $callingClass)
{
$callingClassFile = (new \ReflectionClass($callingClass))->getFileName();
$versionFile = \substr($callingClassFile, 0, \strrpos($callingClassFile, \DIRECTORY_SEPARATOR . 'src' . \DIRECTORY_SEPARATOR)) . \DIRECTORY_SEPARATOR . 'VERSION';
return Version::readVersionFile($versionFile);
}
}

View File

@@ -0,0 +1,267 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use Exception;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\RepeatedField;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Status;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Exception\RequestException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Testing\MockStatus;
use stdClass;
/**
* Represents an exception thrown during an RPC.
*/
class ApiException extends Exception
{
private $status;
private $metadata;
private $basicMessage;
private $decodedMetadataErrorInfo;
/**
* ApiException constructor.
* @param string $message
* @param int $code
* @param string|null $status
* @param array $optionalArgs {
* @type Exception|null $previous
* @type array|null $metadata
* @type string|null $basicMessage
* }
*/
public function __construct(string $message, int $code, string $status = null, array $optionalArgs = [])
{
$optionalArgs += ['previous' => null, 'metadata' => null, 'basicMessage' => $message];
parent::__construct($message, $code, $optionalArgs['previous']);
$this->status = $status;
$this->metadata = $optionalArgs['metadata'];
$this->basicMessage = $optionalArgs['basicMessage'];
if ($this->metadata) {
$this->decodedMetadataErrorInfo = self::decodeMetadataErrorInfo($this->metadata);
}
}
public function getStatus()
{
return $this->status;
}
/**
* Returns null if metadata does not contain error info, or returns containsErrorInfo() array
* if the metadata does contain error info.
* @param array $metadata
* @return array $details {
* @type string|null $reason
* @type string|null $domain
* @type array|null $errorInfoMetadata
* }
*/
private static function decodeMetadataErrorInfo(array $metadata)
{
$details = [];
// ApiExceptions created from RPC status have metadata that is an array of objects.
if (\is_object(\reset($metadata))) {
$metadataRpcStatus = Serializer::decodeAnyMessages($metadata);
$details = self::containsErrorInfo($metadataRpcStatus);
} elseif (self::containsErrorInfo($metadata)) {
$details = self::containsErrorInfo($metadata);
} else {
// For GRPC-based responses, the $metadata needs to be decoded.
$metadataGrpc = Serializer::decodeMetadata($metadata);
$details = self::containsErrorInfo($metadataGrpc);
}
return $details;
}
/**
* Returns the `reason` in ErrorInfo for an exception, or null if there is no ErrorInfo.
* @return string|null $reason
*/
public function getReason()
{
return $this->decodedMetadataErrorInfo ? $this->decodedMetadataErrorInfo['reason'] : null;
}
/**
* Returns the `domain` in ErrorInfo for an exception, or null if there is no ErrorInfo.
* @return string|null $domain
*/
public function getDomain()
{
return $this->decodedMetadataErrorInfo ? $this->decodedMetadataErrorInfo['domain'] : null;
}
/**
* Returns the `metadata` in ErrorInfo for an exception, or null if there is no ErrorInfo.
* @return array|null $errorInfoMetadata
*/
public function getErrorInfoMetadata()
{
return $this->decodedMetadataErrorInfo ? $this->decodedMetadataErrorInfo['errorInfoMetadata'] : null;
}
/**
* @param stdClass $status
* @return ApiException
*/
public static function createFromStdClass(stdClass $status)
{
$metadata = \property_exists($status, 'metadata') ? $status->metadata : null;
return self::create($status->details, $status->code, $metadata, Serializer::decodeMetadata((array) $metadata));
}
/**
* @param string $basicMessage
* @param int $rpcCode
* @param array|null $metadata
* @param Exception $previous
* @return ApiException
*/
public static function createFromApiResponse($basicMessage, $rpcCode, array $metadata = null, Exception $previous = null)
{
return self::create($basicMessage, $rpcCode, $metadata, Serializer::decodeMetadata((array) $metadata), $previous);
}
/**
* For REST-based responses, the metadata does not need to be decoded.
*
* @param string $basicMessage
* @param int $rpcCode
* @param array|null $metadata
* @param Exception $previous
* @return ApiException
*/
public static function createFromRestApiResponse($basicMessage, $rpcCode, array $metadata = null, Exception $previous = null)
{
return self::create($basicMessage, $rpcCode, $metadata, \is_null($metadata) ? [] : $metadata, $previous);
}
/**
* Checks if decoded metadata includes errorInfo message.
* If errorInfo is set, it will always contain `reason`, `domain`, and `metadata` keys.
* @param array $decodedMetadata
* @return array {
* @type string $reason
* @type string $domain
* @type array $errorInfoMetadata
* }
*/
private static function containsErrorInfo(array $decodedMetadata)
{
if (empty($decodedMetadata)) {
return [];
}
foreach ($decodedMetadata as $value) {
$isErrorInfoArray = isset($value['reason']) && isset($value['domain']) && isset($value['metadata']);
if ($isErrorInfoArray) {
return ['reason' => $value['reason'], 'domain' => $value['domain'], 'errorInfoMetadata' => $value['metadata']];
}
}
return [];
}
/**
* Construct an ApiException with a useful message, including decoded metadata.
* If the decoded metadata includes an errorInfo message, then the domain, reason,
* and metadata fields from that message are hoisted directly into the error.
*
* @param string $basicMessage
* @param int $rpcCode
* @param iterable|null $metadata
* @param array $decodedMetadata
* @param Exception|null $previous
* @return ApiException
*/
private static function create(string $basicMessage, int $rpcCode, $metadata, array $decodedMetadata, Exception $previous = null)
{
$containsErrorInfo = self::containsErrorInfo($decodedMetadata);
$rpcStatus = ApiStatus::statusFromRpcCode($rpcCode);
$messageData = ['message' => $basicMessage, 'code' => $rpcCode, 'status' => $rpcStatus, 'details' => $decodedMetadata];
if ($containsErrorInfo) {
$messageData = \array_merge($containsErrorInfo, $messageData);
}
$message = \json_encode($messageData, \JSON_PRETTY_PRINT);
if ($metadata instanceof RepeatedField) {
$metadata = \iterator_to_array($metadata);
}
return new ApiException($message, $rpcCode, $rpcStatus, ['previous' => $previous, 'metadata' => $metadata, 'basicMessage' => $basicMessage]);
}
/**
* @param Status $status
* @return ApiException
*/
public static function createFromRpcStatus(Status $status)
{
return self::create($status->getMessage(), $status->getCode(), $status->getDetails(), Serializer::decodeAnyMessages($status->getDetails()));
}
/**
* Creates an ApiException from a GuzzleHttp RequestException.
*
* @param RequestException $ex
* @param boolean $isStream
* @return ApiException
* @throws ValidationException
*/
public static function createFromRequestException(RequestException $ex, bool $isStream = \false)
{
$res = $ex->getResponse();
$body = (string) $res->getBody();
$decoded = \json_decode($body, \true);
// A streaming response body will return one error in an array. Parse
// that first (and only) error message, if provided.
if ($isStream && isset($decoded[0])) {
$decoded = $decoded[0];
}
if (isset($decoded['error']) && $decoded['error']) {
$error = $decoded['error'];
$basicMessage = $error['message'] ?? '';
$code = isset($error['status']) ? ApiStatus::rpcCodeFromStatus($error['status']) : $ex->getCode();
$metadata = $error['details'] ?? null;
return static::createFromRestApiResponse($basicMessage, $code, $metadata);
}
// Use the RPC code instead of the HTTP Status Code.
$code = ApiStatus::rpcCodeFromHttpStatusCode($res->getStatusCode());
return static::createFromApiResponse($body, $code);
}
/**
* @return null|string
*/
public function getBasicMessage()
{
return $this->basicMessage;
}
/**
* @return mixed[]
*/
public function getMetadata()
{
return $this->metadata;
}
/**
* String representation of ApiException
* @return string
*/
public function __toString()
{
return __CLASS__ . ": {$this->message}\n";
}
}

117
vendor/Gcp/google/gax/src/ApiStatus.php vendored Normal file
View File

@@ -0,0 +1,117 @@
<?php
/*
* Copyright 2017 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code;
class ApiStatus
{
const OK = 'OK';
const CANCELLED = 'CANCELLED';
const UNKNOWN = 'UNKNOWN';
const INVALID_ARGUMENT = 'INVALID_ARGUMENT';
const DEADLINE_EXCEEDED = 'DEADLINE_EXCEEDED';
const NOT_FOUND = 'NOT_FOUND';
const ALREADY_EXISTS = 'ALREADY_EXISTS';
const PERMISSION_DENIED = 'PERMISSION_DENIED';
const RESOURCE_EXHAUSTED = 'RESOURCE_EXHAUSTED';
const FAILED_PRECONDITION = 'FAILED_PRECONDITION';
const ABORTED = 'ABORTED';
const OUT_OF_RANGE = 'OUT_OF_RANGE';
const UNIMPLEMENTED = 'UNIMPLEMENTED';
const INTERNAL = 'INTERNAL';
const UNAVAILABLE = 'UNAVAILABLE';
const DATA_LOSS = 'DATA_LOSS';
const UNAUTHENTICATED = 'UNAUTHENTICATED';
const UNRECOGNIZED_STATUS = 'UNRECOGNIZED_STATUS';
const UNRECOGNIZED_CODE = -1;
private static $apiStatusToCodeMap = [ApiStatus::OK => Code::OK, ApiStatus::CANCELLED => Code::CANCELLED, ApiStatus::UNKNOWN => Code::UNKNOWN, ApiStatus::INVALID_ARGUMENT => Code::INVALID_ARGUMENT, ApiStatus::DEADLINE_EXCEEDED => Code::DEADLINE_EXCEEDED, ApiStatus::NOT_FOUND => Code::NOT_FOUND, ApiStatus::ALREADY_EXISTS => Code::ALREADY_EXISTS, ApiStatus::PERMISSION_DENIED => Code::PERMISSION_DENIED, ApiStatus::RESOURCE_EXHAUSTED => Code::RESOURCE_EXHAUSTED, ApiStatus::FAILED_PRECONDITION => Code::FAILED_PRECONDITION, ApiStatus::ABORTED => Code::ABORTED, ApiStatus::OUT_OF_RANGE => Code::OUT_OF_RANGE, ApiStatus::UNIMPLEMENTED => Code::UNIMPLEMENTED, ApiStatus::INTERNAL => Code::INTERNAL, ApiStatus::UNAVAILABLE => Code::UNAVAILABLE, ApiStatus::DATA_LOSS => Code::DATA_LOSS, ApiStatus::UNAUTHENTICATED => Code::UNAUTHENTICATED];
private static $codeToApiStatusMap = [Code::OK => ApiStatus::OK, Code::CANCELLED => ApiStatus::CANCELLED, Code::UNKNOWN => ApiStatus::UNKNOWN, Code::INVALID_ARGUMENT => ApiStatus::INVALID_ARGUMENT, Code::DEADLINE_EXCEEDED => ApiStatus::DEADLINE_EXCEEDED, Code::NOT_FOUND => ApiStatus::NOT_FOUND, Code::ALREADY_EXISTS => ApiStatus::ALREADY_EXISTS, Code::PERMISSION_DENIED => ApiStatus::PERMISSION_DENIED, Code::RESOURCE_EXHAUSTED => ApiStatus::RESOURCE_EXHAUSTED, Code::FAILED_PRECONDITION => ApiStatus::FAILED_PRECONDITION, Code::ABORTED => ApiStatus::ABORTED, Code::OUT_OF_RANGE => ApiStatus::OUT_OF_RANGE, Code::UNIMPLEMENTED => ApiStatus::UNIMPLEMENTED, Code::INTERNAL => ApiStatus::INTERNAL, Code::UNAVAILABLE => ApiStatus::UNAVAILABLE, Code::DATA_LOSS => ApiStatus::DATA_LOSS, Code::UNAUTHENTICATED => ApiStatus::UNAUTHENTICATED];
private static $httpStatusCodeToRpcCodeMap = [400 => Code::INVALID_ARGUMENT, 401 => Code::UNAUTHENTICATED, 403 => Code::PERMISSION_DENIED, 404 => Code::NOT_FOUND, 409 => Code::ABORTED, 416 => Code::OUT_OF_RANGE, 429 => Code::RESOURCE_EXHAUSTED, 499 => Code::CANCELLED, 501 => Code::UNIMPLEMENTED, 503 => Code::UNAVAILABLE, 504 => Code::DEADLINE_EXCEEDED];
/**
* @param string $status
* @return bool
*/
public static function isValidStatus(string $status)
{
return \array_key_exists($status, self::$apiStatusToCodeMap);
}
/**
* @param int $code
* @return string
*/
public static function statusFromRpcCode(int $code)
{
if (\array_key_exists($code, self::$codeToApiStatusMap)) {
return self::$codeToApiStatusMap[$code];
}
return ApiStatus::UNRECOGNIZED_STATUS;
}
/**
* @param string $status
* @return int
*/
public static function rpcCodeFromStatus(string $status)
{
if (\array_key_exists($status, self::$apiStatusToCodeMap)) {
return self::$apiStatusToCodeMap[$status];
}
return ApiStatus::UNRECOGNIZED_CODE;
}
/**
* Maps HTTP status codes to Google\Rpc\Code codes.
* Some codes are left out because they map to multiple gRPC codes (e.g. 500).
*
* @param int $httpStatusCode
* @return int
*/
public static function rpcCodeFromHttpStatusCode(int $httpStatusCode)
{
if (\array_key_exists($httpStatusCode, self::$httpStatusCodeToRpcCodeMap)) {
return self::$httpStatusCodeToRpcCodeMap[$httpStatusCode];
}
// All 2xx
if ($httpStatusCode >= 200 && $httpStatusCode < 300) {
return Code::OK;
}
// All 4xx
if ($httpStatusCode >= 400 && $httpStatusCode < 500) {
return Code::FAILED_PRECONDITION;
}
// All 5xx
if ($httpStatusCode >= 500 && $httpStatusCode < 600) {
return Code::INTERNAL;
}
// Everything else (We cannot change this to Code::UNKNOWN because it would break BC)
return ApiStatus::UNRECOGNIZED_CODE;
}
}

138
vendor/Gcp/google/gax/src/ArrayTrait.php vendored Normal file
View File

@@ -0,0 +1,138 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Provides basic array helper methods.
*
* @internal
*/
trait ArrayTrait
{
/**
* Pluck a value out of an array.
*
* @param string $key
* @param array $arr
* @param bool $isRequired
* @return mixed|null
* @throws \InvalidArgumentException
*/
private function pluck(string $key, array &$arr, bool $isRequired = \true)
{
if (!\array_key_exists($key, $arr)) {
if ($isRequired) {
throw new \InvalidArgumentException("Key {$key} does not exist in the provided array.");
}
return null;
}
$value = $arr[$key];
unset($arr[$key]);
return $value;
}
/**
* Pluck a subset of an array.
*
* @param array $keys
* @param array $arr
* @return array
*/
private function pluckArray(array $keys, array &$arr)
{
$values = [];
foreach ($keys as $key) {
if (\array_key_exists($key, $arr)) {
$values[$key] = $this->pluck($key, $arr, \false);
}
}
return $values;
}
/**
* Determine whether given array is associative.
*
* @param array $arr
* @return bool
*/
private function isAssoc(array $arr)
{
return \array_keys($arr) !== \range(0, \count($arr) - 1);
}
/**
* Just like array_filter(), but preserves falsey values except null.
*
* @param array $arr
* @return array
*/
private function arrayFilterRemoveNull(array $arr)
{
return \array_filter($arr, function ($element) {
if (!\is_null($element)) {
return \true;
}
return \false;
});
}
/**
* Return a subset of an array, like pluckArray, without modifying the original array.
*
* @param array $keys
* @param array $arr
* @return array
*/
private function subsetArray(array $keys, array $arr)
{
return \array_intersect_key($arr, \array_flip($keys));
}
/**
* A method, similar to PHP's `array_merge_recursive`, with two differences.
*
* 1. Keys in $array2 take precedence over keys in $array1.
* 2. Non-array keys found in both inputs are not transformed into an array
* and appended. Rather, the value in $array2 is used.
*
* @param array $array1
* @param array $array2
* @return array
*/
private function arrayMergeRecursive(array $array1, array $array2)
{
foreach ($array2 as $key => $value) {
if (\array_key_exists($key, $array1) && \is_array($array1[$key]) && \is_array($value)) {
$array1[$key] = $this->isAssoc($array1[$key]) && $this->isAssoc($value) ? $this->arrayMergeRecursive($array1[$key], $value) : \array_merge($array1[$key], $value);
} else {
$array1[$key] = $value;
}
}
return $array1;
}
}

168
vendor/Gcp/google/gax/src/BidiStream.php vendored Normal file
View File

@@ -0,0 +1,168 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\BidiStreamingCall;
/**
* BidiStream is the response object from a gRPC bidirectional streaming API call.
*/
class BidiStream
{
private $call;
private $isComplete = \false;
private $writesClosed = \false;
private $resourcesGetMethod = null;
private $pendingResources = [];
/**
* BidiStream constructor.
*
* @param BidiStreamingCall $bidiStreamingCall The gRPC bidirectional streaming call object
* @param array $streamingDescriptor
*/
public function __construct(BidiStreamingCall $bidiStreamingCall, array $streamingDescriptor = [])
{
$this->call = $bidiStreamingCall;
if (\array_key_exists('resourcesGetMethod', $streamingDescriptor)) {
$this->resourcesGetMethod = $streamingDescriptor['resourcesGetMethod'];
}
}
/**
* Write request to the server.
*
* @param mixed $request The request to write
* @throws ValidationException
*/
public function write($request)
{
if ($this->isComplete) {
throw new ValidationException("Cannot call write() after streaming call is complete.");
}
if ($this->writesClosed) {
throw new ValidationException("Cannot call write() after calling closeWrite().");
}
$this->call->write($request);
}
/**
* Write all requests in $requests.
*
* @param iterable $requests An Iterable of request objects to write to the server
*
* @throws ValidationException
*/
public function writeAll($requests = [])
{
foreach ($requests as $request) {
$this->write($request);
}
}
/**
* Inform the server that no more requests will be written. The write() function cannot be
* called after closeWrite() is called.
* @throws ValidationException
*/
public function closeWrite()
{
if ($this->isComplete) {
throw new ValidationException("Cannot call closeWrite() after streaming call is complete.");
}
if (!$this->writesClosed) {
$this->call->writesDone();
$this->writesClosed = \true;
}
}
/**
* Read the next response from the server. Returns null if the streaming call completed
* successfully. Throws an ApiException if the streaming call failed.
*
* @throws ValidationException
* @throws ApiException
* @return mixed
*/
public function read()
{
if ($this->isComplete) {
throw new ValidationException("Cannot call read() after streaming call is complete.");
}
$resourcesGetMethod = $this->resourcesGetMethod;
if (!\is_null($resourcesGetMethod)) {
if (\count($this->pendingResources) === 0) {
$response = $this->call->read();
if (!\is_null($response)) {
$pendingResources = [];
foreach ($response->{$resourcesGetMethod}() as $resource) {
$pendingResources[] = $resource;
}
$this->pendingResources = \array_reverse($pendingResources);
}
}
$result = \array_pop($this->pendingResources);
} else {
$result = $this->call->read();
}
if (\is_null($result)) {
$status = $this->call->getStatus();
$this->isComplete = \true;
if (!($status->code == Code::OK)) {
throw ApiException::createFromStdClass($status);
}
}
return $result;
}
/**
* Call closeWrite(), and read all responses from the server, until the streaming call is
* completed. Throws an ApiException if the streaming call failed.
*
* @throws ValidationException
* @throws ApiException
* @return \Generator|mixed[]
*/
public function closeWriteAndReadAll()
{
$this->closeWrite();
$response = $this->read();
while (!\is_null($response)) {
(yield $response);
$response = $this->read();
}
}
/**
* Return the underlying gRPC call object
*
* @return \Grpc\BidiStreamingCall|mixed
*/
public function getBidiStreamingCall()
{
return $this->call;
}
}

111
vendor/Gcp/google/gax/src/Call.php vendored Normal file
View File

@@ -0,0 +1,111 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
/**
* Contains information necessary to manage a network request.
*/
class Call
{
const UNARY_CALL = 0;
const BIDI_STREAMING_CALL = 1;
const CLIENT_STREAMING_CALL = 2;
const SERVER_STREAMING_CALL = 3;
const LONGRUNNING_CALL = 4;
const PAGINATED_CALL = 5;
private $method;
private $callType;
private $decodeType;
private $message;
private $descriptor;
/**
* @param string $method
* @param string $decodeType
* @param mixed|Message $message
* @param array|null $descriptor
* @param int $callType
*/
public function __construct(string $method, string $decodeType = null, $message = null, $descriptor = [], int $callType = Call::UNARY_CALL)
{
$this->method = $method;
$this->decodeType = $decodeType;
$this->message = $message;
$this->descriptor = $descriptor;
$this->callType = $callType;
}
/**
* @return string
*/
public function getMethod()
{
return $this->method;
}
/**
* @return int
*/
public function getCallType()
{
return $this->callType;
}
/**
* @return string
*/
public function getDecodeType()
{
return $this->decodeType;
}
/**
* @return mixed|Message
*/
public function getMessage()
{
return $this->message;
}
/**
* @return array|null
*/
public function getDescriptor()
{
return $this->descriptor;
}
/**
* @param mixed|Message $message
* @return Call
*/
public function withMessage($message)
{
// @phpstan-ignore-next-line
return new static($this->method, $this->decodeType, $message, $this->descriptor, $this->callType);
}
}

View File

@@ -0,0 +1,247 @@
<?php
/*
* Copyright 2024 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\CredentialsLoader;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\FetchAuthTokenInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\GetUniverseDomainInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\Gcp\ApiConfig;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\Gcp\Config;
/**
* Common functions used to work with various clients.
*
* @internal
*/
trait ClientOptionsTrait
{
use ArrayTrait;
private static $gapicVersionFromFile;
private static function getGapicVersion(array $options)
{
if (isset($options['libVersion'])) {
return $options['libVersion'];
}
if (!isset(self::$gapicVersionFromFile)) {
self::$gapicVersionFromFile = AgentHeader::readGapicVersionFromFile(__CLASS__);
}
return self::$gapicVersionFromFile;
}
private static function initGrpcGcpConfig(string $hostName, string $confPath)
{
$apiConfig = new ApiConfig();
$apiConfig->mergeFromJsonString(\file_get_contents($confPath));
$config = new Config($hostName, $apiConfig);
return $config;
}
/**
* Get default options. This function should be "overridden" by clients using late static
* binding to provide default options to the client.
*
* @return array
* @access private
*/
private static function getClientDefaults()
{
return [];
}
private function buildClientOptions(array $options)
{
// Build $defaultOptions starting from top level
// variables, then going into deeper nesting, so that
// we will not encounter missing keys
$defaultOptions = self::getClientDefaults();
$defaultOptions += ['disableRetries' => \false, 'credentials' => null, 'credentialsConfig' => [], 'transport' => null, 'transportConfig' => [], 'gapicVersion' => self::getGapicVersion($options), 'libName' => null, 'libVersion' => null, 'apiEndpoint' => null, 'clientCertSource' => null, 'universeDomain' => null];
$supportedTransports = $this->supportedTransports();
foreach ($supportedTransports as $transportName) {
if (!\array_key_exists($transportName, $defaultOptions['transportConfig'])) {
$defaultOptions['transportConfig'][$transportName] = [];
}
}
if (\in_array('grpc', $supportedTransports)) {
$defaultOptions['transportConfig']['grpc'] = ['stubOpts' => ['grpc.service_config_disable_resolution' => 1]];
}
// Keep track of the API Endpoint
$apiEndpoint = $options['apiEndpoint'] ?? null;
// Merge defaults into $options starting from top level
// variables, then going into deeper nesting, so that
// we will not encounter missing keys
$options += $defaultOptions;
$options['credentialsConfig'] += $defaultOptions['credentialsConfig'];
$options['transportConfig'] += $defaultOptions['transportConfig'];
// @phpstan-ignore-line
if (isset($options['transportConfig']['grpc'])) {
$options['transportConfig']['grpc'] += $defaultOptions['transportConfig']['grpc'];
$options['transportConfig']['grpc']['stubOpts'] += $defaultOptions['transportConfig']['grpc']['stubOpts'];
}
if (isset($options['transportConfig']['rest'])) {
$options['transportConfig']['rest'] += $defaultOptions['transportConfig']['rest'];
}
// These calls do not apply to "New Surface" clients.
if ($this->isBackwardsCompatibilityMode()) {
$preModifiedOptions = $options;
$this->modifyClientOptions($options);
// NOTE: this is required to ensure backwards compatiblity with $options['apiEndpoint']
if ($options['apiEndpoint'] !== $preModifiedOptions['apiEndpoint']) {
$apiEndpoint = $options['apiEndpoint'];
}
// serviceAddress is now deprecated and acts as an alias for apiEndpoint
if (isset($options['serviceAddress'])) {
$apiEndpoint = $this->pluck('serviceAddress', $options, \false);
}
} else {
// Ads is using this method in their new surface clients, so we need to call it.
// However, this method is not used anywhere else for the new surface clients
// @TODO: Remove this in GAX V2
$this->modifyClientOptions($options);
}
// If an API endpoint is different form the default, ensure the "audience" does not conflict
// with the custom endpoint by setting "user defined" scopes.
if ($apiEndpoint && $apiEndpoint != $defaultOptions['apiEndpoint'] && empty($options['credentialsConfig']['scopes']) && !empty($options['credentialsConfig']['defaultScopes'])) {
$options['credentialsConfig']['scopes'] = $options['credentialsConfig']['defaultScopes'];
}
// mTLS: detect and load the default clientCertSource if the environment variable
// "GOOGLE_API_USE_CLIENT_CERTIFICATE" is true, and the cert source is available
if (empty($options['clientCertSource']) && CredentialsLoader::shouldLoadClientCertSource()) {
if ($defaultCertSource = CredentialsLoader::getDefaultClientCertSource()) {
$options['clientCertSource'] = function () use($defaultCertSource) {
$cert = \call_user_func($defaultCertSource);
// the key and the cert are returned in one string
return [$cert, $cert];
};
}
}
// mTLS: If no apiEndpoint has been supplied by the user, and either
// GOOGLE_API_USE_MTLS_ENDPOINT tells us to, or mTLS is available, use the mTLS endpoint.
if (\is_null($apiEndpoint) && $this->shouldUseMtlsEndpoint($options)) {
$apiEndpoint = self::determineMtlsEndpoint($options['apiEndpoint']);
}
// If the user has not supplied a universe domain, use the environment variable if set.
// Otherwise, use the default ("googleapis.com").
$options['universeDomain'] ??= \getenv('GOOGLE_CLOUD_UNIVERSE_DOMAIN') ?: GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
// mTLS: It is not valid to configure mTLS outside of "googleapis.com" (yet)
if (isset($options['clientCertSource']) && $options['universeDomain'] !== GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN) {
throw new ValidationException('mTLS is not supported outside the "googleapis.com" universe');
}
if (\is_null($apiEndpoint)) {
if (\defined('self::SERVICE_ADDRESS_TEMPLATE')) {
// Derive the endpoint from the service address template and the universe domain
$apiEndpoint = \str_replace('UNIVERSE_DOMAIN', $options['universeDomain'], self::SERVICE_ADDRESS_TEMPLATE);
} else {
// For older clients, the service address template does not exist. Use the default
// endpoint instead.
$apiEndpoint = $defaultOptions['apiEndpoint'];
}
}
if (\extension_loaded('sysvshm') && isset($options['gcpApiConfigPath']) && \file_exists($options['gcpApiConfigPath']) && !empty($apiEndpoint)) {
$grpcGcpConfig = self::initGrpcGcpConfig($apiEndpoint, $options['gcpApiConfigPath']);
if (!\array_key_exists('stubOpts', $options['transportConfig']['grpc'])) {
$options['transportConfig']['grpc']['stubOpts'] = [];
}
$options['transportConfig']['grpc']['stubOpts'] += ['grpc_call_invoker' => $grpcGcpConfig->callInvoker()];
}
$options['apiEndpoint'] = $apiEndpoint;
return $options;
}
private function shouldUseMtlsEndpoint(array $options)
{
$mtlsEndpointEnvVar = \getenv('GOOGLE_API_USE_MTLS_ENDPOINT');
if ('always' === $mtlsEndpointEnvVar) {
return \true;
}
if ('never' === $mtlsEndpointEnvVar) {
return \false;
}
// For all other cases, assume "auto" and return true if clientCertSource exists
return !empty($options['clientCertSource']);
}
private static function determineMtlsEndpoint(string $apiEndpoint)
{
$parts = \explode('.', $apiEndpoint);
if (\count($parts) < 3) {
return $apiEndpoint;
// invalid endpoint!
}
return \sprintf('%s.mtls.%s', \array_shift($parts), \implode('.', $parts));
}
/**
* @param mixed $credentials
* @param array $credentialsConfig
* @return CredentialsWrapper
* @throws ValidationException
*/
private function createCredentialsWrapper($credentials, array $credentialsConfig, string $universeDomain)
{
if (\is_null($credentials)) {
return CredentialsWrapper::build($credentialsConfig, $universeDomain);
} elseif (\is_string($credentials) || \is_array($credentials)) {
return CredentialsWrapper::build(['keyFile' => $credentials] + $credentialsConfig, $universeDomain);
} elseif ($credentials instanceof FetchAuthTokenInterface) {
$authHttpHandler = $credentialsConfig['authHttpHandler'] ?? null;
return new CredentialsWrapper($credentials, $authHttpHandler, $universeDomain);
} elseif ($credentials instanceof CredentialsWrapper) {
return $credentials;
} else {
throw new ValidationException('Unexpected value in $auth option, got: ' . \print_r($credentials, \true));
}
}
/**
* This defaults to all three transports, which One-Platform supports.
* Discovery clients should define this function and only return ['rest'].
*/
private static function supportedTransports()
{
return ['grpc', 'grpc-fallback', 'rest'];
}
// Gapic Client Extension Points
// The methods below provide extension points that can be used to customize client
// functionality. These extension points are currently considered
// private and may change at any time.
/**
* Modify options passed to the client before calling setClientOptions.
*
* @param array $options
* @access private
* @internal
*/
protected function modifyClientOptions(array &$options)
{
// Do nothing - this method exists to allow option modification by partial veneers.
}
/**
* @internal
*/
private function isBackwardsCompatibilityMode() : bool
{
return \false;
}
}

View File

@@ -0,0 +1,104 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\ClientStreamingCall;
/**
* ClientStream is the response object from a gRPC client streaming API call.
*/
class ClientStream
{
private $call;
/**
* ClientStream constructor.
*
* @param ClientStreamingCall $clientStreamingCall The gRPC client streaming call object
* @param array $streamingDescriptor
*/
public function __construct(
// @phpstan-ignore-line
ClientStreamingCall $clientStreamingCall,
array $streamingDescriptor = []
)
{
$this->call = $clientStreamingCall;
}
/**
* Write request to the server.
*
* @param mixed $request The request to write
*/
public function write($request)
{
$this->call->write($request);
}
/**
* Read the response from the server, completing the streaming call.
*
* @throws ApiException
* @return mixed The response object from the server
*/
public function readResponse()
{
list($response, $status) = $this->call->wait();
if ($status->code == Code::OK) {
return $response;
} else {
throw ApiException::createFromStdClass($status);
}
}
/**
* Write all data in $dataArray and read the response from the server, completing the streaming
* call.
*
* @param mixed[] $requests An iterator of request objects to write to the server
* @return mixed The response object from the server
*/
public function writeAllAndReadResponse(array $requests)
{
foreach ($requests as $request) {
$this->write($request);
}
return $this->readResponse();
}
/**
* Return the underlying gRPC call object
*
* @return \Grpc\ClientStreamingCall|mixed
*/
public function getClientStreamingCall()
{
return $this->call;
}
}

View File

@@ -0,0 +1,277 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DomainException;
use Exception;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\ApplicationDefaultCredentials;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\ProjectIdProviderInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\Cache\MemoryCacheItemPool;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\Credentials\ServiceAccountCredentials;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\CredentialsLoader;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\FetchAuthTokenCache;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\FetchAuthTokenInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\GetQuotaProjectInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\GetUniverseDomainInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\HttpHandler\Guzzle6HttpHandler;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\HttpHandler\Guzzle7HttpHandler;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\HttpHandler\HttpHandlerFactory;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\UpdateMetadataInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Cache\CacheItemPoolInterface;
/**
* The CredentialsWrapper object provides a wrapper around a FetchAuthTokenInterface.
*/
class CredentialsWrapper implements ProjectIdProviderInterface
{
use ValidationTrait;
/** @var FetchAuthTokenInterface $credentialsFetcher */
private ?FetchAuthTokenInterface $credentialsFetcher = null;
/** @var callable $authHttpHandle */
private $authHttpHandler;
private string $universeDomain;
private bool $hasCheckedUniverse = \false;
/** @var int */
private static int $eagerRefreshThresholdSeconds = 10;
/**
* CredentialsWrapper constructor.
* @param FetchAuthTokenInterface $credentialsFetcher A credentials loader
* used to fetch access tokens.
* @param callable $authHttpHandler A handler used to deliver PSR-7 requests
* specifically for authentication. Should match a signature of
* `function (RequestInterface $request, array $options) : ResponseInterface`.
* @throws ValidationException
*/
public function __construct(FetchAuthTokenInterface $credentialsFetcher, callable $authHttpHandler = null, string $universeDomain = GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN)
{
$this->credentialsFetcher = $credentialsFetcher;
$this->authHttpHandler = $authHttpHandler ?: self::buildHttpHandlerFactory();
if (empty($universeDomain)) {
throw new ValidationException('The universe domain cannot be empty');
}
$this->universeDomain = $universeDomain;
}
/**
* Factory method to create a CredentialsWrapper from an array of options.
*
* @param array $args {
* An array of optional arguments.
*
* @type string|array $keyFile
* Credentials to be used. Accepts either a path to a credentials file, or a decoded
* credentials file as a PHP array. If this is not specified, application default
* credentials will be used.
* @type string[] $scopes
* A string array of scopes to use when acquiring credentials.
* @type callable $authHttpHandler
* A handler used to deliver PSR-7 requests specifically
* for authentication. Should match a signature of
* `function (RequestInterface $request, array $options) : ResponseInterface`.
* @type bool $enableCaching
* Enable caching of access tokens. Defaults to true.
* @type CacheItemPoolInterface $authCache
* A cache for storing access tokens. Defaults to a simple in memory implementation.
* @type array $authCacheOptions
* Cache configuration options.
* @type string $quotaProject
* Specifies a user project to bill for access charges associated with the request.
* @type string[] $defaultScopes
* A string array of default scopes to use when acquiring
* credentials.
* @type bool $useJwtAccessWithScope
* Ensures service account credentials use JWT Access (also known as self-signed
* JWTs), even when user-defined scopes are supplied.
* }
* @param string $universeDomain The expected universe of the credentials. Defaults to
* "googleapis.com"
* @return CredentialsWrapper
* @throws ValidationException
*/
public static function build(array $args = [], string $universeDomain = GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN)
{
$args += ['keyFile' => null, 'scopes' => null, 'authHttpHandler' => null, 'enableCaching' => \true, 'authCache' => null, 'authCacheOptions' => [], 'quotaProject' => null, 'defaultScopes' => null, 'useJwtAccessWithScope' => \true];
$keyFile = $args['keyFile'];
$authHttpHandler = $args['authHttpHandler'] ?: self::buildHttpHandlerFactory();
if (\is_null($keyFile)) {
$loader = self::buildApplicationDefaultCredentials($args['scopes'], $authHttpHandler, $args['authCacheOptions'], $args['authCache'], $args['quotaProject'], $args['defaultScopes']);
if ($loader instanceof FetchAuthTokenCache) {
$loader = $loader->getFetcher();
}
} else {
if (\is_string($keyFile)) {
if (!\file_exists($keyFile)) {
throw new ValidationException("Could not find keyfile: {$keyFile}");
}
$keyFile = \json_decode(\file_get_contents($keyFile), \true);
}
if (isset($args['quotaProject'])) {
$keyFile['quota_project_id'] = $args['quotaProject'];
}
$loader = CredentialsLoader::makeCredentials($args['scopes'], $keyFile, $args['defaultScopes']);
}
if ($loader instanceof ServiceAccountCredentials && $args['useJwtAccessWithScope']) {
// Ensures the ServiceAccountCredentials uses JWT Access, also known
// as self-signed JWTs, even when user-defined scopes are supplied.
$loader->useJwtAccessWithScope();
}
if ($args['enableCaching']) {
$authCache = $args['authCache'] ?: new MemoryCacheItemPool();
$loader = new FetchAuthTokenCache($loader, $args['authCacheOptions'], $authCache);
}
return new CredentialsWrapper($loader, $authHttpHandler, $universeDomain);
}
/**
* @return string|null The quota project associated with the credentials.
*/
public function getQuotaProject()
{
if ($this->credentialsFetcher instanceof GetQuotaProjectInterface) {
return $this->credentialsFetcher->getQuotaProject();
}
return null;
}
public function getProjectId(callable $httpHandler = null) : ?string
{
// Ensure that FetchAuthTokenCache does not throw an exception
if ($this->credentialsFetcher instanceof FetchAuthTokenCache && !$this->credentialsFetcher->getFetcher() instanceof ProjectIdProviderInterface) {
return null;
}
if ($this->credentialsFetcher instanceof ProjectIdProviderInterface) {
return $this->credentialsFetcher->getProjectId($httpHandler);
}
return null;
}
/**
* @deprecated
* @return string Bearer string containing access token.
*/
public function getBearerString()
{
$token = $this->credentialsFetcher->getLastReceivedToken();
if (self::isExpired($token)) {
$this->checkUniverseDomain();
$token = $this->credentialsFetcher->fetchAuthToken($this->authHttpHandler);
if (!self::isValid($token)) {
return '';
}
}
return empty($token['access_token']) ? '' : 'Bearer ' . $token['access_token'];
}
/**
* @param string $audience optional audience for self-signed JWTs.
* @return callable Callable function that returns an authorization header.
*/
public function getAuthorizationHeaderCallback($audience = null)
{
// NOTE: changes to this function should be treated carefully and tested thoroughly. It will
// be passed into the gRPC c extension, and changes have the potential to trigger very
// difficult-to-diagnose segmentation faults.
return function () use($audience) {
$token = $this->credentialsFetcher->getLastReceivedToken();
if (self::isExpired($token)) {
$this->checkUniverseDomain();
// Call updateMetadata to take advantage of self-signed JWTs
if ($this->credentialsFetcher instanceof UpdateMetadataInterface) {
return $this->credentialsFetcher->updateMetadata([], $audience);
}
// In case a custom fetcher is provided (unlikely) which doesn't
// implement UpdateMetadataInterface
$token = $this->credentialsFetcher->fetchAuthToken($this->authHttpHandler);
if (!self::isValid($token)) {
return [];
}
}
$tokenString = $token['access_token'];
if (!empty($tokenString)) {
return ['authorization' => ["Bearer {$tokenString}"]];
}
return [];
};
}
/**
* Verify that the expected universe domain matches the universe domain from the credentials.
*/
public function checkUniverseDomain()
{
if (\false === $this->hasCheckedUniverse) {
$credentialsUniverse = $this->credentialsFetcher instanceof GetUniverseDomainInterface ? $this->credentialsFetcher->getUniverseDomain() : GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
if ($credentialsUniverse !== $this->universeDomain) {
throw new ValidationException(\sprintf('The configured universe domain (%s) does not match the credential universe domain (%s)', $this->universeDomain, $credentialsUniverse));
}
$this->hasCheckedUniverse = \true;
}
}
/**
* @return Guzzle6HttpHandler|Guzzle7HttpHandler
* @throws ValidationException
*/
private static function buildHttpHandlerFactory()
{
try {
return HttpHandlerFactory::build();
} catch (Exception $ex) {
throw new ValidationException("Failed to build HttpHandler", $ex->getCode(), $ex);
}
}
/**
* @param array $scopes
* @param callable $authHttpHandler
* @param array $authCacheOptions
* @param CacheItemPoolInterface $authCache
* @param string $quotaProject
* @param array $defaultScopes
* @return FetchAuthTokenInterface
* @throws ValidationException
*/
private static function buildApplicationDefaultCredentials(array $scopes = null, callable $authHttpHandler = null, array $authCacheOptions = null, CacheItemPoolInterface $authCache = null, $quotaProject = null, array $defaultScopes = null)
{
try {
return ApplicationDefaultCredentials::getCredentials($scopes, $authHttpHandler, $authCacheOptions, $authCache, $quotaProject, $defaultScopes);
} catch (DomainException $ex) {
throw new ValidationException("Could not construct ApplicationDefaultCredentials", $ex->getCode(), $ex);
}
}
/**
* @param mixed $token
*/
private static function isValid($token)
{
return \is_array($token) && \array_key_exists('access_token', $token);
}
/**
* @param mixed $token
*/
private static function isExpired($token)
{
return !(self::isValid($token) && \array_key_exists('expires_at', $token) && $token['expires_at'] > \time() + self::$eagerRefreshThresholdSeconds);
}
}

View File

@@ -0,0 +1,172 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use Generator;
use InvalidArgumentException;
use IteratorAggregate;
use LengthException;
/**
* A collection of elements retrieved using one or more API calls. The
* collection will attempt to retrieve a fixed number of elements, and
* will make API calls until that fixed number is reached, or there
* are no more elements to retrieve.
*/
class FixedSizeCollection implements IteratorAggregate
{
private $collectionSize;
private $pageList;
/**
* FixedSizeCollection constructor.
* @param Page $initialPage
* @param int $collectionSize
*/
public function __construct(Page $initialPage, int $collectionSize)
{
if ($collectionSize <= 0) {
throw new InvalidArgumentException("collectionSize must be > 0. collectionSize: {$collectionSize}");
}
if ($collectionSize < $initialPage->getPageElementCount()) {
$ipc = $initialPage->getPageElementCount();
throw new InvalidArgumentException("collectionSize must be greater than or equal to the number of " . "elements in initialPage. collectionSize: {$collectionSize}, " . "initialPage size: {$ipc}");
}
$this->collectionSize = $collectionSize;
$this->pageList = FixedSizeCollection::createPageArray($initialPage, $collectionSize);
}
/**
* Returns the number of elements in the collection. This will be
* equal to the collectionSize parameter used at construction
* unless there are no elements remaining to be retrieved.
*
* @return int
*/
public function getCollectionSize()
{
$size = 0;
foreach ($this->pageList as $page) {
$size += $page->getPageElementCount();
}
return $size;
}
/**
* Returns true if there are more elements that can be retrieved
* from the API.
*
* @return bool
*/
public function hasNextCollection()
{
return $this->getLastPage()->hasNextPage();
}
/**
* Returns a page token that can be passed into the API list
* method to retrieve additional elements.
*
* @return string
*/
public function getNextPageToken()
{
return $this->getLastPage()->getNextPageToken();
}
/**
* Retrieves the next FixedSizeCollection using one or more API calls.
*
* @return FixedSizeCollection
*/
public function getNextCollection()
{
$lastPage = $this->getLastPage();
$nextPage = $lastPage->getNextPage($this->collectionSize);
return new FixedSizeCollection($nextPage, $this->collectionSize);
}
/**
* Returns an iterator over the elements of the collection.
*
* @return Generator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
foreach ($this->pageList as $page) {
foreach ($page as $element) {
(yield $element);
}
}
}
/**
* Returns an iterator over FixedSizeCollections, starting with this
* and making API calls as required until all of the elements have
* been retrieved.
*
* @return Generator|FixedSizeCollection[]
*/
public function iterateCollections()
{
$currentCollection = $this;
(yield $this);
while ($currentCollection->hasNextCollection()) {
$currentCollection = $currentCollection->getNextCollection();
(yield $currentCollection);
}
}
private function getLastPage()
{
$pageList = $this->pageList;
// Get last element in array...
$lastPage = \end($pageList);
\reset($pageList);
return $lastPage;
}
/**
* @param Page $initialPage
* @param int $collectionSize
* @return Page[]
*/
private static function createPageArray(Page $initialPage, int $collectionSize)
{
$pageList = [$initialPage];
$currentPage = $initialPage;
$itemCount = $currentPage->getPageElementCount();
while ($itemCount < $collectionSize && $currentPage->hasNextPage()) {
$remainingCount = $collectionSize - $itemCount;
$currentPage = $currentPage->getNextPage($remainingCount);
$rxElementCount = $currentPage->getPageElementCount();
if ($rxElementCount > $remainingCount) {
throw new LengthException("API returned a number of elements " . "exceeding the specified page size limit. page size: " . "{$remainingCount}, elements received: {$rxElementCount}");
}
\array_push($pageList, $currentPage);
$itemCount += $rxElementCount;
}
return $pageList;
}
}

44
vendor/Gcp/google/gax/src/GPBLabel.php vendored Normal file
View File

@@ -0,0 +1,44 @@
<?php
/*
* Copyright 2017 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Container class for Protobuf label constants. See FieldDescriptorProto.Label in
* https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto
*/
class GPBLabel
{
const OPTIONAL = 1;
const REQUIRED = 2;
const REPEATED = 3;
}

59
vendor/Gcp/google/gax/src/GPBType.php vendored Normal file
View File

@@ -0,0 +1,59 @@
<?php
/*
* Copyright 2017 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Container class for Protobuf type constants. See FieldDescriptorProto.Type in
* https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto
*/
class GPBType
{
const DOUBLE = 1;
const FLOAT = 2;
const INT64 = 3;
const UINT64 = 4;
const INT32 = 5;
const FIXED64 = 6;
const FIXED32 = 7;
const BOOL = 8;
const STRING = 9;
const GROUP = 10;
const MESSAGE = 11;
const BYTES = 12;
const UINT32 = 13;
const ENUM = 14;
const SFIXED32 = 15;
const SFIXED64 = 16;
const SINT32 = 17;
const SINT64 = 18;
}

View File

@@ -0,0 +1,701 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\LongRunning\OperationsClient;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware\CredentialsWrapperMiddleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware\FixedHeaderMiddleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware\OperationsMiddleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware\OptionsFilterMiddleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware\PagedMiddleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware\RetryMiddleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\CallOptions;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\ClientOptions;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\GrpcFallbackTransport;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\GrpcTransport;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\RestTransport;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\TransportInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\FetchAuthTokenInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\LongRunning\Operation;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Common functions used to work with various clients.
*
* @internal
*/
trait GapicClientTrait
{
use ClientOptionsTrait;
use ValidationTrait {
ValidationTrait::validate as traitValidate;
}
use GrpcSupportTrait;
private ?TransportInterface $transport = null;
private ?CredentialsWrapper $credentialsWrapper = null;
/** @var RetrySettings[] $retrySettings */
private array $retrySettings = [];
private string $serviceName = '';
private array $agentHeader = [];
private array $descriptors = [];
/** @var array<callable> $middlewareCallables */
private array $middlewareCallables = [];
private array $transportCallMethods = [Call::UNARY_CALL => 'startUnaryCall', Call::BIDI_STREAMING_CALL => 'startBidiStreamingCall', Call::CLIENT_STREAMING_CALL => 'startClientStreamingCall', Call::SERVER_STREAMING_CALL => 'startServerStreamingCall'];
private bool $backwardsCompatibilityMode;
/**
* Add a middleware to the call stack by providing a callable which will be
* invoked at the start of each call, and will return an instance of
* {@see MiddlewareInterface} when invoked.
*
* The callable must have the following method signature:
*
* callable(MiddlewareInterface): MiddlewareInterface
*
* An implementation may look something like this:
* ```
* $client->addMiddleware(function (MiddlewareInterface $handler) {
* return new class ($handler) implements MiddlewareInterface {
* public function __construct(private MiddlewareInterface $handler) {
* }
*
* public function __invoke(Call $call, array $options) {
* // modify call and options (pre-request)
* $response = ($this->handler)($call, $options);
* // modify the response (post-request)
* return $response;
* }
* };
* });
* ```
*
* @param callable $middlewareCallable A callable which returns an instance
* of {@see MiddlewareInterface} when invoked with a
* MiddlewareInterface instance as its first argument.
* @return void
*/
public function addMiddleware(callable $middlewareCallable) : void
{
$this->middlewareCallables[] = $middlewareCallable;
}
/**
* Initiates an orderly shutdown in which preexisting calls continue but new
* calls are immediately cancelled.
*
* @experimental
*/
public function close()
{
$this->transport->close();
}
/**
* Get the transport for the client. This method is protected to support
* use by customized clients.
*
* @access private
* @return TransportInterface
*/
protected function getTransport()
{
return $this->transport;
}
/**
* Get the credentials for the client. This method is protected to support
* use by customized clients.
*
* @access private
* @return CredentialsWrapper
*/
protected function getCredentialsWrapper()
{
return $this->credentialsWrapper;
}
/**
* Configures the GAPIC client based on an array of options.
*
* @param array $options {
* An array of required and optional arguments.
*
* @type string $apiEndpoint
* The address of the API remote host, for example "example.googleapis.com. May also
* include the port, for example "example.googleapis.com:443"
* @type bool $disableRetries
* Determines whether or not retries defined by the client configuration should be
* disabled. Defaults to `false`.
* @type string|array $clientConfig
* Client method configuration, including retry settings. This option can be either a
* path to a JSON file, or a PHP array containing the decoded JSON data.
* By default this settings points to the default client config file, which is provided
* in the resources folder.
* @type string|array|FetchAuthTokenInterface|CredentialsWrapper $credentials
* The credentials to be used by the client to authorize API calls. This option
* accepts either a path to a credentials file, or a decoded credentials file as a
* PHP array.
* *Advanced usage*: In addition, this option can also accept a pre-constructed
* \Google\Auth\FetchAuthTokenInterface object or \Google\ApiCore\CredentialsWrapper
* object. Note that when one of these objects are provided, any settings in
* $authConfig will be ignored.
* @type array $credentialsConfig
* Options used to configure credentials, including auth token caching, for the client.
* For a full list of supporting configuration options, see
* \Google\ApiCore\CredentialsWrapper::build.
* @type string|TransportInterface $transport
* The transport used for executing network requests. May be either the string `rest`,
* `grpc`, or 'grpc-fallback'. Defaults to `grpc` if gRPC support is detected on the system.
* *Advanced usage*: Additionally, it is possible to pass in an already instantiated
* TransportInterface object. Note that when this objects is provided, any settings in
* $transportConfig, and any `$apiEndpoint` setting, will be ignored.
* @type array $transportConfig
* Configuration options that will be used to construct the transport. Options for
* each supported transport type should be passed in a key for that transport. For
* example:
* $transportConfig = [
* 'grpc' => [...],
* 'rest' => [...],
* 'grpc-fallback' => [...],
* ];
* See the GrpcTransport::build and RestTransport::build
* methods for the supported options.
* @type string $versionFile
* The path to a file which contains the current version of the client.
* @type string $descriptorsConfigPath
* The path to a descriptor configuration file.
* @type string $serviceName
* The name of the service.
* @type string $libName
* The name of the client application.
* @type string $libVersion
* The version of the client application.
* @type string $gapicVersion
* The code generator version of the GAPIC library.
* @type callable $clientCertSource
* A callable which returns the client cert as a string.
* }
* @throws ValidationException
*/
private function setClientOptions(array $options)
{
// serviceAddress is now deprecated and acts as an alias for apiEndpoint
if (isset($options['serviceAddress'])) {
$options['apiEndpoint'] = $this->pluck('serviceAddress', $options, \false);
}
$this->validateNotNull($options, ['apiEndpoint', 'serviceName', 'descriptorsConfigPath', 'clientConfig', 'disableRetries', 'credentialsConfig', 'transportConfig']);
$this->traitValidate($options, ['credentials', 'transport', 'gapicVersion', 'libName', 'libVersion']);
if ($this->isBackwardsCompatibilityMode()) {
if (\is_string($options['clientConfig'])) {
// perform validation for V1 surfaces which is done in the
// ClientOptions class for v2 surfaces.
$options['clientConfig'] = \json_decode(\file_get_contents($options['clientConfig']), \true);
self::validateFileExists($options['descriptorsConfigPath']);
}
} else {
// cast to ClientOptions for new surfaces only
$options = new ClientOptions($options);
}
$this->serviceName = $options['serviceName'];
$this->retrySettings = RetrySettings::load($this->serviceName, $options['clientConfig'], $options['disableRetries']);
$headerInfo = ['libName' => $options['libName'], 'libVersion' => $options['libVersion'], 'gapicVersion' => $options['gapicVersion']];
// Edge case: If the client has the gRPC extension installed, but is
// a REST-only library, then the grpcVersion header should not be set.
if ($this->transport instanceof GrpcTransport) {
$headerInfo['grpcVersion'] = \phpversion('grpc');
} elseif ($this->transport instanceof RestTransport || $this->transport instanceof GrpcFallbackTransport) {
$headerInfo['restVersion'] = Version::getApiCoreVersion();
}
$this->agentHeader = AgentHeader::buildAgentHeader($headerInfo);
// Set "client_library_name" depending on client library surface being used
$userAgentHeader = \sprintf('gcloud-php-%s/%s', $this->isBackwardsCompatibilityMode() ? 'legacy' : 'new', $options['gapicVersion']);
$this->agentHeader['User-Agent'] = [$userAgentHeader];
self::validateFileExists($options['descriptorsConfigPath']);
$descriptors = (require $options['descriptorsConfigPath']);
$this->descriptors = $descriptors['interfaces'][$this->serviceName];
$this->credentialsWrapper = $this->createCredentialsWrapper($options['credentials'], $options['credentialsConfig'], $options['universeDomain']);
$transport = $options['transport'] ?: self::defaultTransport();
$this->transport = $transport instanceof TransportInterface ? $transport : $this->createTransport($options['apiEndpoint'], $transport, $options['transportConfig'], $options['clientCertSource']);
}
/**
* @param string $apiEndpoint
* @param string $transport
* @param TransportOptions|array $transportConfig
* @param callable $clientCertSource
* @return TransportInterface
* @throws ValidationException
*/
private function createTransport(string $apiEndpoint, $transport, $transportConfig, callable $clientCertSource = null)
{
if (!\is_string($transport)) {
throw new ValidationException("'transport' must be a string, instead got:" . \print_r($transport, \true));
}
$supportedTransports = self::supportedTransports();
if (!\in_array($transport, $supportedTransports)) {
throw new ValidationException(\sprintf('Unexpected transport option "%s". Supported transports: %s', $transport, \implode(', ', $supportedTransports)));
}
$configForSpecifiedTransport = $transportConfig[$transport] ?? [];
if (\is_array($configForSpecifiedTransport)) {
$configForSpecifiedTransport['clientCertSource'] = $clientCertSource;
} else {
$configForSpecifiedTransport->setClientCertSource($clientCertSource);
$configForSpecifiedTransport = $configForSpecifiedTransport->toArray();
}
switch ($transport) {
case 'grpc':
// Setting the user agent for gRPC requires special handling
if (isset($this->agentHeader['User-Agent'])) {
if ($configForSpecifiedTransport['stubOpts']['grpc.primary_user_agent'] ??= '') {
$configForSpecifiedTransport['stubOpts']['grpc.primary_user_agent'] .= ' ';
}
$configForSpecifiedTransport['stubOpts']['grpc.primary_user_agent'] .= $this->agentHeader['User-Agent'][0];
}
return GrpcTransport::build($apiEndpoint, $configForSpecifiedTransport);
case 'grpc-fallback':
return GrpcFallbackTransport::build($apiEndpoint, $configForSpecifiedTransport);
case 'rest':
if (!isset($configForSpecifiedTransport['restClientConfigPath'])) {
throw new ValidationException("The 'restClientConfigPath' config is required for 'rest' transport.");
}
$restConfigPath = $configForSpecifiedTransport['restClientConfigPath'];
return RestTransport::build($apiEndpoint, $restConfigPath, $configForSpecifiedTransport);
default:
throw new ValidationException("Unexpected 'transport' option: {$transport}. " . "Supported values: ['grpc', 'rest', 'grpc-fallback']");
}
}
/**
* @param array $options
* @return OperationsClient
*/
private function createOperationsClient(array $options)
{
$this->pluckArray(['serviceName', 'clientConfig', 'descriptorsConfigPath'], $options);
// User-supplied operations client
if ($operationsClient = $this->pluck('operationsClient', $options, \false)) {
return $operationsClient;
}
// operationsClientClass option
$operationsClientClass = $this->pluck('operationsClientClass', $options, \false) ?: OperationsCLient::class;
return new $operationsClientClass($options);
}
/**
* @return string
*/
private static function defaultTransport()
{
return self::getGrpcDependencyStatus() ? 'grpc' : 'rest';
}
private function validateCallConfig(string $methodName)
{
// Ensure a method descriptor exists for the target method.
if (!isset($this->descriptors[$methodName])) {
throw new ValidationException("Requested method '{$methodName}' does not exist in descriptor configuration.");
}
$methodDescriptors = $this->descriptors[$methodName];
// Ensure required descriptor configuration exists.
if (!isset($methodDescriptors['callType'])) {
throw new ValidationException("Requested method '{$methodName}' does not have a callType " . 'in descriptor configuration.');
}
$callType = $methodDescriptors['callType'];
// Validate various callType specific configurations.
if ($callType == Call::LONGRUNNING_CALL) {
if (!isset($methodDescriptors['longRunning'])) {
throw new ValidationException("Requested method '{$methodName}' does not have a longRunning config " . 'in descriptor configuration.');
}
// @TODO: check if the client implements `OperationsClientInterface` instead
if (!\method_exists($this, 'getOperationsClient')) {
throw new ValidationException('Client missing required getOperationsClient ' . "for longrunning call '{$methodName}'");
}
} elseif ($callType == Call::PAGINATED_CALL) {
if (!isset($methodDescriptors['pageStreaming'])) {
throw new ValidationException("Requested method '{$methodName}' with callType PAGINATED_CALL does not " . 'have a pageStreaming in descriptor configuration.');
}
}
// LRO are either Standard LRO response type or custom, which are handled by
// startOperationCall, so no need to validate responseType for those callType.
if ($callType != Call::LONGRUNNING_CALL) {
if (!isset($methodDescriptors['responseType'])) {
throw new ValidationException("Requested method '{$methodName}' does not have a responseType " . 'in descriptor configuration.');
}
}
return $methodDescriptors;
}
/**
* @param string $methodName
* @param Message $request
* @param array $optionalArgs {
* Call Options
*
* @type array $headers [optional] key-value array containing headers
* @type int $timeoutMillis [optional] the timeout in milliseconds for the call
* @type array $transportOptions [optional] transport-specific call options
* @type RetrySettings|array $retrySettings [optional] A retry settings override for the call.
* }
*
* @experimental
*
* @return PromiseInterface
*/
private function startAsyncCall(string $methodName, Message $request, array $optionalArgs = [])
{
// Convert method name to the UpperCamelCase of RPC names from lowerCamelCase of GAPIC method names
// in order to find the method in the descriptor config.
$methodName = \ucfirst($methodName);
$methodDescriptors = $this->validateCallConfig($methodName);
$callType = $methodDescriptors['callType'];
switch ($callType) {
case Call::PAGINATED_CALL:
return $this->getPagedListResponseAsync($methodName, $optionalArgs, $methodDescriptors['responseType'], $request, $methodDescriptors['interfaceOverride'] ?? $this->serviceName);
case Call::SERVER_STREAMING_CALL:
case Call::CLIENT_STREAMING_CALL:
case Call::BIDI_STREAMING_CALL:
throw new ValidationException("Call type '{$callType}' of requested method " . "'{$methodName}' is not supported for async execution.");
}
return $this->startApiCall($methodName, $request, $optionalArgs);
}
/**
* @param string $methodName
* @param Message $request
* @param array $optionalArgs {
* Call Options
*
* @type array $headers [optional] key-value array containing headers
* @type int $timeoutMillis [optional] the timeout in milliseconds for the call
* @type array $transportOptions [optional] transport-specific call options
* @type RetrySettings|array $retrySettings [optional] A retry settings
* override for the call.
* }
*
* @experimental
*
* @return PromiseInterface|PagedListResponse|BidiStream|ClientStream|ServerStream
*/
private function startApiCall(string $methodName, Message $request = null, array $optionalArgs = [])
{
$methodDescriptors = $this->validateCallConfig($methodName);
$callType = $methodDescriptors['callType'];
// Prepare request-based headers, merge with user-provided headers,
// which take precedence.
$headerParams = $methodDescriptors['headerParams'] ?? [];
$requestHeaders = $this->buildRequestParamsHeader($headerParams, $request);
$optionalArgs['headers'] = \array_merge($requestHeaders, $optionalArgs['headers'] ?? []);
// Default the interface name, if not set, to the client's protobuf service name.
$interfaceName = $methodDescriptors['interfaceOverride'] ?? $this->serviceName;
// Handle call based on call type configured in the method descriptor config.
if ($callType == Call::LONGRUNNING_CALL) {
return $this->startOperationsCall(
$methodName,
$optionalArgs,
$request,
$this->getOperationsClient(),
$interfaceName,
// Custom operations will define their own operation response type, whereas standard
// LRO defaults to the same type.
$methodDescriptors['responseType'] ?? null
);
}
// Fully-qualified name of the response message PHP class.
$decodeType = $methodDescriptors['responseType'];
if ($callType == Call::PAGINATED_CALL) {
return $this->getPagedListResponse($methodName, $optionalArgs, $decodeType, $request, $interfaceName);
}
// Unary, and all Streaming types handled by startCall.
return $this->startCall($methodName, $decodeType, $optionalArgs, $request, $callType, $interfaceName);
}
/**
* @param string $methodName
* @param string $decodeType
* @param array $optionalArgs {
* Call Options
*
* @type array $headers [optional] key-value array containing headers
* @type int $timeoutMillis [optional] the timeout in milliseconds for the call
* @type array $transportOptions [optional] transport-specific call options
* @type RetrySettings|array $retrySettings [optional] A retry settings
* override for the call.
* }
* @param Message $request
* @param int $callType
* @param string $interfaceName
*
* @return PromiseInterface|BidiStream|ClientStream|ServerStream
*/
private function startCall(string $methodName, string $decodeType, array $optionalArgs = [], Message $request = null, int $callType = Call::UNARY_CALL, string $interfaceName = null)
{
$optionalArgs = $this->configureCallOptions($optionalArgs);
$callStack = $this->createCallStack($this->configureCallConstructionOptions($methodName, $optionalArgs));
$descriptor = $this->descriptors[$methodName]['grpcStreaming'] ?? null;
$call = new Call($this->buildMethod($interfaceName, $methodName), $decodeType, $request, $descriptor, $callType);
switch ($callType) {
case Call::UNARY_CALL:
$this->modifyUnaryCallable($callStack);
break;
case Call::BIDI_STREAMING_CALL:
case Call::CLIENT_STREAMING_CALL:
case Call::SERVER_STREAMING_CALL:
$this->modifyStreamingCallable($callStack);
break;
}
return $callStack($call, $optionalArgs + \array_filter(['audience' => self::getDefaultAudience()]));
}
/**
* @param array $callConstructionOptions {
* Call Construction Options
*
* @type RetrySettings $retrySettings [optional] A retry settings override
* For the call.
* }
*
* @return callable
*/
private function createCallStack(array $callConstructionOptions)
{
$quotaProject = $this->credentialsWrapper->getQuotaProject();
$fixedHeaders = $this->agentHeader;
if ($quotaProject) {
$fixedHeaders += ['X-Goog-User-Project' => [$quotaProject]];
}
$callStack = function (Call $call, array $options) {
$startCallMethod = $this->transportCallMethods[$call->getCallType()];
return $this->transport->{$startCallMethod}($call, $options);
};
$callStack = new CredentialsWrapperMiddleware($callStack, $this->credentialsWrapper);
$callStack = new FixedHeaderMiddleware($callStack, $fixedHeaders, \true);
$callStack = new RetryMiddleware($callStack, $callConstructionOptions['retrySettings']);
$callStack = new OptionsFilterMiddleware($callStack, ['headers', 'timeoutMillis', 'transportOptions', 'metadataCallback', 'audience', 'metadataReturnType']);
foreach (\array_reverse($this->middlewareCallables) as $fn) {
/** @var MiddlewareInterface $callStack */
$callStack = $fn($callStack);
}
return $callStack;
}
/**
* @param string $methodName
* @param array $optionalArgs {
* Optional arguments
*
* @type RetrySettings|array $retrySettings [optional] A retry settings
* override for the call.
* }
*
* @return array
*/
private function configureCallConstructionOptions(string $methodName, array $optionalArgs)
{
$retrySettings = $this->retrySettings[$methodName];
// Allow for retry settings to be changed at call time
if (isset($optionalArgs['retrySettings'])) {
if ($optionalArgs['retrySettings'] instanceof RetrySettings) {
$retrySettings = $optionalArgs['retrySettings'];
} else {
$retrySettings = $retrySettings->with($optionalArgs['retrySettings']);
}
}
return ['retrySettings' => $retrySettings];
}
/**
* @return array
*/
private function configureCallOptions(array $optionalArgs) : array
{
if ($this->isBackwardsCompatibilityMode()) {
return $optionalArgs;
}
// cast to CallOptions for new surfaces only
return (new CallOptions($optionalArgs))->toArray();
}
/**
* @param string $methodName
* @param array $optionalArgs {
* Call Options
*
* @type array $headers [optional] key-value array containing headers
* @type int $timeoutMillis [optional] the timeout in milliseconds for the call
* @type array $transportOptions [optional] transport-specific call options
* }
* @param Message $request
* @param OperationsClient|object $client
* @param string $interfaceName
* @param string $operationClass If provided, will be used instead of the default
* operation response class of {@see \Google\LongRunning\Operation}.
*
* @return PromiseInterface
*/
private function startOperationsCall(string $methodName, array $optionalArgs, Message $request, $client, string $interfaceName = null, string $operationClass = null)
{
$optionalArgs = $this->configureCallOptions($optionalArgs);
$callStack = $this->createCallStack($this->configureCallConstructionOptions($methodName, $optionalArgs));
$descriptor = $this->descriptors[$methodName]['longRunning'];
$metadataReturnType = null;
// Call the methods supplied in "additionalArgumentMethods" on the request Message object
// to build the "additionalOperationArguments" option for the operation response.
if (isset($descriptor['additionalArgumentMethods'])) {
$additionalArgs = [];
foreach ($descriptor['additionalArgumentMethods'] as $additionalArgsMethodName) {
$additionalArgs[] = $request->{$additionalArgsMethodName}();
}
$descriptor['additionalOperationArguments'] = $additionalArgs;
unset($descriptor['additionalArgumentMethods']);
}
if (isset($descriptor['metadataReturnType'])) {
$metadataReturnType = $descriptor['metadataReturnType'];
}
$callStack = new OperationsMiddleware($callStack, $client, $descriptor);
$call = new Call($this->buildMethod($interfaceName, $methodName), $operationClass ?: Operation::class, $request, [], Call::UNARY_CALL);
$this->modifyUnaryCallable($callStack);
return $callStack($call, $optionalArgs + \array_filter(['metadataReturnType' => $metadataReturnType, 'audience' => self::getDefaultAudience()]));
}
/**
* @param string $methodName
* @param array $optionalArgs
* @param string $decodeType
* @param Message $request
* @param string $interfaceName
*
* @return PagedListResponse
*/
private function getPagedListResponse(string $methodName, array $optionalArgs, string $decodeType, Message $request, string $interfaceName = null)
{
return $this->getPagedListResponseAsync($methodName, $optionalArgs, $decodeType, $request, $interfaceName)->wait();
}
/**
* @param string $methodName
* @param array $optionalArgs
* @param string $decodeType
* @param Message $request
* @param string $interfaceName
*
* @return PromiseInterface
*/
private function getPagedListResponseAsync(string $methodName, array $optionalArgs, string $decodeType, Message $request, string $interfaceName = null)
{
$optionalArgs = $this->configureCallOptions($optionalArgs);
$callStack = $this->createCallStack($this->configureCallConstructionOptions($methodName, $optionalArgs));
$descriptor = new PageStreamingDescriptor($this->descriptors[$methodName]['pageStreaming']);
$callStack = new PagedMiddleware($callStack, $descriptor);
$call = new Call($this->buildMethod($interfaceName, $methodName), $decodeType, $request, [], Call::UNARY_CALL);
$this->modifyUnaryCallable($callStack);
return $callStack($call, $optionalArgs + \array_filter(['audience' => self::getDefaultAudience()]));
}
/**
* @param string $interfaceName
* @param string $methodName
*
* @return string
*/
private function buildMethod(string $interfaceName = null, string $methodName = null)
{
return \sprintf('%s/%s', $interfaceName ?: $this->serviceName, $methodName);
}
/**
* @param array $headerParams
* @param Message|null $request
*
* @return array
*/
private function buildRequestParamsHeader(array $headerParams, Message $request = null)
{
$headers = [];
// No request message means no request-based headers.
if (!$request) {
return $headers;
}
foreach ($headerParams as $headerParam) {
$msg = $request;
$value = null;
foreach ($headerParam['fieldAccessors'] as $accessor) {
$value = $msg->{$accessor}();
// In case the field in question is nested in another message,
// skip the header param when the nested message field is unset.
$msg = $value;
if (\is_null($msg)) {
break;
}
}
$keyName = $headerParam['keyName'];
// If there are value pattern matchers configured and the target
// field was set, evaluate the matchers in the order that they were
// annotated in with last one matching wins.
$original = $value;
$matchers = isset($headerParam['matchers']) && !\is_null($value) ? $headerParam['matchers'] : [];
foreach ($matchers as $matcher) {
$matches = [];
if (\preg_match($matcher, $original, $matches)) {
$value = $matches[$keyName];
}
}
// If there are no matches or the target field was unset, skip this
// header param.
if (!$value) {
continue;
}
$headers[$keyName] = $value;
}
$requestParams = new RequestParamsHeaderDescriptor($headers);
return $requestParams->getHeader();
}
/**
* The SERVICE_ADDRESS constant is set by GAPIC clients
*/
private static function getDefaultAudience()
{
if (!\defined('self::SERVICE_ADDRESS')) {
return null;
}
return 'https://' . self::SERVICE_ADDRESS . '/';
// @phpstan-ignore-line
}
/**
* Modify the unary callable.
*
* @param callable $callable
* @access private
*/
protected function modifyUnaryCallable(callable &$callable)
{
// Do nothing - this method exists to allow callable modification by partial veneers.
}
/**
* Modify the streaming callable.
*
* @param callable $callable
* @access private
*/
protected function modifyStreamingCallable(callable &$callable)
{
// Do nothing - this method exists to allow callable modification by partial veneers.
}
/**
* @internal
*/
private function isBackwardsCompatibilityMode() : bool
{
return $this->backwardsCompatibilityMode ?? ($this->backwardsCompatibilityMode = \substr(__CLASS__, -11) === 'GapicClient');
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Provides helper methods for gRPC support.
*
* @internal
*/
trait GrpcSupportTrait
{
/**
* @return bool
*/
private static function getGrpcDependencyStatus()
{
return \extension_loaded('grpc');
}
/**
* @throws ValidationException
*/
private static function validateGrpcSupport()
{
if (!self::getGrpcDependencyStatus()) {
throw new ValidationException('gRPC support has been requested but required dependencies ' . 'have not been found. For details on how to install the ' . 'gRPC extension please see https://cloud.google.com/php/grpc.');
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* Copyright 2024 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* For connect to emulator.
*/
class InsecureCredentialsWrapper extends CredentialsWrapper
{
public function __construct()
{
}
/**
* @param string $audience
* @return callable|null Returns null so the gRPC can accept it as an insecure channel.
*/
public function getAuthorizationHeaderCallback($audience = null) : ?callable
{
return null;
}
public function checkUniverseDomain() : void
{
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\CredentialsWrapper;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware which adds a CredentialsWrapper object to the call options.
*/
class CredentialsWrapperMiddleware implements MiddlewareInterface
{
/** @var callable */
private $nextHandler;
private CredentialsWrapper $credentialsWrapper;
public function __construct(callable $nextHandler, CredentialsWrapper $credentialsWrapper)
{
$this->nextHandler = $nextHandler;
$this->credentialsWrapper = $credentialsWrapper;
}
public function __invoke(Call $call, array $options)
{
$next = $this->nextHandler;
return $next($call, $options + ['credentialsWrapper' => $this->credentialsWrapper]);
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware to add fixed headers to an API call.
*/
class FixedHeaderMiddleware implements MiddlewareInterface
{
/** @var callable */
private $nextHandler;
private array $headers;
private bool $overrideUserHeaders;
public function __construct(callable $nextHandler, array $headers, bool $overrideUserHeaders = \false)
{
$this->nextHandler = $nextHandler;
$this->headers = $headers;
$this->overrideUserHeaders = $overrideUserHeaders;
}
public function __invoke(Call $call, array $options)
{
$userHeaders = $options['headers'] ?? [];
if ($this->overrideUserHeaders) {
$options['headers'] = $this->headers + $userHeaders;
} else {
$options['headers'] = $userHeaders + $this->headers;
}
$next = $this->nextHandler;
return $next($call, $options);
}
}

View File

@@ -0,0 +1,90 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ClientStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServerStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\BidiStream;
/**
* Middlewares must take a MiddlewareInterface as their first constructor
* argument {@see Google\ApiCore\Middleware\ResponseMetadataMiddleware}, which
* represents the next middleware in the chain. This next middleware MUST be
* invoked by this MiddlewareInterface, and the result must be returned as part
* of the `__invoke` method implementation.
*
* To create your own middleware, first implement the interface, as well as pass the handler
* in through the constructor:
*
* ```
* use Google\ApiCore\Call;
* use Google\ApiCore\Middleware\MiddlewareInterface;
*
* class MyTestMiddleware implements MiddlewareInterface
* {
* public function __construct(MiddlewareInterface $handler)
* {
*. $this->handler = $handler;
* }
* public function __invoke(Call $call, array $options)
* {
* echo "Logging info about the call: " . $call->getMethod();
* return ($this->handler)($call, $options);
* }
* }
* ```
*
* Next, add the middleware to any class implementing `GapicClientTrait` by passing in a
* callable which returns the new middleware:
*
* ```
* $client = new ExampleGoogleApiServiceClient();
* $client->addMiddleware(function (MiddlewareInterface $handler) {
* return new MyTestMiddleware($handler);
* });
* ```
*/
interface MiddlewareInterface
{
/**
* Modify or observe the API call request and response.
* The returned value must include the result of the next MiddlewareInterface invocation in the
* chain.
*
* @param Call $call
* @param array $options
* @return PromiseInterface|ClientStream|ServerStream|BidiStream
*/
public function __invoke(Call $call, array $options);
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\OperationResponse;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware which wraps the response in an OperationResponse object.
*/
class OperationsMiddleware implements MiddlewareInterface
{
/** @var callable */
private $nextHandler;
private object $operationsClient;
private array $descriptor;
public function __construct(callable $nextHandler, $operationsClient, array $descriptor)
{
$this->nextHandler = $nextHandler;
$this->operationsClient = $operationsClient;
$this->descriptor = $descriptor;
}
public function __invoke(Call $call, array $options)
{
$next = $this->nextHandler;
return $next($call, $options)->then(function (Message $response) {
$options = $this->descriptor + ['lastProtoResponse' => $response];
$operationNameMethod = $options['operationNameMethod'] ?? 'getName';
$operationName = \call_user_func([$response, $operationNameMethod]);
return new OperationResponse($operationName, $this->operationsClient, $options);
});
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ArrayTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware which filters the $options array.
*/
class OptionsFilterMiddleware implements MiddlewareInterface
{
use ArrayTrait;
/** @var callable */
private $nextHandler;
private array $permittedOptions;
public function __construct(callable $nextHandler, array $permittedOptions)
{
$this->nextHandler = $nextHandler;
$this->permittedOptions = $permittedOptions;
}
public function __invoke(Call $call, array $options)
{
$next = $this->nextHandler;
$filteredOptions = $this->pluckArray($this->permittedOptions, $options);
return $next($call, $filteredOptions);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Page;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\PagedListResponse;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\PageStreamingDescriptor;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware which wraps the response in an PagedListResponses object.
*/
class PagedMiddleware implements MiddlewareInterface
{
/** @var callable */
private $nextHandler;
private PageStreamingDescriptor $descriptor;
/**
* @param callable $nextHandler
* @param PageStreamingDescriptor $descriptor
*/
public function __construct(callable $nextHandler, PageStreamingDescriptor $descriptor)
{
$this->nextHandler = $nextHandler;
$this->descriptor = $descriptor;
}
public function __invoke(Call $call, array $options)
{
$next = $this->nextHandler;
$descriptor = $this->descriptor;
return $next($call, $options)->then(function (Message $response) use($call, $next, $options, $descriptor) {
$page = new Page($call, $options, $next, $descriptor, $response);
return new PagedListResponse($page);
});
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\Promise;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware which transforms $response into [$response, $metadata]
*/
class ResponseMetadataMiddleware implements MiddlewareInterface
{
/** @var callable */
private $nextHandler;
/**
* @param callable $nextHandler
*/
public function __construct(callable $nextHandler)
{
$this->nextHandler = $nextHandler;
}
public function __invoke(Call $call, array $options)
{
$metadataReceiver = new Promise();
$options['metadataCallback'] = function ($metadata) use($metadataReceiver) {
$metadataReceiver->resolve($metadata);
};
$next = $this->nextHandler;
return $next($call, $options)->then(function ($response) use($metadataReceiver) {
if ($metadataReceiver->getState() === PromiseInterface::FULFILLED) {
return [$response, $metadataReceiver->wait()];
} else {
return [$response, []];
}
});
}
}

View File

@@ -0,0 +1,150 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Middleware;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiStatus;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\RetrySettings;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
/**
* Middleware that adds retry functionality.
*/
class RetryMiddleware implements MiddlewareInterface
{
/** @var callable */
private $nextHandler;
private RetrySettings $retrySettings;
private ?float $deadlineMs;
/*
* The number of retries that have already been attempted.
* The original API call will have $retryAttempts set to 0.
*/
private int $retryAttempts;
public function __construct(callable $nextHandler, RetrySettings $retrySettings, $deadlineMs = null, $retryAttempts = 0)
{
$this->nextHandler = $nextHandler;
$this->retrySettings = $retrySettings;
$this->deadlineMs = $deadlineMs;
$this->retryAttempts = $retryAttempts;
}
/**
* @param Call $call
* @param array $options
*
* @return PromiseInterface
*/
public function __invoke(Call $call, array $options)
{
$nextHandler = $this->nextHandler;
if (!isset($options['timeoutMillis'])) {
// default to "noRetriesRpcTimeoutMillis" when retries are disabled, otherwise use "initialRpcTimeoutMillis"
if (!$this->retrySettings->retriesEnabled() && $this->retrySettings->getNoRetriesRpcTimeoutMillis() > 0) {
$options['timeoutMillis'] = $this->retrySettings->getNoRetriesRpcTimeoutMillis();
} elseif ($this->retrySettings->getInitialRpcTimeoutMillis() > 0) {
$options['timeoutMillis'] = $this->retrySettings->getInitialRpcTimeoutMillis();
}
}
// Call the handler immediately if retry settings are disabled.
if (!$this->retrySettings->retriesEnabled()) {
return $nextHandler($call, $options);
}
return $nextHandler($call, $options)->then(null, function ($e) use($call, $options) {
$retryFunction = $this->getRetryFunction();
// If the number of retries has surpassed the max allowed retries
// then throw the exception as we normally would.
// If the maxRetries is set to 0, then we don't check this condition.
if (0 !== $this->retrySettings->getMaxRetries() && $this->retryAttempts >= $this->retrySettings->getMaxRetries()) {
throw $e;
}
// If the retry function returns false then throw the
// exception as we normally would.
if (!$retryFunction($e, $options)) {
throw $e;
}
// Retry function returned true, so we attempt another retry
return $this->retry($call, $options, $e->getStatus());
});
}
/**
* @param Call $call
* @param array $options
* @param string $status
*
* @return PromiseInterface
* @throws ApiException
*/
private function retry(Call $call, array $options, string $status)
{
$delayMult = $this->retrySettings->getRetryDelayMultiplier();
$maxDelayMs = $this->retrySettings->getMaxRetryDelayMillis();
$timeoutMult = $this->retrySettings->getRpcTimeoutMultiplier();
$maxTimeoutMs = $this->retrySettings->getMaxRpcTimeoutMillis();
$totalTimeoutMs = $this->retrySettings->getTotalTimeoutMillis();
$delayMs = $this->retrySettings->getInitialRetryDelayMillis();
$timeoutMs = $options['timeoutMillis'];
$currentTimeMs = $this->getCurrentTimeMs();
$deadlineMs = $this->deadlineMs ?: $currentTimeMs + $totalTimeoutMs;
if ($currentTimeMs >= $deadlineMs) {
throw new ApiException('Retry total timeout exceeded.', \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code::DEADLINE_EXCEEDED, ApiStatus::DEADLINE_EXCEEDED);
}
$delayMs = \min($delayMs * $delayMult, $maxDelayMs);
$timeoutMs = (int) \min($timeoutMs * $timeoutMult, $maxTimeoutMs, $deadlineMs - $this->getCurrentTimeMs());
$nextHandler = new RetryMiddleware($this->nextHandler, $this->retrySettings->with(['initialRetryDelayMillis' => $delayMs]), $deadlineMs, $this->retryAttempts + 1);
// Set the timeout for the call
$options['timeoutMillis'] = $timeoutMs;
return $nextHandler($call, $options);
}
protected function getCurrentTimeMs()
{
return \microtime(\true) * 1000.0;
}
/**
* This is the default retry behaviour.
*/
private function getRetryFunction()
{
return $this->retrySettings->getRetryFunction() ?? function (\Throwable $e, array $options) : bool {
// This is the default retry behaviour, i.e. we don't retry an ApiException
// and for other exception types, we only retry when the error code is in
// the list of retryable error codes.
if (!$e instanceof ApiException) {
return \false;
}
if (!\in_array($e->getStatus(), $this->retrySettings->getRetryableCodes())) {
return \false;
}
return \true;
};
}
}

View File

@@ -0,0 +1,414 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\LongRunning\Operation;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Any;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Status;
use LogicException;
/**
* Response object from a long running API method.
*
* The OperationResponse object is returned by API methods that perform
* a long running operation. It provides methods that can be used to
* poll the status of the operation, retrieve the results, and cancel
* the operation.
*
* To support a long running operation, the server must implement the
* Operations API, which is used by the OperationResponse object. If
* more control is required, it is possible to make calls against the
* Operations API directly instead of via the OperationResponse object
* using an Operations Client instance.
*/
class OperationResponse
{
use PollingTrait;
const DEFAULT_POLLING_INTERVAL = 1000;
const DEFAULT_POLLING_MULTIPLIER = 2;
const DEFAULT_MAX_POLLING_INTERVAL = 60000;
const DEFAULT_MAX_POLLING_DURATION = 0;
private string $operationName;
private ?object $operationsClient;
private ?string $operationReturnType;
private ?string $metadataReturnType;
private array $defaultPollSettings = ['initialPollDelayMillis' => self::DEFAULT_POLLING_INTERVAL, 'pollDelayMultiplier' => self::DEFAULT_POLLING_MULTIPLIER, 'maxPollDelayMillis' => self::DEFAULT_MAX_POLLING_INTERVAL, 'totalPollTimeoutMillis' => self::DEFAULT_MAX_POLLING_DURATION];
private ?object $lastProtoResponse;
private bool $deleted = \false;
private array $additionalArgs;
private string $getOperationMethod;
private ?string $cancelOperationMethod;
private ?string $deleteOperationMethod;
private string $operationStatusMethod;
/** @var mixed */
private $operationStatusDoneValue;
private ?string $operationErrorCodeMethod;
private ?string $operationErrorMessageMethod;
/**
* OperationResponse constructor.
*
* @param string $operationName
* @param object $operationsClient
* @param array $options {
* Optional. Options for configuring the operation response object.
*
* @type string $operationReturnType The return type of the longrunning operation.
* @type string $metadataReturnType The type of the metadata returned in the operation response.
* @type int $initialPollDelayMillis The initial polling interval to use, in milliseconds.
* @type int $pollDelayMultiplier Multiplier applied to the polling interval on each retry.
* @type int $maxPollDelayMillis The maximum polling interval to use, in milliseconds.
* @type int $totalPollTimeoutMillis The maximum amount of time to continue polling.
* @type object $lastProtoResponse A response already received from the server.
* @type string $getOperationMethod The method on $operationsClient to get the operation.
* @type string $cancelOperationMethod The method on $operationsClient to cancel the operation.
* @type string $deleteOperationMethod The method on $operationsClient to delete the operation.
* @type string $operationStatusMethod The method on the operation to get the status.
* @type string $operationStatusDoneValue The method on the operation to determine if the status is done.
* @type array $additionalOperationArguments Additional arguments to pass to $operationsClient methods.
* @type string $operationErrorCodeMethod The method on the operation to get the error code
* @type string $operationErrorMessageMethod The method on the operation to get the error status
* }
*/
public function __construct(string $operationName, $operationsClient, array $options = [])
{
$this->operationName = $operationName;
$this->operationsClient = $operationsClient;
$options += ['operationReturnType' => null, 'metadataReturnType' => null, 'lastProtoResponse' => null, 'getOperationMethod' => 'getOperation', 'cancelOperationMethod' => 'cancelOperation', 'deleteOperationMethod' => 'deleteOperation', 'operationStatusMethod' => 'getDone', 'operationStatusDoneValue' => \true, 'additionalOperationArguments' => [], 'operationErrorCodeMethod' => null, 'operationErrorMessageMethod' => null];
$this->operationReturnType = $options['operationReturnType'];
$this->metadataReturnType = $options['metadataReturnType'];
$this->lastProtoResponse = $options['lastProtoResponse'];
$this->getOperationMethod = $options['getOperationMethod'];
$this->cancelOperationMethod = $options['cancelOperationMethod'];
$this->deleteOperationMethod = $options['deleteOperationMethod'];
$this->additionalArgs = $options['additionalOperationArguments'];
$this->operationStatusMethod = $options['operationStatusMethod'];
$this->operationStatusDoneValue = $options['operationStatusDoneValue'];
$this->operationErrorCodeMethod = $options['operationErrorCodeMethod'];
$this->operationErrorMessageMethod = $options['operationErrorMessageMethod'];
if (isset($options['initialPollDelayMillis'])) {
$this->defaultPollSettings['initialPollDelayMillis'] = $options['initialPollDelayMillis'];
}
if (isset($options['pollDelayMultiplier'])) {
$this->defaultPollSettings['pollDelayMultiplier'] = $options['pollDelayMultiplier'];
}
if (isset($options['maxPollDelayMillis'])) {
$this->defaultPollSettings['maxPollDelayMillis'] = $options['maxPollDelayMillis'];
}
if (isset($options['totalPollTimeoutMillis'])) {
$this->defaultPollSettings['totalPollTimeoutMillis'] = $options['totalPollTimeoutMillis'];
}
}
/**
* Check whether the operation has completed.
*
* @return bool
*/
public function isDone()
{
if (!$this->hasProtoResponse()) {
return \false;
}
$status = \call_user_func([$this->lastProtoResponse, $this->operationStatusMethod]);
if (\is_null($status)) {
return \false;
}
return $status === $this->operationStatusDoneValue;
}
/**
* Check whether the operation completed successfully. If the operation is not complete, or if the operation
* failed, return false.
*
* @return bool
*/
public function operationSucceeded()
{
if (!$this->hasProtoResponse()) {
return \false;
}
if (!$this->canHaveResult()) {
// For Operations which do not have a result, we consider a successful
// operation when the operation has completed without errors.
return $this->isDone() && !$this->hasErrors();
}
return !\is_null($this->getResult());
}
/**
* Check whether the operation failed. If the operation is not complete, or if the operation
* succeeded, return false.
*
* @return bool
*/
public function operationFailed()
{
return $this->hasErrors();
}
/**
* Get the formatted name of the operation
*
* @return string The formatted name of the operation
*/
public function getName()
{
return $this->operationName;
}
/**
* Poll the server in a loop until the operation is complete.
*
* Return true if the operation completed, otherwise return false. If the
* $options['totalPollTimeoutMillis'] setting is not set (or set <= 0) then
* pollUntilComplete will continue polling until the operation completes,
* and therefore will always return true.
*
* @param array $options {
* Options for configuring the polling behaviour.
*
* @type int $initialPollDelayMillis The initial polling interval to use, in milliseconds.
* @type int $pollDelayMultiplier Multiplier applied to the polling interval on each retry.
* @type int $maxPollDelayMillis The maximum polling interval to use, in milliseconds.
* @type int $totalPollTimeoutMillis The maximum amount of time to continue polling, in milliseconds.
* }
* @throws ApiException If an API call fails.
* @throws ValidationException
* @return bool Indicates if the operation completed.
*/
public function pollUntilComplete(array $options = [])
{
if ($this->isDone()) {
return \true;
}
$pollSettings = \array_merge($this->defaultPollSettings, $options);
return $this->poll(function () {
$this->reload();
return $this->isDone();
}, $pollSettings);
}
/**
* Reload the status of the operation with a request to the service.
*
* @throws ApiException If the API call fails.
* @throws ValidationException If called on a deleted operation.
*/
public function reload()
{
if ($this->deleted) {
throw new ValidationException("Cannot call reload() on a deleted operation");
}
$this->lastProtoResponse = $this->operationsCall($this->getOperationMethod, $this->getName(), $this->additionalArgs);
}
/**
* Return the result of the operation. If operationSucceeded() is false, return null.
*
* @return mixed|null The result of the operation, or null if operationSucceeded() is false
*/
public function getResult()
{
if (!$this->hasProtoResponse()) {
return null;
}
if (!$this->canHaveResult()) {
return null;
}
if (!$this->isDone()) {
return null;
}
/** @var Any|null $anyResponse */
$anyResponse = $this->lastProtoResponse->getResponse();
if (\is_null($anyResponse)) {
return null;
}
if (\is_null($this->operationReturnType)) {
return $anyResponse;
}
$operationReturnType = $this->operationReturnType;
/** @var Message $response */
$response = new $operationReturnType();
$response->mergeFromString($anyResponse->getValue());
return $response;
}
/**
* If the operation failed, return the status. If operationFailed() is false, return null.
*
* @return Status|null The status of the operation in case of failure, or null if
* operationFailed() is false.
*/
public function getError()
{
if (!$this->hasProtoResponse() || !$this->isDone()) {
return null;
}
if ($this->operationErrorCodeMethod || $this->operationErrorMessageMethod) {
$errorCode = $this->operationErrorCodeMethod ? \call_user_func([$this->lastProtoResponse, $this->operationErrorCodeMethod]) : null;
$errorMessage = $this->operationErrorMessageMethod ? \call_user_func([$this->lastProtoResponse, $this->operationErrorMessageMethod]) : null;
return (new Status())->setCode(ApiStatus::rpcCodeFromHttpStatusCode($errorCode))->setMessage($errorMessage);
}
if (\method_exists($this->lastProtoResponse, 'getError')) {
return $this->lastProtoResponse->getError();
}
return null;
}
/**
* Get an array containing the values of 'operationReturnType', 'metadataReturnType', and
* the polling options `initialPollDelayMillis`, `pollDelayMultiplier`, `maxPollDelayMillis`,
* and `totalPollTimeoutMillis`. The array can be passed as the $options argument to the
* constructor when creating another OperationResponse object.
*
* @return array
*/
public function getDescriptorOptions()
{
return ['operationReturnType' => $this->operationReturnType, 'metadataReturnType' => $this->metadataReturnType] + $this->defaultPollSettings;
}
/**
* @return Operation|mixed|null The last Operation object received from the server.
*/
public function getLastProtoResponse()
{
return $this->lastProtoResponse;
}
/**
* @return object The OperationsClient object used to make
* requests to the operations API.
*/
public function getOperationsClient()
{
return $this->operationsClient;
}
/**
* Cancel the long-running operation.
*
* For operations of type Google\LongRunning\Operation, this method starts
* asynchronous cancellation on a long-running operation. The server
* makes a best effort to cancel the operation, but success is not
* guaranteed. If the server doesn't support this method, it will throw an
* ApiException with code \Google\Rpc\Code::UNIMPLEMENTED. Clients can continue
* to use reload and pollUntilComplete methods to check whether the cancellation
* succeeded or whether the operation completed despite cancellation.
* On successful cancellation, the operation is not deleted; instead, it becomes
* an operation with a getError() value with a \Google\Rpc\Status code of 1,
* corresponding to \Google\Rpc\Code::CANCELLED.
*
* @throws ApiException If the API call fails.
* @throws LogicException If the API call method has not been configured
*/
public function cancel()
{
if (\is_null($this->cancelOperationMethod)) {
throw new LogicException('The cancel operation is not supported by this API');
}
$this->operationsCall($this->cancelOperationMethod, $this->getName(), $this->additionalArgs);
}
/**
* Delete the long-running operation.
*
* For operations of type Google\LongRunning\Operation, this method
* indicates that the client is no longer interested in the operation result.
* It does not cancel the operation. If the server doesn't support this method,
* it will throw an ApiException with code \Google\Rpc\Code::UNIMPLEMENTED.
*
* @throws ApiException If the API call fails.
* @throws LogicException If the API call method has not been configured
*/
public function delete()
{
if (\is_null($this->deleteOperationMethod)) {
throw new LogicException('The delete operation is not supported by this API');
}
$this->operationsCall($this->deleteOperationMethod, $this->getName(), $this->additionalArgs);
$this->deleted = \true;
}
/**
* Get the metadata returned with the last proto response. If a metadata type was provided, then
* the return value will be of that type - otherwise, the return value will be of type Any. If
* no metadata object is available, returns null.
*
* @return mixed The metadata returned from the server in the last response.
*/
public function getMetadata()
{
if (!$this->hasProtoResponse()) {
return null;
}
if (!\method_exists($this->lastProtoResponse, 'getMetadata')) {
// The call to getMetadata is only for OnePlatform LROs, and is not
// supported by other LRO GAPIC clients (e.g. Compute)
return null;
}
/** @var Any|null $any */
$any = $this->lastProtoResponse->getMetadata();
if (\is_null($this->metadataReturnType)) {
return $any;
}
if (\is_null($any)) {
return null;
}
// @TODO: This is probably not doing anything and can be removed in the next release.
if (\is_null($any->getValue())) {
return null;
}
$metadataReturnType = $this->metadataReturnType;
/** @var Message $metadata */
$metadata = new $metadataReturnType();
$metadata->mergeFromString($any->getValue());
return $metadata;
}
private function operationsCall($method, $name, array $additionalArgs)
{
$args = \array_merge([$name], $additionalArgs);
return \call_user_func_array([$this->operationsClient, $method], $args);
}
private function canHaveResult()
{
// The call to getResponse is only for OnePlatform LROs, and is not
// supported by other LRO GAPIC clients (e.g. Compute)
return \method_exists($this->lastProtoResponse, 'getResponse');
}
private function hasErrors()
{
if (!$this->hasProtoResponse()) {
return \false;
}
if (\method_exists($this->lastProtoResponse, 'getError')) {
return !empty($this->lastProtoResponse->getError());
}
if ($this->operationErrorCodeMethod) {
$errorCode = \call_user_func([$this->lastProtoResponse, $this->operationErrorCodeMethod]);
return !empty($errorCode);
}
// This should never happen unless an API is misconfigured
throw new LogicException('Unable to determine operation error status for this service');
}
private function hasProtoResponse()
{
return !\is_null($this->lastProtoResponse);
}
}

View File

@@ -0,0 +1,138 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options;
use ArrayAccess;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\CredentialsWrapper;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\RetrySettings;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\TransportInterface;
/**
* The CallOptions class provides typing to the associative array of options
* passed to transport RPC methods. See {@see TransportInterface::startUnaryCall()},
* {@see TransportInterface::startBidiStreamingCall()},
* {@see TransportInterface::startClientStreamingCall()}, and
* {@see TransportInterface::startServerStreamingCall()}.
*/
class CallOptions implements ArrayAccess
{
use OptionsTrait;
private array $headers;
private ?int $timeoutMillis;
private array $transportOptions;
/** @var RetrySettings|array|null $retrySettings */
private $retrySettings;
/**
* @param array $options {
* Call options
*
* @type array $headers
* Key-value array containing headers
* @type int $timeoutMillis
* The timeout in milliseconds for the call.
* @type array $transportOptions
* Transport-specific call options. See {@see CallOptions::setTransportOptions}.
* @type RetrySettings|array $retrySettings
* A retry settings override for the call. If $retrySettings is an
* array, the settings will be merged with the method's default
* retry settings. If $retrySettings is a RetrySettings object,
* that object will be used instead of the method defaults.
* }
*/
public function __construct(array $options)
{
$this->fromArray($options);
}
/**
* Sets the array of options as class properites.
*
* @param array $arr See the constructor for the list of supported options.
*/
private function fromArray(array $arr) : void
{
$this->setHeaders($arr['headers'] ?? []);
$this->setTimeoutMillis($arr['timeoutMillis'] ?? null);
$this->setTransportOptions($arr['transportOptions'] ?? []);
$this->setRetrySettings($arr['retrySettings'] ?? null);
}
/**
* @param array $headers
*/
public function setHeaders(array $headers)
{
$this->headers = $headers;
}
/**
* @param int|null $timeoutMillis
*/
public function setTimeoutMillis(?int $timeoutMillis)
{
$this->timeoutMillis = $timeoutMillis;
}
/**
* @param array $transportOptions {
* Transport-specific call-time options.
*
* @type array $grpcOptions
* Key-value pairs for gRPC-specific options passed as the `$options` argument to {@see \Grpc\BaseStub}
* request methods. Current options are `call_credentials_callback` and `timeout`.
* **NOTE**: This library sets `call_credentials_callback` using {@see CredentialsWrapper}, and `timeout`
* using the `timeoutMillis` call option, so these options are not very useful.
* @type array $grpcFallbackOptions
* Key-value pairs for gRPC fallback specific options passed as the `$options` argument to the
* `$httpHandler` callable. By default these are passed to {@see \GuzzleHttp\Client} as request options.
* See {@link https://docs.guzzlephp.org/en/stable/request-options.html}.
* @type array $restOptions
* Key-value pairs for REST-specific options passed as the `$options` argument to the `$httpHandler`
* callable. By default these are passed to {@see \GuzzleHttp\Client} as request options.
* See {@link https://docs.guzzlephp.org/en/stable/request-options.html}.
* }
*/
public function setTransportOptions(array $transportOptions)
{
$this->transportOptions = $transportOptions;
}
/**
* @deprecated use CallOptions::setTransportOptions
*/
public function setTransportSpecificOptions(array $transportSpecificOptions)
{
$this->setTransportOptions($transportSpecificOptions);
}
/**
* @param RetrySettings|array|null $retrySettings
*/
public function setRetrySettings($retrySettings)
{
$this->retrySettings = $retrySettings;
}
}

View File

@@ -0,0 +1,284 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options;
use ArrayAccess;
use Closure;
use InvalidArgumentException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\CredentialsWrapper;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\TransportInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\FetchAuthTokenInterface;
/**
* The ClientOptions class adds typing to the associative array of options
* passed into each API client constructor. To use this class directly, pass
* the result of {@see ClientOptions::toArray} to the client constructor:
*
* ```
* use Google\ApiCore\ClientOptions;
* use Google\Cloud\SecretManager\Client\SecretManagerClient;
*
* $options = new ClientOptions([
* 'credentials' => '/path/to/my/credentials.json'
* ]);
* $secretManager = new SecretManagerClient($options->toArray());
* ```
*
* Note: It's possible to pass an associative array to the API clients as well,
* as ClientOptions will still be used internally for validation.
*/
class ClientOptions implements ArrayAccess
{
use OptionsTrait;
private ?string $apiEndpoint;
private bool $disableRetries;
private array $clientConfig;
/** @var string|array|FetchAuthTokenInterface|CredentialsWrapper|null */
private $credentials;
private array $credentialsConfig;
/** @var string|TransportInterface|null $transport */
private $transport;
private TransportOptions $transportConfig;
private ?string $versionFile;
private ?string $descriptorsConfigPath;
private ?string $serviceName;
private ?string $libName;
private ?string $libVersion;
private ?string $gapicVersion;
private ?Closure $clientCertSource;
private ?string $universeDomain;
/**
* @param array $options {
* @type string $apiEndpoint
* The address of the API remote host, for example "example.googleapis.com. May also
* include the port, for example "example.googleapis.com:443"
* @type bool $disableRetries
* Determines whether or not retries defined by the client configuration should be
* disabled. Defaults to `false`.
* @type string|array $clientConfig
* Client method configuration, including retry settings. This option can be either a
* path to a JSON file, or a PHP array containing the decoded JSON data.
* By default this settings points to the default client config file, which is provided
* in the resources folder.
* @type string|array|FetchAuthTokenInterface|CredentialsWrapper $credentials
* The credentials to be used by the client to authorize API calls. This option
* accepts either a path to a credentials file, or a decoded credentials file as a
* PHP array.
* *Advanced usage*: In addition, this option can also accept a pre-constructed
* \Google\Auth\FetchAuthTokenInterface object or \Google\ApiCore\CredentialsWrapper
* object. Note that when one of these objects are provided, any settings in
* $authConfig will be ignored.
* @type array $credentialsConfig
* Options used to configure credentials, including auth token caching, for the client.
* For a full list of supporting configuration options, see
* \Google\ApiCore\CredentialsWrapper::build.
* @type string|TransportInterface|null $transport
* The transport used for executing network requests. May be either the string `rest`,
* `grpc`, or 'grpc-fallback'. Defaults to `grpc` if gRPC support is detected on the system.
* *Advanced usage*: Additionally, it is possible to pass in an already instantiated
* TransportInterface object. Note that when this objects is provided, any settings in
* $transportConfig, and any `$apiEndpoint` setting, will be ignored.
* @type array $transportConfig
* Configuration options that will be used to construct the transport. Options for
* each supported transport type should be passed in a key for that transport. For
* example:
* $transportConfig = [
* 'grpc' => [...],
* 'rest' => [...],
* 'grpc-fallback' => [...],
* ];
* See the GrpcTransport::build and RestTransport::build
* methods for the supported options.
* @type string $versionFile
* The path to a file which contains the current version of the client.
* @type string $descriptorsConfigPath
* The path to a descriptor configuration file.
* @type string $serviceName
* The name of the service.
* @type string $libName
* The name of the client application.
* @type string $libVersion
* The version of the client application.
* @type string $gapicVersion
* The code generator version of the GAPIC library.
* @type callable $clientCertSource
* A callable which returns the client cert as a string.
* @type string $universeDomain
* The default service domain for a given Cloud universe.
* }
*/
public function __construct(array $options)
{
$this->fromArray($options);
}
/**
* Sets the array of options as class properites.
*
* @param array $arr See the constructor for the list of supported options.
*/
private function fromArray(array $arr) : void
{
$this->setApiEndpoint($arr['apiEndpoint'] ?? null);
$this->setDisableRetries($arr['disableRetries'] ?? \false);
$this->setClientConfig($arr['clientConfig'] ?? []);
$this->setCredentials($arr['credentials'] ?? null);
$this->setCredentialsConfig($arr['credentialsConfig'] ?? []);
$this->setTransport($arr['transport'] ?? null);
$this->setTransportConfig(new TransportOptions($arr['transportConfig'] ?? []));
$this->setVersionFile($arr['versionFile'] ?? null);
$this->setDescriptorsConfigPath($arr['descriptorsConfigPath'] ?? null);
$this->setServiceName($arr['serviceName'] ?? null);
$this->setLibName($arr['libName'] ?? null);
$this->setLibVersion($arr['libVersion'] ?? null);
$this->setGapicVersion($arr['gapicVersion'] ?? null);
$this->setClientCertSource($arr['clientCertSource'] ?? null);
$this->setUniverseDomain($arr['universeDomain'] ?? null);
}
/**
* @param ?string $apiEndpoint
*/
public function setApiEndpoint(?string $apiEndpoint) : void
{
$this->apiEndpoint = $apiEndpoint;
}
/**
* @param bool $disableRetries
*/
public function setDisableRetries(bool $disableRetries) : void
{
$this->disableRetries = $disableRetries;
}
/**
* @param string|array $clientConfig
* @throws InvalidArgumentException
*/
public function setClientConfig($clientConfig) : void
{
if (\is_string($clientConfig)) {
$this->clientConfig = \json_decode(\file_get_contents($clientConfig), \true);
} elseif (\is_array($clientConfig)) {
$this->clientConfig = $clientConfig;
} else {
throw new InvalidArgumentException('Invalid client config');
}
}
/**
* @param string|array|FetchAuthTokenInterface|CredentialsWrapper|null $credentials
*/
public function setCredentials($credentials) : void
{
$this->credentials = $credentials;
}
/**
* @param array $credentialsConfig
*/
public function setCredentialsConfig(array $credentialsConfig) : void
{
$this->credentialsConfig = $credentialsConfig;
}
/**
* @param string|TransportInterface|null $transport
*/
public function setTransport($transport) : void
{
$this->transport = $transport;
}
/**
* @param TransportOptions $transportConfig
*/
public function setTransportConfig(TransportOptions $transportConfig) : void
{
$this->transportConfig = $transportConfig;
}
/**
* @param ?string $versionFile
*/
public function setVersionFile(?string $versionFile) : void
{
$this->versionFile = $versionFile;
}
/**
* @param ?string $descriptorsConfigPath
*/
private function setDescriptorsConfigPath(?string $descriptorsConfigPath)
{
if (!\is_null($descriptorsConfigPath)) {
self::validateFileExists($descriptorsConfigPath);
}
$this->descriptorsConfigPath = $descriptorsConfigPath;
}
/**
* @param ?string $serviceName
*/
public function setServiceName(?string $serviceName) : void
{
$this->serviceName = $serviceName;
}
/**
* @param ?string $libName
*/
public function setLibName(?string $libName) : void
{
$this->libName = $libName;
}
/**
* @param ?string $libVersion
*/
public function setLibVersion(?string $libVersion) : void
{
$this->libVersion = $libVersion;
}
/**
* @param ?string $gapicVersion
*/
public function setGapicVersion(?string $gapicVersion) : void
{
$this->gapicVersion = $gapicVersion;
}
/**
* @param ?callable $clientCertSource
*/
public function setClientCertSource(?callable $clientCertSource)
{
if (!\is_null($clientCertSource)) {
$clientCertSource = Closure::fromCallable($clientCertSource);
}
$this->clientCertSource = $clientCertSource;
}
/**
* @param string $universeDomain
*/
public function setUniverseDomain(?string $universeDomain)
{
$this->universeDomain = $universeDomain;
}
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
use BadMethodCallException;
/**
* Trait implemented by any class representing an associative array of PHP options.
* This provides validation and typehinting to loosely typed associative arrays.
*/
trait OptionsTrait
{
/**
* @param string $filePath
* @throws ValidationException
*/
private static function validateFileExists(string $filePath)
{
if (!\file_exists($filePath)) {
throw new ValidationException("Could not find specified file: {$filePath}");
}
}
public function offsetExists($offset) : bool
{
return isset($this->{$offset});
}
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->{$offset};
}
/**
* @throws BadMethodCallException
*/
public function offsetSet($offset, $value) : void
{
throw new BadMethodCallException('Cannot set options through array access. Use the setters instead');
}
/**
* @throws BadMethodCallException
*/
public function offsetUnset($offset) : void
{
throw new BadMethodCallException('Cannot unset options through array access. Use the setters instead');
}
public function toArray() : array
{
$arr = [];
foreach (\get_object_vars($this) as $key => $value) {
$arr[$key] = $value;
}
return $arr;
}
}

View File

@@ -0,0 +1,81 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions\GrpcTransportOptions;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions\GrpcFallbackTransportOptions;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions\RestTransportOptions;
use ArrayAccess;
class TransportOptions implements ArrayAccess
{
use OptionsTrait;
private GrpcTransportOptions $grpc;
private GrpcFallbackTransportOptions $grpcFallback;
private RestTransportOptions $rest;
/**
* @param array $options {
* Config options used to construct the transport.
*
* @type array $grpc
* @type array $grpcFallback
* @type array $rest
* }
*/
public function __construct(array $options)
{
$this->fromArray($options);
}
/**
* Sets the array of options as class properites.
*
* @param array $arr See the constructor for the list of supported options.
*/
private function fromArray(array $arr) : void
{
$this->setGrpc(new GrpcTransportOptions($arr['grpc'] ?? []));
$this->setGrpcFallback(new GrpcFallbackTransportOptions($arr['grpc-fallback'] ?? []));
$this->setRest(new RestTransportOptions($arr['rest'] ?? []));
}
public function setGrpc(GrpcTransportOptions $grpc) : void
{
$this->grpc = $grpc;
}
public function setGrpcFallback(GrpcFallbackTransportOptions $grpcFallback) : void
{
$this->grpcFallback = $grpcFallback;
}
public function setRest(RestTransportOptions $rest) : void
{
$this->rest = $rest;
}
}

View File

@@ -0,0 +1,88 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions;
use ArrayAccess;
use Closure;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\OptionsTrait;
/**
* The GrpcFallbackTransportOptions class provides typing to the associative array of options used
* to configure {@see \Google\ApiCore\Transport\GrpcFallbackTransport}.
*/
class GrpcFallbackTransportOptions implements ArrayAccess
{
use OptionsTrait;
private ?Closure $clientCertSource;
private ?Closure $httpHandler;
/**
* @param array $options {
* Config options used to construct the gRPC Fallback transport.
*
* @type callable $clientCertSource
* A callable which returns the client cert as a string.
* @type callable $httpHandler
* A handler used to deliver PSR-7 requests.
* }
*/
public function __construct(array $options)
{
$this->fromArray($options);
}
/**
* Sets the array of options as class properites.
*
* @param array $arr See the constructor for the list of supported options.
*/
private function fromArray(array $arr) : void
{
$this->setClientCertSource($arr['clientCertSource'] ?? null);
$this->setHttpHandler($arr['httpHandler'] ?? null);
}
public function setHttpHandler(?callable $httpHandler)
{
if (!\is_null($httpHandler)) {
$httpHandler = Closure::fromCallable($httpHandler);
}
$this->httpHandler = $httpHandler;
}
/**
* @param ?callable $clientCertSource
*/
public function setClientCertSource(?callable $clientCertSource)
{
if (!\is_null($clientCertSource)) {
$clientCertSource = Closure::fromCallable($clientCertSource);
}
$this->clientCertSource = $clientCertSource;
}
}

View File

@@ -0,0 +1,120 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions;
use ArrayAccess;
use Closure;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\OptionsTrait;
use Grpc\Channel;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\Interceptor;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc\UnaryInterceptorInterface;
/**
* The GrpcTransportOptions class provides typing to the associative array of options used to
* configure {@see \Google\ApiCore\Transport\GrpcTransport}.
*/
class GrpcTransportOptions implements ArrayAccess
{
use OptionsTrait;
private array $stubOpts;
private ?Channel $channel;
/**
* @var Interceptor[]|UnaryInterceptorInterface[]
*/
private array $interceptors;
private ?Closure $clientCertSource;
/**
* @param array $options {
* Config options used to construct the gRPC transport.
*
* @type array $stubOpts Options used to construct the gRPC stub (see
* {@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}).
* @type Channel $channel Grpc channel to be used.
* @type Interceptor[]|UnaryInterceptorInterface[] $interceptors *EXPERIMENTAL*
* Interceptors used to intercept RPC invocations before a call starts.
* Please note that implementations of
* {@see \Google\ApiCore\Transport\Grpc\UnaryInterceptorInterface} are
* considered deprecated and support will be removed in a future
* release. To prepare for this, please take the time to convert
* `UnaryInterceptorInterface` implementations over to a class which
* extends {@see Grpc\Interceptor}.
* @type callable $clientCertSource A callable which returns the client cert as a string.
* }
*/
public function __construct(array $options)
{
$this->fromArray($options);
}
/**
* Sets the array of options as class properites.
*
* @param array $arr See the constructor for the list of supported options.
*/
private function fromArray(array $arr) : void
{
$this->setStubOpts($arr['stubOpts'] ?? []);
$this->setChannel($arr['channel'] ?? null);
$this->setInterceptors($arr['interceptors'] ?? []);
$this->setClientCertSource($arr['clientCertSource'] ?? null);
}
/**
* @param array $stubOpts
*/
public function setStubOpts(array $stubOpts)
{
$this->stubOpts = $stubOpts;
}
/**
* @param ?Channel $channel
*/
public function setChannel(?Channel $channel)
{
$this->channel = $channel;
}
/**
* @param Interceptor[]|UnaryInterceptorInterface[] $interceptors
*/
public function setInterceptors(array $interceptors)
{
$this->interceptors = $interceptors;
}
/**
* @param ?callable $clientCertSource
*/
public function setClientCertSource(?callable $clientCertSource)
{
if (!\is_null($clientCertSource)) {
$clientCertSource = Closure::fromCallable($clientCertSource);
}
$this->clientCertSource = $clientCertSource;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/*
* Copyright 2023 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\TransportOptions;
use ArrayAccess;
use Closure;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Options\OptionsTrait;
/**
* The RestTransportOptions class provides typing to the associative array of options used to
* configure {@see \Google\ApiCore\Transport\RestTransport}.
*/
class RestTransportOptions implements ArrayAccess
{
use OptionsTrait;
private ?Closure $httpHandler;
private ?Closure $clientCertSource;
private ?string $restClientConfigPath;
/**
* @param array $options {
* Config options used to construct the REST transport.
*
* @type callable $httpHandler
* A handler used to deliver PSR-7 requests.
* @type callable $clientCertSource
* A callable which returns the client cert as a string.
* @type string $restClientConfigPath
* The path to the REST client config file.
* }
*/
public function __construct(array $options)
{
$this->fromArray($options);
}
/**
* Sets the array of options as class properites.
*
* @param array $arr See the constructor for the list of supported options.
*/
private function fromArray(array $arr) : void
{
$this->setHttpHandler($arr['httpHandler'] ?? null);
$this->setClientCertSource($arr['clientCertSource'] ?? null);
$this->setRestClientConfigPath($arr['restClientConfigPath'] ?? null);
}
/**
* @param ?callable $httpHandler
*/
public function setHttpHandler(?callable $httpHandler)
{
if (!\is_null($httpHandler)) {
$httpHandler = Closure::fromCallable($httpHandler);
}
$this->httpHandler = $httpHandler;
}
/**
* @param ?callable $clientCertSource
*/
public function setClientCertSource(?callable $clientCertSource)
{
if (!\is_null($clientCertSource)) {
$clientCertSource = Closure::fromCallable($clientCertSource);
}
$this->clientCertSource = $clientCertSource;
}
/**
* @param ?string $restClientConfigPath
*/
public function setRestClientConfigPath(?string $restClientConfigPath)
{
$this->restClientConfigPath = $restClientConfigPath;
}
}

220
vendor/Gcp/google/gax/src/Page.php vendored Normal file
View File

@@ -0,0 +1,220 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use Generator;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\MapField;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use IteratorAggregate;
/**
* A Page object wraps an API list method response and provides methods
* to retrieve additional pages using the page token.
*/
class Page implements IteratorAggregate
{
const FINAL_PAGE_TOKEN = "";
private $call;
private $callable;
private $options;
private $pageStreamingDescriptor;
private $pageToken;
// @phpstan-ignore-line
private $response;
/**
* Page constructor.
*
* @param Call $call
* @param array $options
* @param callable $callable
* @param PageStreamingDescriptor $pageStreamingDescriptor
* @param Message $response
*/
public function __construct(Call $call, array $options, callable $callable, PageStreamingDescriptor $pageStreamingDescriptor, Message $response)
{
$this->call = $call;
$this->options = $options;
$this->callable = $callable;
$this->pageStreamingDescriptor = $pageStreamingDescriptor;
$this->response = $response;
$requestPageTokenGetMethod = $this->pageStreamingDescriptor->getRequestPageTokenGetMethod();
$this->pageToken = $this->call->getMessage()->{$requestPageTokenGetMethod}();
}
/**
* Returns true if there are more pages that can be retrieved from the
* API.
*
* @return bool
*/
public function hasNextPage()
{
return \strcmp($this->getNextPageToken(), Page::FINAL_PAGE_TOKEN) != 0;
}
/**
* Returns the next page token from the response.
*
* @return string
*/
public function getNextPageToken()
{
$responsePageTokenGetMethod = $this->pageStreamingDescriptor->getResponsePageTokenGetMethod();
return $this->getResponseObject()->{$responsePageTokenGetMethod}();
}
/**
* Retrieves the next Page object using the next page token.
*
* @param int|null $pageSize
* @throws ValidationException if there are no pages remaining, or if pageSize is supplied but
* is not supported by the API
* @throws ApiException if the call to fetch the next page fails.
* @return Page
*/
public function getNextPage(int $pageSize = null)
{
if (!$this->hasNextPage()) {
throw new ValidationException('Could not complete getNextPage operation: ' . 'there are no more pages to retrieve.');
}
$oldRequest = $this->getRequestObject();
$requestClass = \get_class($oldRequest);
$newRequest = new $requestClass();
$newRequest->mergeFrom($oldRequest);
$requestPageTokenSetMethod = $this->pageStreamingDescriptor->getRequestPageTokenSetMethod();
$newRequest->{$requestPageTokenSetMethod}($this->getNextPageToken());
if (isset($pageSize)) {
if (!$this->pageStreamingDescriptor->requestHasPageSizeField()) {
throw new ValidationException('pageSize argument was defined, but the method does not ' . 'support a page size parameter in the optional array argument');
}
$requestPageSizeSetMethod = $this->pageStreamingDescriptor->getRequestPageSizeSetMethod();
$newRequest->{$requestPageSizeSetMethod}($pageSize);
}
$this->call = $this->call->withMessage($newRequest);
$callable = $this->callable;
$response = $callable($this->call, $this->options)->wait();
return new Page($this->call, $this->options, $this->callable, $this->pageStreamingDescriptor, $response);
}
/**
* Return the number of elements in the response.
*
* @return int
*/
public function getPageElementCount()
{
$resourcesGetMethod = $this->pageStreamingDescriptor->getResourcesGetMethod();
return \count($this->getResponseObject()->{$resourcesGetMethod}());
}
/**
* Return an iterator over the elements in the response.
*
* @return Generator
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
$resourcesGetMethod = $this->pageStreamingDescriptor->getResourcesGetMethod();
$items = $this->getResponseObject()->{$resourcesGetMethod}();
foreach ($items as $key => $element) {
if ($items instanceof MapField) {
(yield $key => $element);
} else {
(yield $element);
}
}
}
/**
* Return an iterator over Page objects, beginning with this object.
* Additional Page objects are retrieved lazily via API calls until
* all elements have been retrieved.
*
* @return Generator|array<Page>
* @throws ValidationException
* @throws ApiException
*/
public function iteratePages()
{
$currentPage = $this;
(yield $this);
while ($currentPage->hasNextPage()) {
$currentPage = $currentPage->getNextPage();
(yield $currentPage);
}
}
/**
* Gets the request object used to generate the Page.
*
* @return mixed|Message
*/
public function getRequestObject()
{
return $this->call->getMessage();
}
/**
* Gets the API response object.
*
* @return mixed|Message
*/
public function getResponseObject()
{
return $this->response;
}
/**
* Returns a collection of elements with a fixed size set by
* the collectionSize parameter. The collection will only contain
* fewer than collectionSize elements if there are no more
* pages to be retrieved from the server.
*
* NOTE: it is an error to call this method if an optional parameter
* to set the page size is not supported or has not been set in the
* API call that was used to create this page. It is also an error
* if the collectionSize parameter is less than the page size that
* has been set.
*
* @param int $collectionSize
* @throws ValidationException if a FixedSizeCollection of the specified size cannot be constructed
* @return FixedSizeCollection
*/
public function expandToFixedSizeCollection($collectionSize)
{
if (!$this->pageStreamingDescriptor->requestHasPageSizeField()) {
throw new ValidationException("FixedSizeCollection is not supported for this method, because " . "the method does not support an optional argument to set the " . "page size.");
}
$request = $this->getRequestObject();
$pageSizeGetMethod = $this->pageStreamingDescriptor->getRequestPageSizeGetMethod();
$pageSize = $request->{$pageSizeGetMethod}();
if (\is_null($pageSize)) {
throw new ValidationException("Error while expanding Page to FixedSizeCollection: No page size " . "parameter found. The page size parameter must be set in the API " . "optional arguments array, and must be less than the collectionSize " . "parameter, in order to create a FixedSizeCollection object.");
}
if ($pageSize > $collectionSize) {
throw new ValidationException("Error while expanding Page to FixedSizeCollection: collectionSize " . "parameter is less than the page size optional argument specified in " . "the API call. collectionSize: {$collectionSize}, page size: {$pageSize}");
}
return new FixedSizeCollection($this, $collectionSize);
}
}

View File

@@ -0,0 +1,151 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use InvalidArgumentException;
/**
* Holds the description information used for page streaming.
*/
class PageStreamingDescriptor
{
private $descriptor;
/**
* @param array $descriptor {
* Required.
* @type string $requestPageTokenGetMethod the get method for the page token in the request object.
* @type string $requestPageTokenSetMethod the set method for the page token in the request object.
* @type string $responsePageTokenGetMethod the get method for the page token in the response object.
* @type string resourcesGetMethod the get method for the resources in the response object.
*
* Optional.
* @type string $requestPageSizeGetMethod the get method for the page size in the request object.
* }
*/
public function __construct(array $descriptor)
{
self::validate($descriptor);
$this->descriptor = $descriptor;
}
/**
* @param array $fields {
* Required.
*
* @type string $requestPageTokenField the page token field in the request object.
* @type string $responsePageTokenField the page token field in the response object.
* @type string $resourceField the resource field in the response object.
*
* Optional.
* @type string $requestPageSizeField the page size field in the request object.
* }
* @return PageStreamingDescriptor
*/
public static function createFromFields(array $fields)
{
$requestPageToken = $fields['requestPageTokenField'];
$responsePageToken = $fields['responsePageTokenField'];
$resources = $fields['resourceField'];
$descriptor = ['requestPageTokenGetMethod' => PageStreamingDescriptor::getMethod($requestPageToken), 'requestPageTokenSetMethod' => PageStreamingDescriptor::setMethod($requestPageToken), 'responsePageTokenGetMethod' => PageStreamingDescriptor::getMethod($responsePageToken), 'resourcesGetMethod' => PageStreamingDescriptor::getMethod($resources)];
if (isset($fields['requestPageSizeField'])) {
$requestPageSize = $fields['requestPageSizeField'];
$descriptor['requestPageSizeGetMethod'] = PageStreamingDescriptor::getMethod($requestPageSize);
$descriptor['requestPageSizeSetMethod'] = PageStreamingDescriptor::setMethod($requestPageSize);
}
return new PageStreamingDescriptor($descriptor);
}
private static function getMethod(string $field)
{
return 'get' . \ucfirst($field);
}
private static function setMethod(string $field)
{
return 'set' . \ucfirst($field);
}
/**
* @return string The page token get method on the request object
*/
public function getRequestPageTokenGetMethod()
{
return $this->descriptor['requestPageTokenGetMethod'];
}
/**
* @return string The page size get method on the request object
*/
public function getRequestPageSizeGetMethod()
{
return $this->descriptor['requestPageSizeGetMethod'];
}
/**
* @return bool True if the request object has a page size field
*/
public function requestHasPageSizeField()
{
return \array_key_exists('requestPageSizeGetMethod', $this->descriptor);
}
/**
* @return string The page token get method on the response object
*/
public function getResponsePageTokenGetMethod()
{
return $this->descriptor['responsePageTokenGetMethod'];
}
/**
* @return string The resources get method on the response object
*/
public function getResourcesGetMethod()
{
return $this->descriptor['resourcesGetMethod'];
}
/**
* @return string The page token set method on the request object
*/
public function getRequestPageTokenSetMethod()
{
return $this->descriptor['requestPageTokenSetMethod'];
}
/**
* @return string The page size set method on the request object
*/
public function getRequestPageSizeSetMethod()
{
return $this->descriptor['requestPageSizeSetMethod'];
}
private static function validate(array $descriptor)
{
$requiredFields = ['requestPageTokenGetMethod', 'requestPageTokenSetMethod', 'responsePageTokenGetMethod', 'resourcesGetMethod'];
foreach ($requiredFields as $field) {
if (empty($descriptor[$field])) {
throw new InvalidArgumentException("{$field} is required for PageStreamingDescriptor");
}
}
}
}

View File

@@ -0,0 +1,189 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use Generator;
use IteratorAggregate;
/**
* Response object for paged results from a list API method
*
* The PagedListResponse object is returned by API methods that implement
* pagination, and makes it easier to access multiple pages of results
* without having to manually manipulate page tokens. Pages are retrieved
* lazily, with additional API calls being made as additional results
* are required.
*
* The list elements can be accessed in the following ways:
* - As a single iterable used in a foreach loop or via the getIterator method
* - As pages of elements, using the getPage and iteratePages methods
* - As fixed size collections of elements, using the
* getFixedSizeCollection and iterateFixedSizeCollections methods
*
* Example of using PagedListResponse as an iterator:
* ```
* $pagedListResponse = $client->getList(...);
* foreach ($pagedListResponse as $element) {
* // doSomethingWith($element);
* }
* ```
*
* Example of iterating over each page of elements:
* ```
* $pagedListResponse = $client->getList(...);
* foreach ($pagedListResponse->iteratePages() as $page) {
* foreach ($page as $element) {
* // doSomethingWith($element);
* }
* }
* ```
*
* Example of accessing the current page, and manually iterating
* over pages:
* ```
* $pagedListResponse = $client->getList(...);
* $page = $pagedListResponse->getPage();
* // doSomethingWith($page);
* while ($page->hasNextPage()) {
* $page = $page->getNextPage();
* // doSomethingWith($page);
* }
* ```
*/
class PagedListResponse implements IteratorAggregate
{
private $firstPage;
/**
* PagedListResponse constructor.
*
* @param Page $firstPage A page containing response details.
*/
public function __construct(Page $firstPage)
{
$this->firstPage = $firstPage;
}
/**
* Returns an iterator over the full list of elements. If the
* API response contains a (non-empty) next page token, then
* the PagedListResponse object will make calls to the underlying
* API to retrieve additional elements as required.
*
* NOTE: The result of this method is the same as getIterator().
* Prefer using getIterator(), or iterate directly on the
* PagedListResponse object.
*
* @return Generator
* @throws ValidationException
*/
public function iterateAllElements()
{
return $this->getIterator();
}
/**
* Returns an iterator over the full list of elements. If the
* API response contains a (non-empty) next page token, then
* the PagedListResponse object will make calls to the underlying
* API to retrieve additional elements as required.
*
* @return Generator
* @throws ValidationException
*/
#[\ReturnTypeWillChange]
public function getIterator()
{
foreach ($this->iteratePages() as $page) {
foreach ($page as $key => $element) {
(yield $key => $element);
}
}
}
/**
* Return the current page of results.
*
* @return Page
*/
public function getPage()
{
return $this->firstPage;
}
/**
* Returns an iterator over pages of results. The pages are
* retrieved lazily from the underlying API.
*
* @return Page[]
* @throws ValidationException
*/
public function iteratePages()
{
return $this->getPage()->iteratePages();
}
/**
* Returns a collection of elements with a fixed size set by
* the collectionSize parameter. The collection will only contain
* fewer than collectionSize elements if there are no more
* pages to be retrieved from the server.
*
* NOTE: it is an error to call this method if an optional parameter
* to set the page size is not supported or has not been set in the
* original API call. It is also an error if the collectionSize parameter
* is less than the page size that has been set.
*
* @param int $collectionSize
* @throws ValidationException if a FixedSizeCollection of the specified size cannot be constructed
* @return FixedSizeCollection
*/
public function expandToFixedSizeCollection(int $collectionSize)
{
return $this->getPage()->expandToFixedSizeCollection($collectionSize);
}
/**
* Returns an iterator over fixed size collections of results.
* The collections are retrieved lazily from the underlying API.
*
* Each collection will have collectionSize elements, with the
* exception of the final collection which may contain fewer
* elements.
*
* NOTE: it is an error to call this method if an optional parameter
* to set the page size is not supported or has not been set in the
* original API call. It is also an error if the collectionSize parameter
* is less than the page size that has been set.
*
* @param int $collectionSize
* @throws ValidationException if a FixedSizeCollection of the specified size cannot be constructed
* @return Generator|FixedSizeCollection[]
*/
public function iterateFixedSizeCollections(int $collectionSize)
{
return $this->expandToFixedSizeCollection($collectionSize)->iterateCollections();
}
}

View File

@@ -0,0 +1,106 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate\AbsoluteResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate\RelativeResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate\ResourceTemplateInterface;
/**
* Represents a path template.
*
* Templates use the syntax of the API platform; see the protobuf of HttpRule for
* details. A template consists of a sequence of literals, wildcards, and variable bindings,
* where each binding can have a sub-path. A string representation can be parsed into an
* instance of PathTemplate, which can then be used to perform matching and instantiation.
*/
class PathTemplate implements ResourceTemplateInterface
{
private $resourceTemplate;
/**
* PathTemplate constructor.
*
* @param string $path A path template string
* @throws ValidationException When $path cannot be parsed into a valid PathTemplate
*/
public function __construct(string $path = null)
{
if (empty($path)) {
throw new ValidationException('Cannot construct PathTemplate from empty string');
}
if ($path[0] === '/') {
$this->resourceTemplate = new AbsoluteResourceTemplate($path);
} else {
$this->resourceTemplate = new RelativeResourceTemplate($path);
}
}
/**
* @return string A string representation of the path template
*/
public function __toString()
{
return $this->resourceTemplate->__toString();
}
/**
* Renders a path template using the provided bindings.
*
* @param array $bindings An array matching var names to binding strings.
* @throws ValidationException if a key isn't provided or if a sub-template
* can't be parsed.
* @return string A rendered representation of this path template.
*/
public function render(array $bindings)
{
return $this->resourceTemplate->render($bindings);
}
/**
* Check if $path matches a resource string.
*
* @param string $path A resource string.
* @return bool
*/
public function matches(string $path)
{
return $this->resourceTemplate->matches($path);
}
/**
* Matches a fully qualified path template string.
*
* @param string $path A fully qualified path template string.
* @throws ValidationException if path can't be matched to the template.
* @return array Array matching var names to binding values.
*/
public function match(string $path)
{
return $this->resourceTemplate->match($path);
}
}

View File

@@ -0,0 +1,90 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* @internal
*/
trait PollingTrait
{
/**
* @param callable $pollCallable The call to poll. Must return a boolean indicating whether the
* operation has completed, and the polling loop can be terminated.
* @param array $options {
* Options for configuring the polling behaviour.
*
* @type int $initialPollDelayMillis The initial polling interval to use, in milliseconds.
* @type int $pollDelayMultiplier Multiplier applied to the polling interval on each retry.
* @type int $maxPollDelayMillis The maximum polling interval to use, in milliseconds.
* @type int $totalPollTimeoutMillis The maximum amount of time to continue polling, in milliseconds.
* }
* @return bool
*/
private function poll(callable $pollCallable, array $options)
{
$currentPollDelayMillis = $options['initialPollDelayMillis'];
$pollDelayMultiplier = $options['pollDelayMultiplier'];
$maxPollDelayMillis = $options['maxPollDelayMillis'];
$totalPollTimeoutMillis = $options['totalPollTimeoutMillis'];
$hasTotalPollTimeout = $totalPollTimeoutMillis > 0.0;
$endTime = $this->getCurrentTimeMillis() + $totalPollTimeoutMillis;
while (\true) {
if ($hasTotalPollTimeout && $this->getCurrentTimeMillis() > $endTime) {
return \false;
}
$this->sleepMillis($currentPollDelayMillis);
if ($pollCallable()) {
return \true;
}
$currentPollDelayMillis = (int) \min([$currentPollDelayMillis * $pollDelayMultiplier, $maxPollDelayMillis]);
}
}
/**
* Protected to allow overriding for tests
*
* @return float Current time in milliseconds
*/
protected function getCurrentTimeMillis()
{
return \microtime(\true) * 1000.0;
}
/**
* Protected to allow overriding for tests
*
* @param int $millis
*/
protected function sleepMillis(int $millis)
{
\usleep($millis * 1000);
}
}

View File

@@ -0,0 +1,234 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate\AbsoluteResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Request;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Utils;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\RequestInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\UriInterface;
/**
* Builds a PSR-7 request from a set of request information.
*
* @internal
*/
class RequestBuilder
{
use ArrayTrait;
use UriTrait;
use ValidationTrait;
private $baseUri;
private $restConfig;
/**
* @param string $baseUri
* @param string $restConfigPath
* @throws ValidationException
*/
public function __construct(string $baseUri, string $restConfigPath)
{
self::validateFileExists($restConfigPath);
$this->baseUri = $baseUri;
$this->restConfig = (require $restConfigPath);
}
/**
* @param string $path
* @return bool
*/
public function pathExists(string $path)
{
list($interface, $method) = \explode('/', $path);
return isset($this->restConfig['interfaces'][$interface][$method]);
}
/**
* @param string $path
* @param Message $message
* @param array $headers
* @return RequestInterface
* @throws ValidationException
*/
public function build(string $path, Message $message, array $headers = [])
{
list($interface, $method) = \explode('/', $path);
if (!isset($this->restConfig['interfaces'][$interface][$method])) {
throw new ValidationException("Failed to build request, as the provided path ({$path}) was not found in the configuration.");
}
$numericEnums = isset($this->restConfig['numericEnums']) && $this->restConfig['numericEnums'];
$methodConfig = $this->restConfig['interfaces'][$interface][$method] + ['placeholders' => [], 'body' => null, 'additionalBindings' => null];
$bindings = $this->buildBindings($methodConfig['placeholders'], $message);
$uriTemplateConfigs = $this->getConfigsForUriTemplates($methodConfig);
foreach ($uriTemplateConfigs as $config) {
$pathTemplate = $this->tryRenderPathTemplate($config['uriTemplate'], $bindings);
if ($pathTemplate) {
// We found a valid uriTemplate - now build and return the Request
list($body, $queryParams) = $this->constructBodyAndQueryParameters($message, $config);
// Request enum fields will be encoded as numbers rather than strings (in the response).
if ($numericEnums) {
$queryParams['$alt'] = "json;enum-encoding=int";
}
$uri = $this->buildUri($pathTemplate, $queryParams);
return new Request($config['method'], $uri, ['Content-Type' => 'application/json'] + $headers, $body);
}
}
// No valid uriTemplate found - construct an exception
$uriTemplates = [];
foreach ($uriTemplateConfigs as $config) {
$uriTemplates[] = $config['uriTemplate'];
}
throw new ValidationException("Could not map bindings for {$path} to any Uri template.\n" . "Bindings: " . \print_r($bindings, \true) . "UriTemplates: " . \print_r($uriTemplates, \true));
}
/**
* Create a list of all possible configs using the additionalBindings
*
* @param array $config
* @return array[] An array of configs
*/
private function getConfigsForUriTemplates(array $config)
{
$configs = [$config];
if ($config['additionalBindings']) {
foreach ($config['additionalBindings'] as $additionalBinding) {
$configs[] = $additionalBinding + $config;
}
}
return $configs;
}
/**
* @param Message $message
* @param array $config
* @return array Tuple [$body, $queryParams]
*/
private function constructBodyAndQueryParameters(Message $message, array $config)
{
$messageDataJson = $message->serializeToJsonString();
if ($config['body'] === '*') {
return [$messageDataJson, []];
}
$body = null;
$queryParams = [];
$messageData = \json_decode($messageDataJson, \true);
foreach ($messageData as $name => $value) {
if (\array_key_exists($name, $config['placeholders'])) {
continue;
}
if (Serializer::toSnakeCase($name) === $config['body']) {
if (($bodyMessage = $message->{"get{$name}"}()) instanceof Message) {
$body = $bodyMessage->serializeToJsonString();
} else {
$body = \json_encode($value);
}
continue;
}
if (\is_array($value) && $this->isAssoc($value)) {
foreach ($value as $key => $value2) {
$queryParams[$name . '.' . $key] = $value2;
}
} else {
$queryParams[$name] = $value;
}
}
// Ensures required query params with default values are always sent
// over the wire.
if (isset($config['queryParams'])) {
foreach ($config['queryParams'] as $requiredQueryParam) {
$requiredQueryParam = Serializer::toCamelCase($requiredQueryParam);
if (!\array_key_exists($requiredQueryParam, $queryParams)) {
$getter = Serializer::getGetter($requiredQueryParam);
$queryParamValue = $message->{$getter}();
if ($queryParamValue instanceof Message) {
// Decode message for the query parameter.
$queryParamValue = \json_decode($queryParamValue->serializeToJsonString(), \true);
}
if (\is_array($queryParamValue)) {
// If the message has properties, add them as nested querystring values.
// NOTE: This only supports nesting at one level of depth.
foreach ($queryParamValue as $key => $value) {
$queryParams[$requiredQueryParam . '.' . $key] = $value;
}
} else {
$queryParams[$requiredQueryParam] = $queryParamValue;
}
}
}
}
return [$body, $queryParams];
}
/**
* @param array $placeholders
* @param Message $message
* @return array Bindings from path template fields to values from message
*/
private function buildBindings(array $placeholders, Message $message)
{
$bindings = [];
foreach ($placeholders as $placeholder => $metadata) {
$value = \array_reduce($metadata['getters'], function (Message $result = null, $getter) {
if ($result) {
return $result->{$getter}();
}
}, $message);
$bindings[$placeholder] = $value;
}
return $bindings;
}
/**
* Try to render the resource name. The rendered resource name will always contain a leading '/'
*
* @param string $uriTemplate
* @param array $bindings
* @return null|string
* @throws ValidationException
*/
private function tryRenderPathTemplate(string $uriTemplate, array $bindings)
{
$template = new AbsoluteResourceTemplate($uriTemplate);
try {
return $template->render($bindings);
} catch (ValidationException $e) {
return null;
}
}
/**
* @param string $path
* @param array $queryParams
* @return UriInterface
*/
private function buildUri(string $path, array $queryParams)
{
$uri = Utils::uriFor(\sprintf('https://%s%s', $this->baseUri, $path));
if ($queryParams) {
$uri = $this->buildUriWithQuery($uri, $queryParams);
}
return $uri;
}
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* Copyright 2017 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Encapsulates request params header metadata.
*/
class RequestParamsHeaderDescriptor
{
const HEADER_KEY = 'x-goog-request-params';
/**
* @var array
*/
private $header;
/**
* RequestParamsHeaderDescriptor constructor.
*
* @param array $requestParams An associative array which contains request params header data in
* a form ['field_name.subfield_name' => value].
*/
public function __construct(array $requestParams)
{
$headerKey = self::HEADER_KEY;
$headerValue = '';
foreach ($requestParams as $key => $value) {
if ('' !== $headerValue) {
$headerValue .= '&';
}
$headerValue .= $key . '=' . \urlencode(\strval($value));
}
$this->header = [$headerKey => [$headerValue]];
}
/**
* Returns an associative array that contains request params header metadata.
*
* @return array
*/
public function getHeader()
{
return $this->header;
}
}

View File

@@ -0,0 +1,100 @@
<?php
/*
* Copyright 2022 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
/**
* Provides functionality for loading a resource name template map from a descriptor config,
* retrieving a PathTemplate, and parsing values using registered templates.
*
* @internal
*/
trait ResourceHelperTrait
{
/** @var array|null */
private static $templateMap;
/**
* placeholder for this function like we have in GapicClientTrait
*/
private static function getClientDefaults()
{
return [];
}
private static function registerPathTemplates()
{
$templateConfigPath = self::getClientDefaults()['descriptorsConfigPath'];
// self::SERVICE_NAME is a constant set per-client.
self::loadPathTemplates($templateConfigPath, self::SERVICE_NAME);
}
private static function loadPathTemplates(string $configPath, string $serviceName)
{
// TODO: Add void return type hint.
if (!\is_null(self::$templateMap)) {
return;
}
$descriptors = (require $configPath);
$templates = $descriptors['interfaces'][$serviceName]['templateMap'] ?? [];
self::$templateMap = [];
foreach ($templates as $name => $template) {
self::$templateMap[$name] = new PathTemplate($template);
}
}
private static function getPathTemplate(string $key)
{
// TODO: Add nullable return type reference once PHP 7.1 is minimum.
if (\is_null(self::$templateMap)) {
self::registerPathTemplates();
}
return self::$templateMap[$key] ?? null;
}
private static function parseFormattedName(string $formattedName, string $template = null) : array
{
if (\is_null(self::$templateMap)) {
self::registerPathTemplates();
}
if ($template) {
if (!isset(self::$templateMap[$template])) {
throw new ValidationException("Template name {$template} does not exist");
}
return self::$templateMap[$template]->match($formattedName);
}
foreach (self::$templateMap as $templateName => $pathTemplate) {
try {
return $pathTemplate->match($formattedName);
} catch (ValidationException $ex) {
// Swallow the exception to continue trying other path templates
}
}
throw new ValidationException("Input did not match any known format. Input: {$formattedName}");
}
}

View File

@@ -0,0 +1,135 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
/**
* Represents an absolute resource template, meaning that it will always contain a leading slash,
* and may contain a trailing verb (":<verb>").
*
* Examples:
* /projects
* /projects/{project}
* /foo/{bar=**}/fizz/*:action
*
* Templates use the syntax of the API platform; see
* https://github.com/googleapis/api-common-protos/blob/master/google/api/http.proto
* for details. A template consists of a sequence of literals, wildcards, and variable bindings,
* where each binding can have a sub-path. A string representation can be parsed into an
* instance of AbsoluteResourceTemplate, which can then be used to perform matching and instantiation.
*
* @internal
*/
class AbsoluteResourceTemplate implements ResourceTemplateInterface
{
private RelativeResourceTemplate $resourceTemplate;
/** @var string|bool */
private $verb;
/**
* AbsoluteResourceTemplate constructor.
* @param string $path
* @throws ValidationException
*/
public function __construct(string $path)
{
if (empty($path)) {
throw new ValidationException('Cannot construct AbsoluteResourceTemplate from empty string');
}
if ($path[0] !== '/') {
throw new ValidationException("Could not construct AbsoluteResourceTemplate from '{$path}': must begin with '/'");
}
$verbSeparatorPos = $this->verbSeparatorPos($path);
$this->resourceTemplate = new RelativeResourceTemplate(\substr($path, 1, $verbSeparatorPos - 1));
$this->verb = \substr($path, $verbSeparatorPos + 1);
}
/**
* @inheritdoc
*/
public function __toString()
{
return \sprintf("/%s%s", $this->resourceTemplate, $this->renderVerb());
}
/**
* @inheritdoc
*/
public function render(array $bindings)
{
return \sprintf("/%s%s", $this->resourceTemplate->render($bindings), $this->renderVerb());
}
/**
* @inheritdoc
*/
public function matches(string $path)
{
try {
$this->match($path);
return \true;
} catch (ValidationException $ex) {
return \false;
}
}
/**
* @inheritdoc
*/
public function match(string $path)
{
if (empty($path)) {
throw $this->matchException($path, "path cannot be empty");
}
if ($path[0] !== '/') {
throw $this->matchException($path, "missing leading '/'");
}
$verbSeparatorPos = $this->verbSeparatorPos($path);
if (\substr($path, $verbSeparatorPos + 1) !== $this->verb) {
throw $this->matchException($path, "trailing verb did not match '{$this->verb}'");
}
return $this->resourceTemplate->match(\substr($path, 1, $verbSeparatorPos - 1));
}
private function matchException(string $path, string $reason)
{
return new ValidationException("Could not match path '{$path}' to template '{$this}': {$reason}");
}
private function renderVerb()
{
return $this->verb ? ':' . $this->verb : '';
}
private function verbSeparatorPos(string $path)
{
$finalSeparatorPos = \strrpos($path, '/');
$verbSeparatorPos = \strrpos($path, ':', $finalSeparatorPos);
if ($verbSeparatorPos === \false) {
$verbSeparatorPos = \strlen($path);
}
return $verbSeparatorPos;
}
}

View File

@@ -0,0 +1,207 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
/**
* Collection of methods for parsing Segments.
*
* @internal
*/
class Parser
{
/**
* Parses a path into an array of segments.
*
* @param string|null $path
* @return array
* @throws ValidationException
*/
public static function parseSegments(string $path = null)
{
if (empty($path)) {
throw new ValidationException("Cannot parse empty path");
}
$segments = [];
$index = 0;
$nextLiteral = '';
$segments[] = self::parseSegmentFromPath($path, $nextLiteral, $index);
while ($index < \strlen($path)) {
self::parseLiteralFromPath($nextLiteral, $path, $index);
$segments[] = self::parseSegmentFromPath($path, $nextLiteral, $index);
}
return $segments;
}
/**
* Given a path and an index, reads a Segment from the path and updates
* the index.
*
* @param string $path
* @param string $nextLiteral
* @param int $index
* @return Segment
* @throws ValidationException
*/
private static function parseSegmentFromPath(string $path, string &$nextLiteral, int &$index)
{
if ($index >= \strlen($path)) {
// A trailing '/' has caused the index to exceed the bounds
// of the string - provide a helpful error message.
throw self::parseError($path, \strlen($path) - 1, "invalid trailing '/'");
}
if ($path[$index] === '{') {
// Validate that the { has a matching }
$closingBraceIndex = \strpos($path, '}', $index);
if ($closingBraceIndex === \false) {
throw self::parseError($path, \strlen($path), "Expected '}' to match '{' at index {$index}, got end of string");
}
$segmentStringLengthWithoutBraces = $closingBraceIndex - $index - 1;
$segmentStringWithoutBraces = \substr($path, $index + 1, $segmentStringLengthWithoutBraces);
$index = $closingBraceIndex + 1;
$nextLiteral = '/';
$remainingPath = \substr($path, $index);
if (!empty($remainingPath)) {
// Find the firstnon-slash separator seen, if any.
$nextSlashIndex = \strpos($remainingPath, '/', 0);
$nonSlashSeparators = ['-', '_', '~', '.'];
foreach ($nonSlashSeparators as $nonSlashSeparator) {
$nonSlashSeparatorIndex = \strpos($remainingPath, $nonSlashSeparator, 0);
$nextOpenBraceIndex = \strpos($remainingPath, '{', 0);
if ($nonSlashSeparatorIndex !== \false && $nonSlashSeparatorIndex === $nextOpenBraceIndex - 1) {
$index += $nonSlashSeparatorIndex;
$nextLiteral = $nonSlashSeparator;
break;
}
}
}
return self::parseVariableSegment($segmentStringWithoutBraces, $nextLiteral);
} else {
$nextSlash = \strpos($path, '/', $index);
if ($nextSlash === \false) {
$nextSlash = \strlen($path);
}
$segmentString = \substr($path, $index, $nextSlash - $index);
$nextLiteral = '/';
$index = $nextSlash;
return self::parse($segmentString, $path, $index);
}
}
/**
* @param string $segmentString
* @param string $path
* @param int $index
* @return Segment
* @throws ValidationException
*/
private static function parse(string $segmentString, string $path, int $index)
{
if ($segmentString === '*') {
return new Segment(Segment::WILDCARD_SEGMENT);
} elseif ($segmentString === '**') {
return new Segment(Segment::DOUBLE_WILDCARD_SEGMENT);
} else {
if (!self::isValidLiteral($segmentString)) {
if (empty($segmentString)) {
// Create user friendly message in case of empty segment
throw self::parseError($path, $index, "Unexpected empty segment (consecutive '/'s are invalid)");
} else {
throw self::parseError($path, $index, "Unexpected characters in literal segment {$segmentString}");
}
}
return new Segment(Segment::LITERAL_SEGMENT, $segmentString);
}
}
/**
* @param string $segmentStringWithoutBraces
* @param string $separatorLiteral
* @return Segment
* @throws ValidationException
*/
private static function parseVariableSegment(string $segmentStringWithoutBraces, string $separatorLiteral)
{
// Validate there are no nested braces
$nestedOpenBracket = \strpos($segmentStringWithoutBraces, '{');
if ($nestedOpenBracket !== \false) {
throw new ValidationException("Unexpected '{' parsing segment {$segmentStringWithoutBraces} at index {$nestedOpenBracket}");
}
$equalsIndex = \strpos($segmentStringWithoutBraces, '=');
if ($equalsIndex === \false) {
// If the variable does not contain '=', we assume the pattern is '*' as per google.rpc.Http
$variableKey = $segmentStringWithoutBraces;
$nestedResource = new RelativeResourceTemplate("*");
} else {
$variableKey = \substr($segmentStringWithoutBraces, 0, $equalsIndex);
$nestedResourceString = \substr($segmentStringWithoutBraces, $equalsIndex + 1);
$nestedResource = new RelativeResourceTemplate($nestedResourceString);
}
if (!self::isValidLiteral($variableKey)) {
throw new ValidationException("Unexpected characters in variable name {$variableKey}");
}
return new Segment(Segment::VARIABLE_SEGMENT, null, $variableKey, $nestedResource, $separatorLiteral);
}
/**
* @param string $literal
* @param string $path
* @param int $index
* @return string
* @throws ValidationException
*/
private static function parseLiteralFromPath(string $literal, string $path, int &$index)
{
$literalLength = \strlen($literal);
if (\strlen($path) < $index + $literalLength) {
throw self::parseError($path, $index, "expected '{$literal}'");
}
$consumedLiteral = \substr($path, $index, $literalLength);
if ($consumedLiteral !== $literal) {
throw self::parseError($path, $index, "expected '{$literal}'");
}
$index += $literalLength;
return $consumedLiteral;
}
private static function parseError(string $path, int $index, string $reason)
{
return new ValidationException("Error parsing '{$path}' at index {$index}: {$reason}");
}
/**
* Check if $literal is a valid segment literal. Segment literals may only contain numbers,
* letters, and any of the following: .-~_
*
* @param string $literal
* @return bool
*/
private static function isValidLiteral(string $literal)
{
return \preg_match("/^[0-9a-zA-Z\\.\\-~_]+\$/", $literal) === 1;
}
}

View File

@@ -0,0 +1,336 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
/**
* Represents a relative resource template, meaning that it will never contain a leading slash or
* trailing verb (":<verb>").
*
* Examples:
* projects
* projects/{project}
* foo/{bar=**}/fizz/*
*
* Templates use the syntax of the API platform; see
* https://github.com/googleapis/api-common-protos/blob/master/google/api/http.proto
* for details. A template consists of a sequence of literals, wildcards, and variable bindings,
* where each binding can have a sub-path. A string representation can be parsed into an
* instance of AbsoluteResourceTemplate, which can then be used to perform matching and instantiation.
*
* @internal
*/
class RelativeResourceTemplate implements ResourceTemplateInterface
{
/** @var Segment[] */
private array $segments;
/**
* RelativeResourceTemplate constructor.
*
* @param string $path
* @throws ValidationException
*/
public function __construct(string $path)
{
if (empty($path)) {
throw new ValidationException('Cannot construct RelativeResourceTemplate from empty string');
}
$this->segments = Parser::parseSegments($path);
$doubleWildcardCount = self::countDoubleWildcards($this->segments);
if ($doubleWildcardCount > 1) {
throw new ValidationException("Cannot parse '{$path}': cannot contain more than one path wildcard");
}
// Check for duplicate keys
$keys = [];
foreach ($this->segments as $segment) {
if ($segment->getSegmentType() === Segment::VARIABLE_SEGMENT) {
if (isset($keys[$segment->getKey()])) {
throw new ValidationException("Duplicate key '{$segment->getKey()}' in path {$path}");
}
$keys[$segment->getKey()] = \true;
}
}
}
/**
* @inheritdoc
*/
public function __toString()
{
return self::renderSegments($this->segments);
}
/**
* @inheritdoc
*/
public function render(array $bindings)
{
$literalSegments = [];
$keySegmentTuples = self::buildKeySegmentTuples($this->segments);
foreach ($keySegmentTuples as list($key, $segment)) {
/** @var Segment $segment */
if ($segment->getSegmentType() === Segment::LITERAL_SEGMENT) {
$literalSegments[] = $segment;
continue;
}
if (!\array_key_exists($key, $bindings)) {
throw $this->renderingException($bindings, "missing required binding '{$key}' for segment '{$segment}'");
}
$value = $bindings[$key];
if (!\is_null($value) && $segment->matches($value)) {
$literalSegments[] = new Segment(Segment::LITERAL_SEGMENT, $value, $segment->getValue(), $segment->getTemplate(), $segment->getSeparator());
} else {
$valueString = \is_null($value) ? "null" : "'{$value}'";
throw $this->renderingException($bindings, "expected binding '{$key}' to match segment '{$segment}', instead got {$valueString}");
}
}
return self::renderSegments($literalSegments);
}
/**
* @inheritdoc
*/
public function matches(string $path)
{
try {
$this->match($path);
return \true;
} catch (ValidationException $ex) {
return \false;
}
}
/**
* @inheritdoc
*/
public function match(string $path)
{
// High level strategy for matching:
// - Build a list of Segments from our template, where any variable segments are
// flattened into a single, non-nested list
// - Break $path into pieces based on '/'.
// - Use the segments to further subdivide the pieces using any applicable non-slash separators.
// - Match pieces of the path with Segments in the flattened list
// In order to build correct bindings after we match the $path against our template, we
// need to (a) calculate the correct positional keys for our wildcards, and (b) maintain
// information about the variable identifier of any flattened segments. To do this, we
// build a list of [string, Segment] tuples, where the string component is the appropriate
// key.
$keySegmentTuples = self::buildKeySegmentTuples($this->segments);
$flattenedKeySegmentTuples = self::flattenKeySegmentTuples($keySegmentTuples);
$flattenedKeySegmentTuplesCount = \count($flattenedKeySegmentTuples);
\assert($flattenedKeySegmentTuplesCount > 0);
$slashPathPieces = \explode('/', $path);
$pathPieces = [];
$pathPiecesIndex = 0;
$startIndex = 0;
$slashPathPiecesCount = \count($slashPathPieces);
$doubleWildcardPieceCount = $slashPathPiecesCount - $flattenedKeySegmentTuplesCount + 1;
for ($i = 0; $i < \count($flattenedKeySegmentTuples); $i++) {
$segmentKey = $flattenedKeySegmentTuples[$i][0];
$segment = $flattenedKeySegmentTuples[$i][1];
// In our flattened list of segments, we should never encounter a variable segment
\assert($segment->getSegmentType() !== Segment::VARIABLE_SEGMENT);
if ($segment->getSegmentType() == Segment::DOUBLE_WILDCARD_SEGMENT) {
$pathPiecesForSegment = \array_slice($slashPathPieces, $pathPiecesIndex, $doubleWildcardPieceCount);
$pathPiece = \implode('/', $pathPiecesForSegment);
$pathPiecesIndex += $doubleWildcardPieceCount;
$pathPieces[] = $pathPiece;
continue;
}
if ($segment->getSegmentType() == Segment::WILDCARD_SEGMENT) {
if ($pathPiecesIndex >= $slashPathPiecesCount) {
break;
}
}
if ($segment->getSeparator() === '/') {
if ($pathPiecesIndex >= $slashPathPiecesCount) {
throw $this->matchException($path, "segment and path length mismatch");
}
$pathPiece = \substr($slashPathPieces[$pathPiecesIndex++], $startIndex);
$startIndex = 0;
} else {
$rawPiece = \substr($slashPathPieces[$pathPiecesIndex], $startIndex);
$pathPieceLength = \strpos($rawPiece, $segment->getSeparator());
$pathPiece = \substr($rawPiece, 0, $pathPieceLength);
$startIndex += $pathPieceLength + 1;
}
$pathPieces[] = $pathPiece;
}
if ($flattenedKeySegmentTuples[$i - 1][1]->getSegmentType() !== Segment::DOUBLE_WILDCARD_SEGMENT) {
// Process any remaining pieces. The binding logic will throw exceptions for any invalid paths.
for (; $pathPiecesIndex < \count($slashPathPieces); $pathPiecesIndex++) {
$pathPieces[] = $slashPathPieces[$pathPiecesIndex];
}
}
$pathPiecesCount = \count($pathPieces);
// We would like to match pieces of our path 1:1 with the segments of our template. However,
// this is confounded by the presence of double wildcards ('**') in the template, which can
// match multiple segments in the path.
// Because there can only be one '**' present, we can determine how many segments it must
// match by examining the difference in count between the template segments and the
// path pieces.
if ($pathPiecesCount < $flattenedKeySegmentTuplesCount) {
// Each segment in $flattenedKeyedSegments must consume at least one
// segment in $pathSegments, so matching must fail.
throw $this->matchException($path, "path does not contain enough segments to be matched");
}
$doubleWildcardPieceCount = $pathPiecesCount - $flattenedKeySegmentTuplesCount + 1;
$bindings = [];
$pathPiecesIndex = 0;
/** @var Segment $segment */
foreach ($flattenedKeySegmentTuples as list($segmentKey, $segment)) {
$pathPiece = $pathPieces[$pathPiecesIndex++];
if (!$segment->matches($pathPiece)) {
throw $this->matchException($path, "expected path element matching '{$segment}', got '{$pathPiece}'");
}
// If we have a valid key, add our $pathPiece to the $bindings array. Note that there
// may be multiple copies of the same $segmentKey. This is because a flattened variable
// segment can match multiple pieces from the path. We can add these to an array and
// collapse them all once the bindings are complete.
if (isset($segmentKey)) {
$bindings += [$segmentKey => []];
$bindings[$segmentKey][] = $pathPiece;
}
}
// It is possible that we have left over path pieces, which can occur if our template does
// not have a double wildcard. In that case, the match should fail.
if ($pathPiecesIndex !== $pathPiecesCount) {
throw $this->matchException($path, "expected end of path, got '{$pathPieces[$pathPiecesIndex]}'");
}
// Collapse the bindings from lists into strings
$collapsedBindings = [];
foreach ($bindings as $key => $boundPieces) {
$collapsedBindings[$key] = \implode('/', $boundPieces);
}
return $collapsedBindings;
}
private function matchException(string $path, string $reason)
{
return new ValidationException("Could not match path '{$path}' to template '{$this}': {$reason}");
}
private function renderingException(array $bindings, string $reason)
{
$bindingsString = \print_r($bindings, \true);
return new ValidationException("Error rendering '{$this}': {$reason}\n" . "Provided bindings: {$bindingsString}");
}
/**
* @param Segment[] $segments
* @param string|null $separator An optional string separator
* @return array[] A list of [string, Segment] tuples
*/
private static function buildKeySegmentTuples(array $segments, string $separator = null)
{
$keySegmentTuples = [];
$positionalArgumentCounter = 0;
foreach ($segments as $segment) {
switch ($segment->getSegmentType()) {
case Segment::WILDCARD_SEGMENT:
case Segment::DOUBLE_WILDCARD_SEGMENT:
$positionalKey = "\${$positionalArgumentCounter}";
$positionalArgumentCounter++;
$newSegment = $segment;
if ($separator !== null) {
$newSegment = new Segment($segment->getSegmentType(), $segment->getValue(), $segment->getKey(), $segment->getTemplate(), $separator);
}
$keySegmentTuples[] = [$positionalKey, $newSegment];
break;
default:
$keySegmentTuples[] = [$segment->getKey(), $segment];
}
}
return $keySegmentTuples;
}
/**
* @param array[] $keySegmentTuples A list of [string, Segment] tuples
* @return array[] A list of [string, Segment] tuples
*/
private static function flattenKeySegmentTuples(array $keySegmentTuples)
{
$flattenedKeySegmentTuples = [];
foreach ($keySegmentTuples as list($key, $segment)) {
/** @var Segment $segment */
switch ($segment->getSegmentType()) {
case Segment::VARIABLE_SEGMENT:
// For segment variables, replace the segment with the segments of its children
$template = $segment->getTemplate();
$nestedKeySegmentTuples = self::buildKeySegmentTuples($template->segments, $segment->getSeparator());
foreach ($nestedKeySegmentTuples as list($nestedKey, $nestedSegment)) {
/** @var Segment $nestedSegment */
// Nested variables are not allowed
\assert($nestedSegment->getSegmentType() !== Segment::VARIABLE_SEGMENT);
// Insert the nested segment with key set to the outer key of the
// parent variable segment
$flattenedKeySegmentTuples[] = [$key, $nestedSegment];
}
break;
default:
// For all other segments, don't change the key or segment
$flattenedKeySegmentTuples[] = [$key, $segment];
}
}
return $flattenedKeySegmentTuples;
}
/**
* @param Segment[] $segments
* @return int
*/
private static function countDoubleWildcards(array $segments)
{
$doubleWildcardCount = 0;
foreach ($segments as $segment) {
switch ($segment->getSegmentType()) {
case Segment::DOUBLE_WILDCARD_SEGMENT:
$doubleWildcardCount++;
break;
case Segment::VARIABLE_SEGMENT:
$doubleWildcardCount += self::countDoubleWildcards($segment->getTemplate()->segments);
break;
}
}
return $doubleWildcardCount;
}
/**
* Joins segments using their separators.
* @param array $segmentsToRender
* @return string
*/
private static function renderSegments(array $segmentsToRender)
{
$renderResult = "";
for ($i = 0; $i < \count($segmentsToRender); $i++) {
$segment = $segmentsToRender[$i];
$renderResult .= $segment;
if ($i < \count($segmentsToRender) - 1) {
$renderResult .= $segment->getSeparator();
}
}
return $renderResult;
}
}

View File

@@ -0,0 +1,87 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
/**
* Represents a resource template that may or may not contain a leading slash, and if a leading
* slash is present may contain a trailing verb (":<verb>"). (Note that a trailing verb without a
* leading slash is not permitted).
*
* Examples:
* projects
* /projects
* foo/{bar=**}/fizz/*
* /foo/{bar=**}/fizz/*:action
*
* Templates use the syntax of the API platform; see
* https://github.com/googleapis/api-common-protos/blob/master/google/api/http.proto
* for details. A template consists of a sequence of literals, wildcards, and variable bindings,
* where each binding can have a sub-path. A string representation can be parsed into an
* instance of AbsoluteResourceTemplate, which can then be used to perform matching and instantiation.
*
* @internal
*/
interface ResourceTemplateInterface
{
/**
* @return string A string representation of the resource template
*/
public function __toString();
/**
* Renders a resource template using the provided bindings.
*
* @param array $bindings An array matching var names to binding strings.
* @return string A rendered representation of this resource template.
* @throws ValidationException If $bindings does not contain all required keys
* or if a sub-template can't be parsed.
*/
public function render(array $bindings);
/**
* Check if $path matches a resource string.
*
* @param string $path A resource string.
* @return bool
*/
public function matches(string $path);
/**
* Matches a given $path to a resource template, and returns an array of bindings between
* wildcards / variables in the template and values in the path. If $path does not match the
* template, then a ValidationException is thrown.
*
* @param string $path A resource string.
* @throws ValidationException if path can't be matched to the template.
* @return array Array matching var names to binding values.
*/
public function match(string $path);
}

View File

@@ -0,0 +1,173 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ResourceTemplate;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
/**
* Represents a segment in a resource template. This is used internally by RelativeResourceTemplate,
* but is not intended for public use and may change without notice.
*
* @internal
*/
class Segment
{
const LITERAL_SEGMENT = 0;
const WILDCARD_SEGMENT = 1;
const DOUBLE_WILDCARD_SEGMENT = 2;
const VARIABLE_SEGMENT = 3;
private int $segmentType;
private ?string $value;
private ?string $key;
private ?RelativeResourceTemplate $template;
private ?string $stringRepr;
private ?string $separator;
/**
* Segment constructor.
* @param int $segmentType
* @param string|null $value
* @param string|null $key
* @param RelativeResourceTemplate|null $template
* @param string $separator The separator that belongs at the end of a segment. Ending segments should use '/'.
* @throws ValidationException
*/
public function __construct(int $segmentType, string $value = null, string $key = null, RelativeResourceTemplate $template = null, string $separator = '/')
{
$this->segmentType = $segmentType;
$this->value = $value;
$this->key = $key;
$this->template = $template;
$this->separator = $separator;
switch ($this->segmentType) {
case Segment::LITERAL_SEGMENT:
$this->stringRepr = "{$this->value}";
break;
case Segment::WILDCARD_SEGMENT:
$this->stringRepr = "*";
break;
case Segment::DOUBLE_WILDCARD_SEGMENT:
$this->stringRepr = "**";
break;
case Segment::VARIABLE_SEGMENT:
$this->stringRepr = "{{$this->key}={$this->template}}";
break;
default:
throw new ValidationException("Unexpected Segment type: {$this->segmentType}");
}
}
/**
* @return string A string representation of the segment.
*/
public function __toString()
{
return $this->stringRepr;
}
/**
* Checks if $value matches this Segment.
*
* @param string $value
* @return bool
* @throws ValidationException
*/
public function matches(string $value)
{
switch ($this->segmentType) {
case Segment::LITERAL_SEGMENT:
return $this->value === $value;
case Segment::WILDCARD_SEGMENT:
return self::isValidBinding($value);
case Segment::DOUBLE_WILDCARD_SEGMENT:
return self::isValidDoubleWildcardBinding($value);
case Segment::VARIABLE_SEGMENT:
return $this->template->matches($value);
default:
throw new ValidationException("Unexpected Segment type: {$this->segmentType}");
}
}
/**
* @return int
*/
public function getSegmentType()
{
return $this->segmentType;
}
/**
* @return string|null
*/
public function getKey()
{
return $this->key;
}
/**
* @return string|null
*/
public function getValue()
{
return $this->value;
}
/**
* @return RelativeResourceTemplate|null
*/
public function getTemplate()
{
return $this->template;
}
/**
* @return string
*/
public function getSeparator()
{
return $this->separator;
}
/**
* Check if $binding is a valid segment binding. Segment bindings may contain any characters
* except a forward slash ('/'), and may not be empty.
*
* @param string $binding
* @return bool
*/
private static function isValidBinding(string $binding)
{
return \preg_match("-^[^/]+\$-", $binding) === 1;
}
/**
* Check if $binding is a valid double wildcard binding. Segment bindings may contain any
* characters, but may not be empty.
*
* @param string $binding
* @return bool
*/
private static function isValidDoubleWildcardBinding(string $binding)
{
return \preg_match("-^.+\$-", $binding) === 1;
}
}

View File

@@ -0,0 +1,462 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use Closure;
/**
* The RetrySettings class is used to configure retrying and timeouts for RPCs.
* This class can be passed as an optional parameter to RPC methods, or as part
* of an optional array in the constructor of a client object. In addition,
* many RPCs and API clients accept a PHP array in place of a RetrySettings
* object. This can be used to change particular retry parameters without
* needing to construct a complete RetrySettings object.
*
* Constructing a RetrySettings object
* -----------------------------------
*
* See the RetrySettings constructor for documentation about parameters that
* can be passed to RetrySettings.
*
* Example of creating a RetrySettings object using the constructor:
* ```
* $retrySettings = new RetrySettings([
* 'initialRetryDelayMillis' => 100,
* 'retryDelayMultiplier' => 1.3,
* 'maxRetryDelayMillis' => 60000,
* 'initialRpcTimeoutMillis' => 20000,
* 'rpcTimeoutMultiplier' => 1.0,
* 'maxRpcTimeoutMillis' => 20000,
* 'totalTimeoutMillis' => 600000,
* 'retryableCodes' => [ApiStatus::DEADLINE_EXCEEDED, ApiStatus::UNAVAILABLE],
* ]);
* ```
*
* It is also possible to create a new RetrySettings object from an existing
* object using the {@see \Google\ApiCore\RetrySettings::with()} method.
*
* Example modifying an existing RetrySettings object using `with()`:
* ```
* $newRetrySettings = $retrySettings->with([
* 'totalTimeoutMillis' => 700000,
* ]);
* ```
*
* Modifying the retry behavior of an RPC method
* ---------------------------------------------
*
* RetrySettings objects can be used to control retries for many RPC methods in
* [google-cloud-php](https://github.com/googleapis/google-cloud-php).
* The examples below make use of the
* [GroupServiceClient](https://googleapis.github.io/google-cloud-php/#/docs/google-cloud/monitoring/v3/groupserviceclient)
* from the [Monitoring V3 API](https://github.com/googleapis/google-cloud-php/tree/master/src/Monitoring/V3),
* but they can be applied to other APIs in the
* [google-cloud-php](https://github.com/googleapis/google-cloud-php) repository.
*
* It is possible to specify the retry behavior to be used by an RPC via the
* `retrySettings` field in the `optionalArgs` parameter. The `retrySettings`
* field can contain either a RetrySettings object, or a PHP array containing
* the particular retry parameters to be updated.
*
* Example of disabling retries for a single call to the
* [listGroups](https://googleapis.github.io/google-cloud-php/#/docs/google-cloud/monitoring/v3/groupserviceclient?method=listGroups)
* method, and setting a custom timeout:
* ```
* $result = $client->listGroups($name, [
* 'retrySettings' => [
* 'retriesEnabled' => false,
* 'noRetriesRpcTimeoutMillis' => 5000,
* ]
* ]);
* ```
*
* Example of creating a new RetrySettings object and using it to override
* the retry settings for a call to the
* [listGroups](https://googleapis.github.io/google-cloud-php/#/docs/google-cloud/monitoring/v3/groupserviceclient?method=listGroups)
* method:
* ```
* $customRetrySettings = new RetrySettings([
* 'initialRetryDelayMillis' => 100,
* 'retryDelayMultiplier' => 1.3,
* 'maxRetryDelayMillis' => 60000,
* 'initialRpcTimeoutMillis' => 20000,
* 'rpcTimeoutMultiplier' => 1.0,
* 'maxRpcTimeoutMillis' => 20000,
* 'totalTimeoutMillis' => 600000,
* 'retryableCodes' => [ApiStatus::DEADLINE_EXCEEDED, ApiStatus::UNAVAILABLE],
* ]);
*
* $result = $client->listGroups($name, [
* 'retrySettings' => $customRetrySettings
* ]);
* ```
*
* Modifying the default retry behavior for RPC methods on a Client object
* -----------------------------------------------------------------------
*
* It is also possible to specify the retry behavior for RPC methods when
* constructing a client object using the 'retrySettingsArray'. The examples
* below again make use of the
* [GroupServiceClient](https://googleapis.github.io/google-cloud-php/#/docs/google-cloud/monitoring/v3/groupserviceclient)
* from the [Monitoring V3 API](https://github.com/googleapis/google-cloud-php/tree/master/src/Monitoring/V3),
* but they can be applied to other APIs in the
* [google-cloud-php](https://github.com/googleapis/google-cloud-php) repository.
*
* The GroupServiceClient object accepts an optional `retrySettingsArray`
* parameter, which can be used to specify retry behavior for RPC methods
* on the client. The `retrySettingsArray` accepts a PHP array in which keys
* are the names of RPC methods on the client, and values are either a
* RetrySettings object or a PHP array containing the particular retry
* parameters to be updated.
*
* Example updating the retry settings for four methods of GroupServiceClient:
* ```
* use Google\Cloud\Monitoring\V3\GroupServiceClient;
*
* $customRetrySettings = new RetrySettings([
* 'initialRetryDelayMillis' => 100,
* 'retryDelayMultiplier' => 1.3,
* 'maxRetryDelayMillis' => 60000,
* 'initialRpcTimeoutMillis' => 20000,
* 'rpcTimeoutMultiplier' => 1.0,
* 'maxRpcTimeoutMillis' => 20000,
* 'totalTimeoutMillis' => 600000,
* 'retryableCodes' => [ApiStatus::DEADLINE_EXCEEDED, ApiStatus::UNAVAILABLE],
* ]);
*
* $updatedCustomRetrySettings = $customRetrySettings->with([
* 'totalTimeoutMillis' => 700000
* ]);
*
* $client = new GroupServiceClient([
* 'retrySettingsArray' => [
* 'listGroups' => ['retriesEnabled' => false],
* 'getGroup' => [
* 'initialRpcTimeoutMillis' => 10000,
* 'maxRpcTimeoutMillis' => 30000,
* 'totalTimeoutMillis' => 60000,
* ],
* 'deleteGroup' => $customRetrySettings,
* 'updateGroup' => $updatedCustomRetrySettings
* ],
* ]);
* ```
*
* Configure the use of logical timeout
* ------------------------------------
*
* To configure the use of a logical timeout, where a logical timeout is the
* duration a method is given to complete one or more RPC attempts, with each
* attempt using only the time remaining in the logical timeout, use
* {@see \Google\ApiCore\RetrySettings::logicalTimeout()} combined with
* {@see \Google\ApiCore\RetrySettings::with()}.
*
* ```
* $timeoutSettings = RetrySettings::logicalTimeout(30000);
*
* $customRetrySettings = $customRetrySettings->with($timeoutSettings);
*
* $result = $client->listGroups($name, [
* 'retrySettings' => $customRetrySettings
* ]);
* ```
*
* {@see \Google\ApiCore\RetrySettings::logicalTimeout()} can also be used on a
* method call independent of a RetrySettings instance.
*
* ```
* $timeoutSettings = RetrySettings::logicalTimeout(30000);
*
* $result = $client->listGroups($name, [
* 'retrySettings' => $timeoutSettings
* ]);
* ```
*/
class RetrySettings
{
use ValidationTrait;
const DEFAULT_MAX_RETRIES = 0;
private $retriesEnabled;
private $retryableCodes;
private $initialRetryDelayMillis;
private $retryDelayMultiplier;
private $maxRetryDelayMillis;
private $initialRpcTimeoutMillis;
private $rpcTimeoutMultiplier;
private $maxRpcTimeoutMillis;
private $totalTimeoutMillis;
private $noRetriesRpcTimeoutMillis;
/**
* The number of maximum retries an operation can do.
* This doesn't include the original API call.
* Setting this to 0 means no limit.
*/
private int $maxRetries;
/**
* When set, this function will be used to evaluate if the retry should
* take place or not. The callable will have the following signature:
* function (Exception $e, array $options): bool
*/
private ?Closure $retryFunction;
/**
* Constructs an instance.
*
* @param array $settings {
* Required. Settings for configuring the retry behavior. All parameters are required except
* $retriesEnabled and $noRetriesRpcTimeoutMillis, which are optional and have defaults
* determined based on the other settings provided.
*
* @type bool $retriesEnabled Optional. Enables retries. If not specified, the value is
* determined using the $retryableCodes setting. If $retryableCodes is empty,
* then $retriesEnabled is set to false; otherwise, it is set to true.
* @type int $noRetriesRpcTimeoutMillis Optional. The timeout of the rpc call to be used
* if $retriesEnabled is false, in milliseconds. It not specified, the value
* of $initialRpcTimeoutMillis is used.
* @type array $retryableCodes The Status codes that are retryable. Each status should be
* either one of the string constants defined on {@see \Google\ApiCore\ApiStatus}
* or an integer constant defined on {@see \Google\Rpc\Code}.
* @type int $initialRetryDelayMillis The initial delay of retry in milliseconds.
* @type int $retryDelayMultiplier The exponential multiplier of retry delay.
* @type int $maxRetryDelayMillis The max delay of retry in milliseconds.
* @type int $initialRpcTimeoutMillis The initial timeout of rpc call in milliseconds.
* @type int $rpcTimeoutMultiplier The exponential multiplier of rpc timeout.
* @type int $maxRpcTimeoutMillis The max timeout of rpc call in milliseconds.
* @type int $totalTimeoutMillis The max accumulative timeout in total.
* @type int $maxRetries The max retries allowed for an operation.
* Defaults to the value of the DEFAULT_MAX_RETRIES constant.
* This option is experimental.
* @type callable $retryFunction This function will be used to decide if we should retry or not.
* Callable signature: `function (Exception $e, array $options): bool`
* This option is experimental.
* }
*/
public function __construct(array $settings)
{
$this->validateNotNull($settings, ['initialRetryDelayMillis', 'retryDelayMultiplier', 'maxRetryDelayMillis', 'initialRpcTimeoutMillis', 'rpcTimeoutMultiplier', 'maxRpcTimeoutMillis', 'totalTimeoutMillis', 'retryableCodes']);
$this->initialRetryDelayMillis = $settings['initialRetryDelayMillis'];
$this->retryDelayMultiplier = $settings['retryDelayMultiplier'];
$this->maxRetryDelayMillis = $settings['maxRetryDelayMillis'];
$this->initialRpcTimeoutMillis = $settings['initialRpcTimeoutMillis'];
$this->rpcTimeoutMultiplier = $settings['rpcTimeoutMultiplier'];
$this->maxRpcTimeoutMillis = $settings['maxRpcTimeoutMillis'];
$this->totalTimeoutMillis = $settings['totalTimeoutMillis'];
$this->retryableCodes = $settings['retryableCodes'];
$this->retriesEnabled = \array_key_exists('retriesEnabled', $settings) ? $settings['retriesEnabled'] : \count($this->retryableCodes) > 0;
$this->noRetriesRpcTimeoutMillis = \array_key_exists('noRetriesRpcTimeoutMillis', $settings) ? $settings['noRetriesRpcTimeoutMillis'] : $this->initialRpcTimeoutMillis;
$this->maxRetries = $settings['maxRetries'] ?? self::DEFAULT_MAX_RETRIES;
$this->retryFunction = $settings['retryFunction'] ?? null;
}
/**
* Constructs an array mapping method names to CallSettings.
*
* @param string $serviceName
* The fully-qualified name of this service, used as a key into
* the client config file.
* @param array $clientConfig
* An array parsed from the standard API client config file.
* @param bool $disableRetries
* Disable retries in all loaded RetrySettings objects. Defaults to false.
* @throws ValidationException
* @return RetrySettings[] $retrySettings
*/
public static function load(string $serviceName, array $clientConfig, bool $disableRetries = \false)
{
$serviceRetrySettings = [];
$serviceConfig = $clientConfig['interfaces'][$serviceName];
$retryCodes = $serviceConfig['retry_codes'];
$retryParams = $serviceConfig['retry_params'];
foreach ($serviceConfig['methods'] as $methodName => $methodConfig) {
$timeoutMillis = $methodConfig['timeout_millis'];
if (empty($methodConfig['retry_codes_name']) || empty($methodConfig['retry_params_name'])) {
// Construct a RetrySettings object with retries disabled
$retrySettings = self::constructDefault()->with(['noRetriesRpcTimeoutMillis' => $timeoutMillis]);
} else {
$retryCodesName = $methodConfig['retry_codes_name'];
$retryParamsName = $methodConfig['retry_params_name'];
if (!\array_key_exists($retryCodesName, $retryCodes)) {
throw new ValidationException("Invalid retry_codes_name setting: '{$retryCodesName}'");
}
if (!\array_key_exists($retryParamsName, $retryParams)) {
throw new ValidationException("Invalid retry_params_name setting: '{$retryParamsName}'");
}
foreach ($retryCodes[$retryCodesName] as $status) {
if (!ApiStatus::isValidStatus($status)) {
throw new ValidationException("Invalid status code: '{$status}'");
}
}
$retryParameters = self::convertArrayFromSnakeCase($retryParams[$retryParamsName]) + ['retryableCodes' => $retryCodes[$retryCodesName], 'noRetriesRpcTimeoutMillis' => $timeoutMillis];
if ($disableRetries) {
$retryParameters['retriesEnabled'] = \false;
}
$retrySettings = new RetrySettings($retryParameters);
}
$serviceRetrySettings[$methodName] = $retrySettings;
}
return $serviceRetrySettings;
}
public static function constructDefault()
{
return new RetrySettings(['retriesEnabled' => \false, 'noRetriesRpcTimeoutMillis' => 30000, 'initialRetryDelayMillis' => 100, 'retryDelayMultiplier' => 1.3, 'maxRetryDelayMillis' => 60000, 'initialRpcTimeoutMillis' => 20000, 'rpcTimeoutMultiplier' => 1, 'maxRpcTimeoutMillis' => 20000, 'totalTimeoutMillis' => 600000, 'retryableCodes' => [], 'maxRetries' => self::DEFAULT_MAX_RETRIES, 'retryFunction' => null]);
}
/**
* Creates a new instance of RetrySettings that updates the settings in the existing instance
* with the settings specified in the $settings parameter.
*
* @param array $settings {
* Settings for configuring the retry behavior. Supports all of the options supported by
* the constructor; see {@see \Google\ApiCore\RetrySettings::__construct()}. All parameters
* are optional - all unset parameters will default to the value in the existing instance.
* }
* @return RetrySettings
*/
public function with(array $settings)
{
$existingSettings = ['initialRetryDelayMillis' => $this->getInitialRetryDelayMillis(), 'retryDelayMultiplier' => $this->getRetryDelayMultiplier(), 'maxRetryDelayMillis' => $this->getMaxRetryDelayMillis(), 'initialRpcTimeoutMillis' => $this->getInitialRpcTimeoutMillis(), 'rpcTimeoutMultiplier' => $this->getRpcTimeoutMultiplier(), 'maxRpcTimeoutMillis' => $this->getMaxRpcTimeoutMillis(), 'totalTimeoutMillis' => $this->getTotalTimeoutMillis(), 'retryableCodes' => $this->getRetryableCodes(), 'retriesEnabled' => $this->retriesEnabled(), 'noRetriesRpcTimeoutMillis' => $this->getNoRetriesRpcTimeoutMillis(), 'maxRetries' => $this->getMaxRetries(), 'retryFunction' => $this->getRetryFunction()];
return new RetrySettings($settings + $existingSettings);
}
/**
* Creates an associative array of the {@see \Google\ApiCore\RetrySettings} timeout fields configured
* with the given timeout specified in the $timeout parameter interpreted as a logical timeout.
*
* @param int $timeout The timeout in milliseconds to be used as a logical call timeout.
* @return array
*/
public static function logicalTimeout(int $timeout)
{
return ['initialRpcTimeoutMillis' => $timeout, 'maxRpcTimeoutMillis' => $timeout, 'totalTimeoutMillis' => $timeout, 'noRetriesRpcTimeoutMillis' => $timeout, 'rpcTimeoutMultiplier' => 1.0];
}
/**
* @return bool Returns true if retries are enabled, otherwise returns false.
*/
public function retriesEnabled()
{
return $this->retriesEnabled;
}
/**
* @return int The timeout of the rpc call to be used if $retriesEnabled is false,
* in milliseconds.
*/
public function getNoRetriesRpcTimeoutMillis()
{
return $this->noRetriesRpcTimeoutMillis;
}
/**
* @return int[] Status codes to retry
*/
public function getRetryableCodes()
{
return $this->retryableCodes;
}
/**
* @return int The initial retry delay in milliseconds. If $this->retriesEnabled()
* is false, this setting is unused.
*/
public function getInitialRetryDelayMillis()
{
return $this->initialRetryDelayMillis;
}
/**
* @return float The retry delay multiplier. If $this->retriesEnabled()
* is false, this setting is unused.
*/
public function getRetryDelayMultiplier()
{
return $this->retryDelayMultiplier;
}
/**
* @return int The maximum retry delay in milliseconds. If $this->retriesEnabled()
* is false, this setting is unused.
*/
public function getMaxRetryDelayMillis()
{
return $this->maxRetryDelayMillis;
}
/**
* @return int The initial rpc timeout in milliseconds. If $this->retriesEnabled()
* is false, this setting is unused - use noRetriesRpcTimeoutMillis to
* set the timeout in that case.
*/
public function getInitialRpcTimeoutMillis()
{
return $this->initialRpcTimeoutMillis;
}
/**
* @return float The rpc timeout multiplier. If $this->retriesEnabled()
* is false, this setting is unused.
*/
public function getRpcTimeoutMultiplier()
{
return $this->rpcTimeoutMultiplier;
}
/**
* @return int The maximum rpc timeout in milliseconds. If $this->retriesEnabled()
* is false, this setting is unused - use noRetriesRpcTimeoutMillis to
* set the timeout in that case.
*/
public function getMaxRpcTimeoutMillis()
{
return $this->maxRpcTimeoutMillis;
}
/**
* @return int The total time in milliseconds to spend on the call, including all
* retry attempts and delays between attempts. If $this->retriesEnabled()
* is false, this setting is unused - use noRetriesRpcTimeoutMillis to
* set the timeout in that case.
*/
public function getTotalTimeoutMillis()
{
return $this->totalTimeoutMillis;
}
/**
* @experimental
*/
public function getMaxRetries()
{
return $this->maxRetries;
}
/**
* @experimental
*/
public function getRetryFunction()
{
return $this->retryFunction;
}
private static function convertArrayFromSnakeCase(array $settings)
{
$camelCaseSettings = [];
foreach ($settings as $key => $value) {
$camelCaseKey = \str_replace(' ', '', \ucwords(\str_replace('_', ' ', $key)));
$camelCaseSettings[\lcfirst($camelCaseKey)] = $value;
}
return $camelCaseSettings;
}
}

421
vendor/Gcp/google/gax/src/Serializer.php vendored Normal file
View File

@@ -0,0 +1,421 @@
<?php
/*
* Copyright 2017 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Any;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Descriptor;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\DescriptorPool;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\FieldDescriptor;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use RuntimeException;
/**
* Collection of methods to help with serialization of protobuf objects
*/
class Serializer
{
const MAP_KEY_FIELD_NAME = 'key';
const MAP_VALUE_FIELD_NAME = 'value';
private static $phpArraySerializer;
private static $metadataKnownTypes = ['google.rpc.retryinfo-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\RetryInfo::class, 'google.rpc.debuginfo-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\DebugInfo::class, 'google.rpc.quotafailure-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\QuotaFailure::class, 'google.rpc.badrequest-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\BadRequest::class, 'google.rpc.requestinfo-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\RequestInfo::class, 'google.rpc.resourceinfo-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\ResourceInfo::class, 'google.rpc.errorinfo-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\ErrorInfo::class, 'google.rpc.help-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Help::class, 'google.rpc.localizedmessage-bin' => \DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\LocalizedMessage::class];
private $fieldTransformers;
private $messageTypeTransformers;
private $decodeFieldTransformers;
private $decodeMessageTypeTransformers;
private $descriptorMaps = [];
/**
* Serializer constructor.
*
* @param array $fieldTransformers An array mapping field names to transformation functions
* @param array $messageTypeTransformers An array mapping message names to transformation functions
* @param array $decodeFieldTransformers An array mapping field names to transformation functions
* @param array $decodeMessageTypeTransformers An array mapping message names to transformation functions
*/
public function __construct($fieldTransformers = [], $messageTypeTransformers = [], $decodeFieldTransformers = [], $decodeMessageTypeTransformers = [])
{
$this->fieldTransformers = $fieldTransformers;
$this->messageTypeTransformers = $messageTypeTransformers;
$this->decodeFieldTransformers = $decodeFieldTransformers;
$this->decodeMessageTypeTransformers = $decodeMessageTypeTransformers;
}
/**
* Encode protobuf message as a PHP array
*
* @param mixed $message
* @return array
* @throws ValidationException
*/
public function encodeMessage($message)
{
// Get message descriptor
$pool = DescriptorPool::getGeneratedPool();
$messageType = $pool->getDescriptorByClassName(\get_class($message));
try {
return $this->encodeMessageImpl($message, $messageType);
} catch (\Exception $e) {
throw new ValidationException("Error encoding message: " . $e->getMessage(), $e->getCode(), $e);
}
}
/**
* Decode PHP array into the specified protobuf message
*
* @param mixed $message
* @param array $data
* @return mixed
* @throws ValidationException
*/
public function decodeMessage($message, array $data)
{
// Get message descriptor
$pool = DescriptorPool::getGeneratedPool();
$messageType = $pool->getDescriptorByClassName(\get_class($message));
try {
return $this->decodeMessageImpl($message, $messageType, $data);
} catch (\Exception $e) {
throw new ValidationException("Error decoding message: " . $e->getMessage(), $e->getCode(), $e);
}
}
/**
* @param Message $message
* @return string Json representation of $message
* @throws ValidationException
*/
public static function serializeToJson(Message $message)
{
return \json_encode(self::serializeToPhpArray($message), \JSON_PRETTY_PRINT);
}
/**
* @param Message $message
* @return array PHP array representation of $message
* @throws ValidationException
*/
public static function serializeToPhpArray(Message $message)
{
return self::getPhpArraySerializer()->encodeMessage($message);
}
/**
* Decode metadata received from gRPC status object
*
* @param array $metadata
* @return array
*/
public static function decodeMetadata(array $metadata)
{
if (\count($metadata) == 0) {
return [];
}
$result = [];
foreach ($metadata as $key => $values) {
foreach ($values as $value) {
$decodedValue = ['@type' => $key];
if (self::hasBinaryHeaderSuffix($key)) {
if (isset(self::$metadataKnownTypes[$key])) {
$class = self::$metadataKnownTypes[$key];
/** @var Message $message */
$message = new $class();
try {
$message->mergeFromString($value);
$decodedValue += self::serializeToPhpArray($message);
} catch (\Exception $e) {
// We encountered an error trying to deserialize the data
$decodedValue += ['data' => '<Unable to deserialize data>'];
}
} else {
// The metadata contains an unexpected binary type
$decodedValue += ['data' => '<Unknown Binary Data>'];
}
} else {
$decodedValue += ['data' => $value];
}
$result[] = $decodedValue;
}
}
return $result;
}
/**
* Decode an array of Any messages into a printable PHP array.
*
* @param iterable $anyArray
* @return array
*/
public static function decodeAnyMessages($anyArray)
{
$results = [];
foreach ($anyArray as $any) {
try {
/** @var Any $any */
/** @var Message $unpacked */
$unpacked = $any->unpack();
$results[] = self::serializeToPhpArray($unpacked);
} catch (\Exception $ex) {
echo "{$ex}\n";
// failed to unpack the $any object - show as unknown binary data
$results[] = ['typeUrl' => $any->getTypeUrl(), 'value' => '<Unknown Binary Data>'];
}
}
return $results;
}
/**
* @param FieldDescriptor $field
* @param Message|array|string $data
* @return mixed
* @throws \Exception
*/
private function encodeElement(FieldDescriptor $field, $data)
{
switch ($field->getType()) {
case GPBType::MESSAGE:
if (\is_array($data)) {
$result = $data;
} else {
$result = $this->encodeMessageImpl($data, $field->getMessageType());
}
$messageType = $field->getMessageType()->getFullName();
if (isset($this->messageTypeTransformers[$messageType])) {
$result = $this->messageTypeTransformers[$messageType]($result);
}
break;
default:
$result = $data;
break;
}
if (isset($this->fieldTransformers[$field->getName()])) {
$result = $this->fieldTransformers[$field->getName()]($result);
}
return $result;
}
private function getDescriptorMaps(Descriptor $descriptor)
{
if (!isset($this->descriptorMaps[$descriptor->getFullName()])) {
$fieldsByName = [];
$fieldCount = $descriptor->getFieldCount();
for ($i = 0; $i < $fieldCount; $i++) {
$field = $descriptor->getField($i);
$fieldsByName[$field->getName()] = $field;
}
$fieldToOneof = [];
$oneofCount = $descriptor->getOneofDeclCount();
for ($i = 0; $i < $oneofCount; $i++) {
$oneof = $descriptor->getOneofDecl($i);
$oneofFieldCount = $oneof->getFieldCount();
for ($j = 0; $j < $oneofFieldCount; $j++) {
$field = $oneof->getField($j);
$fieldToOneof[$field->getName()] = $oneof->getName();
}
}
$this->descriptorMaps[$descriptor->getFullName()] = [$fieldsByName, $fieldToOneof];
}
return $this->descriptorMaps[$descriptor->getFullName()];
}
/**
* @param Message $message
* @param Descriptor $messageType
* @return array
* @throws \Exception
*/
private function encodeMessageImpl(Message $message, Descriptor $messageType)
{
$data = [];
$fieldCount = $messageType->getFieldCount();
for ($i = 0; $i < $fieldCount; $i++) {
$field = $messageType->getField($i);
$key = $field->getName();
$getter = $this->getGetter($key);
$v = $message->{$getter}();
if (\is_null($v)) {
continue;
}
// Check and skip unset fields inside oneofs
list($_, $fieldsToOneof) = $this->getDescriptorMaps($messageType);
if (isset($fieldsToOneof[$key])) {
$oneofName = $fieldsToOneof[$key];
$oneofGetter = $this->getGetter($oneofName);
if ($message->{$oneofGetter}() !== $key) {
continue;
}
}
if ($field->isMap()) {
list($mapFieldsByName, $_) = $this->getDescriptorMaps($field->getMessageType());
$keyField = $mapFieldsByName[self::MAP_KEY_FIELD_NAME];
$valueField = $mapFieldsByName[self::MAP_VALUE_FIELD_NAME];
$arr = [];
foreach ($v as $k => $vv) {
$arr[$this->encodeElement($keyField, $k)] = $this->encodeElement($valueField, $vv);
}
$v = $arr;
} elseif ($field->getLabel() === GPBLabel::REPEATED) {
$arr = [];
foreach ($v as $k => $vv) {
$arr[$k] = $this->encodeElement($field, $vv);
}
$v = $arr;
} else {
$v = $this->encodeElement($field, $v);
}
$key = self::toCamelCase($key);
$data[$key] = $v;
}
return $data;
}
/**
* @param FieldDescriptor $field
* @param mixed $data
* @return mixed
* @throws \Exception
*/
private function decodeElement(FieldDescriptor $field, $data)
{
if (isset($this->decodeFieldTransformers[$field->getName()])) {
$data = $this->decodeFieldTransformers[$field->getName()]($data);
}
switch ($field->getType()) {
case GPBType::MESSAGE:
if ($data instanceof Message) {
return $data;
}
$messageType = $field->getMessageType();
$messageTypeName = $messageType->getFullName();
$klass = $messageType->getClass();
$msg = new $klass();
if (isset($this->decodeMessageTypeTransformers[$messageTypeName])) {
$data = $this->decodeMessageTypeTransformers[$messageTypeName]($data);
}
return $this->decodeMessageImpl($msg, $messageType, $data);
default:
return $data;
}
}
/**
* @param Message $message
* @param Descriptor $messageType
* @param array $data
* @return mixed
* @throws \Exception
*/
private function decodeMessageImpl(Message $message, Descriptor $messageType, array $data)
{
list($fieldsByName, $_) = $this->getDescriptorMaps($messageType);
foreach ($data as $key => $v) {
// Get the field by tag number or name
$fieldName = self::toSnakeCase($key);
// Unknown field found
if (!isset($fieldsByName[$fieldName])) {
throw new RuntimeException(\sprintf("cannot handle unknown field %s on message %s", $fieldName, $messageType->getFullName()));
}
/** @var FieldDescriptor $field */
$field = $fieldsByName[$fieldName];
if ($field->isMap()) {
list($mapFieldsByName, $_) = $this->getDescriptorMaps($field->getMessageType());
$keyField = $mapFieldsByName[self::MAP_KEY_FIELD_NAME];
$valueField = $mapFieldsByName[self::MAP_VALUE_FIELD_NAME];
$arr = [];
foreach ($v as $k => $vv) {
$arr[$this->decodeElement($keyField, $k)] = $this->decodeElement($valueField, $vv);
}
$value = $arr;
} elseif ($field->getLabel() === GPBLabel::REPEATED) {
$arr = [];
foreach ($v as $k => $vv) {
$arr[$k] = $this->decodeElement($field, $vv);
}
$value = $arr;
} else {
$value = $this->decodeElement($field, $v);
}
$setter = $this->getSetter($field->getName());
$message->{$setter}($value);
// We must unset $value here, otherwise the protobuf c extension will mix up the references
// and setting one value will change all others
unset($value);
}
return $message;
}
/**
* @param string $name
* @return string Getter function
*/
public static function getGetter(string $name)
{
return 'get' . \ucfirst(self::toCamelCase($name));
}
/**
* @param string $name
* @return string Setter function
*/
public static function getSetter(string $name)
{
return 'set' . \ucfirst(self::toCamelCase($name));
}
/**
* Convert string from camelCase to snake_case
*
* @param string $key
* @return string
*/
public static function toSnakeCase(string $key)
{
return \strtolower(\preg_replace(['/([a-z\\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $key));
}
/**
* Convert string from snake_case to camelCase
*
* @param string $key
* @return string
*/
public static function toCamelCase(string $key)
{
return \lcfirst(\str_replace(' ', '', \ucwords(\str_replace('_', ' ', $key))));
}
private static function hasBinaryHeaderSuffix(string $key)
{
return \substr_compare($key, "-bin", \strlen($key) - 4) === 0;
}
private static function getPhpArraySerializer()
{
if (\is_null(self::$phpArraySerializer)) {
self::$phpArraySerializer = new Serializer();
}
return self::$phpArraySerializer;
}
public static function loadKnownMetadataTypes()
{
foreach (self::$metadataKnownTypes as $key => $class) {
new $class();
}
}
}
// It is necessary to call this when this file is included. Otherwise we cannot be
// guaranteed that the relevant classes will be loaded into the protobuf descriptor
// pool when we try to unpack an Any object containing that class.
// phpcs:disable PSR1.Files.SideEffects
Serializer::loadKnownMetadataTypes();
// phpcs:enable

View File

@@ -0,0 +1,93 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code;
/**
* ServerStream is the response object from a server streaming API call.
*/
class ServerStream
{
private $call;
private $resourcesGetMethod;
/**
* ServerStream constructor.
*
* @param ServerStreamingCallInterface $serverStreamingCall The server streaming call object
* @param array $streamingDescriptor
*/
public function __construct($serverStreamingCall, array $streamingDescriptor = [])
{
$this->call = $serverStreamingCall;
if (\array_key_exists('resourcesGetMethod', $streamingDescriptor)) {
$this->resourcesGetMethod = $streamingDescriptor['resourcesGetMethod'];
}
}
/**
* A generator which yields results from the server until the streaming call
* completes. Throws an ApiException if the streaming call failed.
*
* @throws ApiException
* @return \Generator|mixed
*/
public function readAll()
{
$resourcesGetMethod = $this->resourcesGetMethod;
if (!\is_null($resourcesGetMethod)) {
foreach ($this->call->responses() as $response) {
foreach ($response->{$resourcesGetMethod}() as $resource) {
(yield $resource);
}
}
} else {
foreach ($this->call->responses() as $response) {
(yield $response);
}
}
// Errors in the REST transport will be thrown from there and not reach
// this handling. Successful REST server-streams will have an OK status.
$status = $this->call->getStatus();
if ($status->code !== Code::OK) {
throw ApiException::createFromStdClass($status);
}
}
/**
* Return the underlying call object.
*
* @return ServerStreamingCallInterface
*/
public function getServerStreamingCall()
{
return $this->call;
}
}

View File

@@ -0,0 +1,87 @@
<?php
/*
* Copyright 2021 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* @internal
*/
interface ServerStreamingCallInterface
{
/**
* Start the call.
*
* @param mixed $data The data to send
* @param array<mixed> $metadata Metadata to send with the call, if applicable
* (optional)
* @param array<mixed> $options An array of options, possible keys:
* 'flags' => a number (optional)
* @return void
*/
public function start($data, array $metadata = [], array $options = []);
/**
* @return mixed An iterator of response values.
*/
public function responses();
/**
* Return the status of the server stream.
*
* @return \stdClass The API status.
*/
public function getStatus();
/**
* @return mixed The metadata sent by the server.
*/
public function getMetadata();
/**
* @return mixed The trailing metadata sent by the server.
*/
public function getTrailingMetadata();
/**
* @return string The URI of the endpoint.
*/
public function getPeer();
/**
* Cancels the call.
*
* @return void
*/
public function cancel();
/**
* Set the CallCredentials for the underlying Call.
*
* @param mixed $call_credentials The CallCredentials object
*
* @return void
*/
public function setCallCredentials($call_credentials);
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* Provides helper methods for service address handling.
*
* @deprecated
* @todo (dwsupplee) serviceAddress is deprecated now in favor of
* apiEndpoint. Rename the trait/method in our next major release.
*/
trait ServiceAddressTrait
{
private static $defaultPort = 443;
/**
* @param string $apiEndpoint
* @return array
* @throws ValidationException
*/
private static function normalizeServiceAddress(string $apiEndpoint)
{
$components = \explode(':', $apiEndpoint);
if (\count($components) == 2) {
// Port is included in service address
return [$components[0], $components[1]];
} elseif (\count($components) == 1) {
// Port is not included - append default port
return [$components[0], self::$defaultPort];
} else {
throw new ValidationException("Invalid apiEndpoint: {$apiEndpoint}");
}
}
}

View File

@@ -0,0 +1,84 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\AbstractCall;
/**
* Class ForwardingCall wraps a \Grpc\AbstractCall.
*
* @experimental
*/
abstract class ForwardingCall
{
/**
* @var AbstractCall|ForwardingCall
*/
protected object $innerCall;
/**
* ForwardingCall constructor.
*
* @param AbstractCall|ForwardingCall $innerCall
*/
public function __construct($innerCall)
{
$this->innerCall = $innerCall;
}
/**
* @return mixed The metadata sent by the server
*/
public function getMetadata()
{
return $this->innerCall->getMetadata();
}
/**
* @return mixed The trailing metadata sent by the server
*/
public function getTrailingMetadata()
{
return $this->innerCall->getTrailingMetadata();
}
/**
* @return string The URI of the endpoint
*/
public function getPeer()
{
return $this->innerCall->getPeer();
}
/**
* Cancels the call.
*/
public function cancel()
{
$this->innerCall->cancel();
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*
* Copyright 2020 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\ServerStreamingCall;
/**
* Class ForwardingServerStreamingCall wraps a \Grpc\ServerStreamingCall.
*
* @experimental
*/
class ForwardingServerStreamingCall extends ForwardingCall
{
/** @var ServerStreamingCall */
protected object $innerCall;
/**
* @return mixed An iterator of response values
*/
public function responses()
{
return $this->innerCall->responses();
}
/**
* Wait for the server to send the status, and return it.
*
* @return \stdClass The status object, with integer $code, string
* $details, and array $metadata members
*/
public function getStatus()
{
return $this->innerCall->getStatus();
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\UnaryCall;
/**
* Class ForwardingUnaryCall wraps a \Grpc\UnaryCall.
*
* @experimental
*/
class ForwardingUnaryCall extends ForwardingCall
{
/** @var UnaryCall */
protected object $innerCall;
/**
* Wait for the server to respond with data and a status.
*
* @return array [response data, status]
*/
public function wait()
{
return $this->innerCall->wait();
}
}

View File

@@ -0,0 +1,113 @@
<?php
/*
* Copyright 2021 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServerStreamingCallInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\Gcp\GCPServerStreamCall;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\ServerStreamingCall;
/**
* Class ServerStreamingCallWrapper implements \Google\ApiCore\ServerStreamingCallInterface.
* This is essentially a wrapper class around the \Grpc\ServerStreamingCall.
*/
class ServerStreamingCallWrapper implements ServerStreamingCallInterface
{
/**
* @var ServerStreamingCall|GCPServerStreamCall
*/
private object $stream;
/**
* @param ServerStreamingCall|GCPServerStreamCall $stream
*/
public function __construct($stream)
{
$this->stream = $stream;
}
/**
* {@inheritdoc}
*/
public function start($data, array $metadata = [], array $callOptions = [])
{
$this->stream->start($data, $metadata, $callOptions);
}
/**
* {@inheritdoc}
*/
public function responses()
{
foreach ($this->stream->responses() as $response) {
(yield $response);
}
}
/**
* {@inheritdoc}
*/
public function getStatus()
{
return $this->stream->getStatus();
}
/**
* {@inheritdoc}
*/
public function getMetadata()
{
return $this->stream->getMetadata();
}
/**
* {@inheritdoc}
*/
public function getTrailingMetadata()
{
return $this->stream->getTrailingMetadata();
}
/**
* {@inheritdoc}
*/
public function getPeer()
{
return $this->stream->getPeer();
}
/**
* {@inheritdoc}
*/
public function cancel()
{
$this->stream->cancel();
}
/**
* {@inheritdoc}
*/
public function setCallCredentials($call_credentials)
{
$this->stream->setCallCredentials($call_credentials);
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc;
/**
* Temporary class to support an interceptor-like interface until gRPC interceptor support is
* available.
*
* @experimental
* @deprecated Deprecated in favor of implementations extending {@see \Grpc\Interceptor}.
*/
interface UnaryInterceptorInterface
{
/**
* @param string $method
* @param \Google\Protobuf\Internal\Message $argument
* @param callable $deserialize
* @param array $metadata
* @param array $options
* @param callable $continuation
* @return mixed
*/
public function interceptUnaryUnary($method, $argument, $deserialize, array $metadata, array $options, callable $continuation);
}

View File

@@ -0,0 +1,179 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiStatus;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServiceAddressTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Status;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Exception\RequestException;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Request;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\RequestInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\ResponseInterface;
/**
* A transport that sends protobuf over HTTP 1.1 that can be used when full gRPC support
* is not available.
*/
class GrpcFallbackTransport implements TransportInterface
{
use ValidationTrait;
use ServiceAddressTrait;
use HttpUnaryTransportTrait;
private string $baseUri;
/**
* @param string $baseUri
* @param callable $httpHandler A handler used to deliver PSR-7 requests.
*/
public function __construct(string $baseUri, callable $httpHandler)
{
$this->baseUri = $baseUri;
$this->httpHandler = $httpHandler;
$this->transportName = 'grpc-fallback';
}
/**
* Builds a GrpcFallbackTransport.
*
* @param string $apiEndpoint
* The address of the API remote host, for example "example.googleapis.com".
* @param array $config {
* Config options used to construct the grpc-fallback transport.
*
* @type callable $httpHandler A handler used to deliver PSR-7 requests.
* }
* @return GrpcFallbackTransport
* @throws ValidationException
*/
public static function build(string $apiEndpoint, array $config = [])
{
$config += ['httpHandler' => null, 'clientCertSource' => null];
list($baseUri, $port) = self::normalizeServiceAddress($apiEndpoint);
$httpHandler = $config['httpHandler'] ?: self::buildHttpHandlerAsync();
$transport = new GrpcFallbackTransport("{$baseUri}:{$port}", $httpHandler);
if ($config['clientCertSource']) {
$transport->configureMtlsChannel($config['clientCertSource']);
}
return $transport;
}
/**
* {@inheritdoc}
*/
public function startUnaryCall(Call $call, array $options)
{
$httpHandler = $this->httpHandler;
return $httpHandler($this->buildRequest($call, $options), $this->getCallOptions($options))->then(function (ResponseInterface $response) use($options) {
if (isset($options['metadataCallback'])) {
$metadataCallback = $options['metadataCallback'];
$metadataCallback($response->getHeaders());
}
return $response;
})->then(function (ResponseInterface $response) use($call) {
return $this->unpackResponse($call, $response);
}, function (\Exception $ex) {
throw $this->transformException($ex);
});
}
/**
* @param Call $call
* @param array $options
* @return RequestInterface
*/
private function buildRequest(Call $call, array $options)
{
// Build common headers and set the content type to 'application/x-protobuf'
$headers = ['Content-Type' => 'application/x-protobuf'] + self::buildCommonHeaders($options);
// It is necessary to supply 'grpc-web' in the 'x-goog-api-client' header
// when using the grpc-fallback protocol.
$headers += ['x-goog-api-client' => []];
$headers['x-goog-api-client'][] = 'grpc-web';
// Uri format: https://<service>/$rpc/<method>
$uri = "https://{$this->baseUri}/\$rpc/{$call->getMethod()}";
return new Request('POST', $uri, $headers, $call->getMessage()->serializeToString());
}
/**
* @param Call $call
* @param ResponseInterface $response
* @return Message
*/
private function unpackResponse(Call $call, ResponseInterface $response)
{
$decodeType = $call->getDecodeType();
/** @var Message $responseMessage */
$responseMessage = new $decodeType();
$responseMessage->mergeFromString((string) $response->getBody());
return $responseMessage;
}
/**
* @param array $options
* @return array
*/
private function getCallOptions(array $options)
{
$callOptions = $options['transportOptions']['grpcFallbackOptions'] ?? [];
if (isset($options['timeoutMillis'])) {
$callOptions['timeout'] = $options['timeoutMillis'] / 1000;
}
if ($this->clientCertSource) {
list($cert, $key) = self::loadClientCertSource($this->clientCertSource);
$callOptions['cert'] = $cert;
$callOptions['key'] = $key;
}
return $callOptions;
}
/**
* @param \Exception $ex
* @return \Exception
*/
private function transformException(\Exception $ex)
{
if ($ex instanceof RequestException && $ex->hasResponse()) {
$res = $ex->getResponse();
$body = (string) $res->getBody();
$status = new Status();
try {
$status->mergeFromString($body);
return ApiException::createFromRpcStatus($status);
} catch (\Exception $parseException) {
// We were unable to parse the response body into a $status object. Instead,
// create an ApiException using the unparsed $body as message.
$code = ApiStatus::rpcCodeFromHttpStatusCode($res->getStatusCode());
return ApiException::createFromApiResponse($body, $code, null, $parseException);
}
} else {
return $ex;
}
}
}

View File

@@ -0,0 +1,212 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport;
use Exception;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\BidiStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ClientStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\GrpcSupportTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServerStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServiceAddressTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc\ServerStreamingCallWrapper;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Grpc\UnaryInterceptorInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\BaseStub;
use Grpc\Channel;
use Grpc\ChannelCredentials;
use DeliciousBrains\WP_Offload_Media\Gcp\Grpc\Interceptor;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\Promise;
/**
* A gRPC based transport implementation.
*/
class GrpcTransport extends BaseStub implements TransportInterface
{
use ValidationTrait;
use GrpcSupportTrait;
use ServiceAddressTrait;
/**
* @param string $hostname
* @param array $opts
* - 'update_metadata': (optional) a callback function which takes in a
* metadata array, and returns an updated metadata array
* - 'grpc.primary_user_agent': (optional) a user-agent string
* @param Channel $channel An already created Channel object (optional)
* @param Interceptor[]|UnaryInterceptorInterface[] $interceptors *EXPERIMENTAL*
* Interceptors used to intercept RPC invocations before a call starts.
* Please note that implementations of
* {@see \Google\ApiCore\Transport\Grpc\UnaryInterceptorInterface} are
* considered deprecated and support will be removed in a future
* release. To prepare for this, please take the time to convert
* `UnaryInterceptorInterface` implementations over to a class which
* extends {@see Grpc\Interceptor}.
* @throws Exception
*/
public function __construct(string $hostname, array $opts, Channel $channel = null, array $interceptors = [])
{
if ($interceptors) {
$channel = Interceptor::intercept($channel ?: new Channel($hostname, $opts), $interceptors);
}
parent::__construct($hostname, $opts, $channel);
}
/**
* Builds a GrpcTransport.
*
* @param string $apiEndpoint
* The address of the API remote host, for example "example.googleapis.com. May also
* include the port, for example "example.googleapis.com:443"
* @param array $config {
* Config options used to construct the gRPC transport.
*
* @type array $stubOpts Options used to construct the gRPC stub (see
* {@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}).
* @type Channel $channel Grpc channel to be used.
* @type Interceptor[]|UnaryInterceptorInterface[] $interceptors *EXPERIMENTAL*
* Interceptors used to intercept RPC invocations before a call starts.
* Please note that implementations of
* {@see \Google\ApiCore\Transport\Grpc\UnaryInterceptorInterface} are
* considered deprecated and support will be removed in a future
* release. To prepare for this, please take the time to convert
* `UnaryInterceptorInterface` implementations over to a class which
* extends {@see Grpc\Interceptor}.
* @type callable $clientCertSource A callable which returns the client cert as a string.
* }
* @return GrpcTransport
* @throws ValidationException
*/
public static function build(string $apiEndpoint, array $config = [])
{
self::validateGrpcSupport();
$config += ['stubOpts' => [], 'channel' => null, 'interceptors' => [], 'clientCertSource' => null];
list($addr, $port) = self::normalizeServiceAddress($apiEndpoint);
$host = "{$addr}:{$port}";
$stubOpts = $config['stubOpts'];
// Set the required 'credentials' key in stubOpts if it is not already set. Use
// array_key_exists because null is a valid value.
if (!\array_key_exists('credentials', $stubOpts)) {
if (isset($config['clientCertSource'])) {
list($cert, $key) = self::loadClientCertSource($config['clientCertSource']);
$stubOpts['credentials'] = ChannelCredentials::createSsl(null, $key, $cert);
} else {
$stubOpts['credentials'] = ChannelCredentials::createSsl();
}
}
$channel = $config['channel'];
if (!\is_null($channel) && !$channel instanceof Channel) {
throw new ValidationException("Channel argument to GrpcTransport must be of type \\Grpc\\Channel, " . "instead got: " . \print_r($channel, \true));
}
try {
return new GrpcTransport($host, $stubOpts, $channel, $config['interceptors']);
} catch (Exception $ex) {
throw new ValidationException("Failed to build GrpcTransport: " . $ex->getMessage(), $ex->getCode(), $ex);
}
}
/**
* {@inheritdoc}
*/
public function startBidiStreamingCall(Call $call, array $options)
{
$this->verifyUniverseDomain($options);
return new BidiStream($this->_bidiRequest('/' . $call->getMethod(), [$call->getDecodeType(), 'decode'], isset($options['headers']) ? $options['headers'] : [], $this->getCallOptions($options)), $call->getDescriptor());
}
/**
* {@inheritdoc}
*/
public function startClientStreamingCall(Call $call, array $options)
{
$this->verifyUniverseDomain($options);
return new ClientStream($this->_clientStreamRequest('/' . $call->getMethod(), [$call->getDecodeType(), 'decode'], isset($options['headers']) ? $options['headers'] : [], $this->getCallOptions($options)), $call->getDescriptor());
}
/**
* {@inheritdoc}
*/
public function startServerStreamingCall(Call $call, array $options)
{
$this->verifyUniverseDomain($options);
$message = $call->getMessage();
if (!$message) {
throw new \InvalidArgumentException('A message is required for ServerStreaming calls.');
}
// This simultaenously creates and starts a \Grpc\ServerStreamingCall.
$stream = $this->_serverStreamRequest('/' . $call->getMethod(), $message, [$call->getDecodeType(), 'decode'], isset($options['headers']) ? $options['headers'] : [], $this->getCallOptions($options));
return new ServerStream(new ServerStreamingCallWrapper($stream), $call->getDescriptor());
}
/**
* {@inheritdoc}
*/
public function startUnaryCall(Call $call, array $options)
{
$this->verifyUniverseDomain($options);
$unaryCall = $this->_simpleRequest('/' . $call->getMethod(), $call->getMessage(), [$call->getDecodeType(), 'decode'], isset($options['headers']) ? $options['headers'] : [], $this->getCallOptions($options));
/** @var Promise $promise */
$promise = new Promise(function () use($unaryCall, $options, &$promise) {
list($response, $status) = $unaryCall->wait();
if ($status->code == Code::OK) {
if (isset($options['metadataCallback'])) {
$metadataCallback = $options['metadataCallback'];
$metadataCallback($unaryCall->getMetadata());
}
$promise->resolve($response);
} else {
throw ApiException::createFromStdClass($status);
}
}, [$unaryCall, 'cancel']);
return $promise;
}
private function verifyUniverseDomain(array $options)
{
if (isset($options['credentialsWrapper'])) {
$options['credentialsWrapper']->checkUniverseDomain();
}
}
private function getCallOptions(array $options)
{
$callOptions = $options['transportOptions']['grpcOptions'] ?? [];
if (isset($options['credentialsWrapper'])) {
$audience = $options['audience'] ?? null;
$credentialsWrapper = $options['credentialsWrapper'];
$callOptions['call_credentials_callback'] = $credentialsWrapper->getAuthorizationHeaderCallback($audience);
}
if (isset($options['timeoutMillis'])) {
$callOptions['timeout'] = $options['timeoutMillis'] * 1000;
}
return $callOptions;
}
private static function loadClientCertSource(callable $clientCertSource)
{
return \call_user_func($clientCertSource);
}
}

View File

@@ -0,0 +1,150 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport;
use Exception;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Auth\HttpHandler\HttpHandlerFactory;
/**
* A trait for shared functionality between transports that support only unary RPCs using simple
* HTTP requests.
*
* @internal
*/
trait HttpUnaryTransportTrait
{
private $httpHandler;
private $transportName;
private $clientCertSource;
/**
* {@inheritdoc}
* @return never
* @throws \BadMethodCallException
*/
public function startClientStreamingCall(Call $call, array $options)
{
$this->throwUnsupportedException();
}
/**
* {@inheritdoc}
* @return never
* @throws \BadMethodCallException
*/
public function startServerStreamingCall(Call $call, array $options)
{
$this->throwUnsupportedException();
}
/**
* {@inheritdoc}
* @return never
* @throws \BadMethodCallException
*/
public function startBidiStreamingCall(Call $call, array $options)
{
$this->throwUnsupportedException();
}
/**
* {@inheritdoc}
*/
public function close()
{
// Nothing to do.
}
/**
* @param array $options
* @return array
*/
private static function buildCommonHeaders(array $options)
{
$headers = $options['headers'] ?? [];
if (!\is_array($headers)) {
throw new \InvalidArgumentException('The "headers" option must be an array');
}
// If not already set, add an auth header to the request
if (!isset($headers['Authorization']) && isset($options['credentialsWrapper'])) {
$credentialsWrapper = $options['credentialsWrapper'];
$audience = $options['audience'] ?? null;
$callback = $credentialsWrapper->getAuthorizationHeaderCallback($audience);
// Prevent unexpected behavior, as the authorization header callback
// uses lowercase "authorization"
unset($headers['authorization']);
// Mitigate scenario where InsecureCredentialsWrapper returns null.
$authHeaders = empty($callback) ? [] : $callback();
if (!\is_array($authHeaders)) {
throw new \UnexpectedValueException('Expected array response from authorization header callback');
}
$headers += $authHeaders;
}
return $headers;
}
/**
* @return callable
* @throws ValidationException
*/
private static function buildHttpHandlerAsync()
{
try {
return [HttpHandlerFactory::build(), 'async'];
} catch (Exception $ex) {
throw new ValidationException("Failed to build HttpHandler", $ex->getCode(), $ex);
}
}
/**
* Set the path to a client certificate.
*
* @param callable $clientCertSource
*/
private function configureMtlsChannel(callable $clientCertSource)
{
$this->clientCertSource = $clientCertSource;
}
/**
* @return never
* @throws \BadMethodCallException
*/
private function throwUnsupportedException()
{
throw new \BadMethodCallException("Streaming calls are not supported while using the {$this->transportName} transport.");
}
private static function loadClientCertSource(callable $clientCertSource)
{
$certFile = \tempnam(\sys_get_temp_dir(), 'cert');
$keyFile = \tempnam(\sys_get_temp_dir(), 'key');
list($cert, $key) = \call_user_func($clientCertSource);
\file_put_contents($certFile, $cert);
\file_put_contents($keyFile, $key);
// the key and the cert are returned in one temporary file
return [$certFile, $keyFile];
}
}

View File

@@ -0,0 +1,215 @@
<?php
/*
* Copyright 2021 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Rest;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\StreamInterface;
use RuntimeException;
class JsonStreamDecoder
{
const ESCAPE_CHAR = '\\';
private StreamInterface $stream;
private bool $closeCalled = \false;
private string $decodeType;
private bool $ignoreUnknown = \true;
private int $readChunkSize = 1024;
/**
* JsonStreamDecoder is a HTTP-JSON response stream decoder for JSON-ecoded
* protobuf messages. The response stream must be a JSON array, where the first
* byte is the opening of the array (i.e. '['), and the last byte is the closing
* of the array (i.e. ']'). Each array item must be a JSON object and comma
* separated.
*
* @param StreamInterface $stream The stream to decode.
* @param string $decodeType The type name of response messages to decode.
* @param array<mixed> $options {
* An array of optional arguments.
*
* @type bool $ignoreUnknown
* Toggles whether or not to throw an exception when an unknown field
* is encountered in a response message. The default is true.
* @type int $readChunkSizeBytes
* The upper size limit in bytes that can be read at a time from the
* response stream. The default is 1 KB.
* }
*
* @experimental
*/
public function __construct(StreamInterface $stream, string $decodeType, array $options = [])
{
$this->stream = $stream;
$this->decodeType = $decodeType;
if (isset($options['ignoreUnknown'])) {
$this->ignoreUnknown = $options['ignoreUnknown'];
}
if (isset($options['readChunkSize'])) {
$this->readChunkSize = $options['readChunkSizeBytes'];
}
}
/**
* Begins decoding the configured response stream. It is a generator which
* yields messages of the given decode type from the stream until the stream
* completes. Throws an Exception if the stream is closed before the closing
* byte is read or if it encounters an error while decoding a message.
*
* @throws RuntimeException
* @return \Generator
*/
public function decode()
{
try {
foreach ($this->_decode() as $response) {
(yield $response);
}
} catch (RuntimeException $re) {
$msg = $re->getMessage();
$streamClosedException = \strpos($msg, 'Stream is detached') !== \false || \strpos($msg, 'Unexpected stream close') !== \false;
// Only throw the exception if close() was not called and it was not
// a closing-related exception.
if (!$this->closeCalled || !$streamClosedException) {
throw $re;
}
}
}
/**
* @return \Generator
*/
private function _decode()
{
$decodeType = $this->decodeType;
$str = \false;
$prev = $chunk = '';
$start = $end = $cursor = $level = 0;
while ($chunk !== '' || !$this->stream->eof()) {
// Read up to $readChunkSize bytes from the stream.
$chunk .= $this->stream->read($this->readChunkSize);
// If the response stream has been closed and the only byte
// remaining is the closing array bracket, we are done.
if ($this->stream->eof() && $chunk === ']') {
$level--;
break;
}
// Parse the freshly read data available in $chunk.
$chunkLength = \strlen($chunk);
while ($cursor < $chunkLength) {
// Access the next byte for processing.
$b = $chunk[$cursor];
// Track open/close double quotes of a key or value. Do not
// toggle flag with the pervious byte was an escape character.
if ($b === '"' && $prev !== self::ESCAPE_CHAR) {
$str = !$str;
}
// Skip over new lines that break up items.
if ($b === "\n" && $level === 1) {
$start++;
}
// Ignore commas separating messages in the stream array.
if ($b === ',' && $level === 1) {
$start++;
}
// Track the opening of a new array or object if not in a string
// value.
if (($b === '{' || $b === '[') && !$str) {
$level++;
// Opening of the array/root object.
// Do not include it in the messageBuffer.
if ($level === 1) {
$start++;
}
}
// Track the closing of an object if not in a string value.
if ($b === '}' && !$str) {
$level--;
if ($level === 1) {
$end = $cursor + 1;
}
}
// Track the closing of an array if not in a string value.
if ($b === ']' && !$str) {
$level--;
// If we are seeing a closing square bracket at the
// response message level, e.g. {"foo], there is a problem.
if ($level === 1) {
throw new \RuntimeException('Received closing byte mid-message');
}
}
// A message-closing byte was just buffered. Decode the
// message with the decode type, clearing the messageBuffer,
// and yield it.
//
// TODO(noahdietz): Support google.protobuf.*Value messages that
// are encoded as primitives and separated by commas.
if ($end !== 0) {
$length = $end - $start;
/** @var \Google\Protobuf\Internal\Message $return */
$return = new $decodeType();
$return->mergeFromJsonString(\substr($chunk, $start, $length), $this->ignoreUnknown);
(yield $return);
// Dump the part of the chunk used for parsing the message
// and use the remaining for the next message.
$remaining = $chunkLength - $length;
$chunk = \substr($chunk, $end, $remaining);
// Reset all indices and exit chunk processing.
$start = 0;
$end = 0;
$cursor = 0;
break;
}
$cursor++;
// An escaped back slash should not escape the following character.
if ($b === self::ESCAPE_CHAR && $prev === self::ESCAPE_CHAR) {
$b = '';
}
$prev = $b;
}
// If after attempting to process the chunk, no progress was made and the
// stream is closed, we must break as the stream has closed prematurely.
if ($cursor === $chunkLength && $this->stream->eof()) {
break;
}
}
if ($level > 0) {
throw new \RuntimeException('Unexpected stream close before receiving the closing byte');
}
}
/**
* Closes the underlying stream. If the stream is actively being decoded, an
* exception will not be thrown due to the interruption.
*
* @return void
*/
public function close()
{
$this->closeCalled = \true;
$this->stream->close();
}
}

View File

@@ -0,0 +1,173 @@
<?php
/*
* Copyright 2021 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Rest;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiStatus;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServerStreamingCallInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Rpc\Code;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Exception\RequestException;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\RequestInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\ResponseInterface;
use stdClass;
/**
* Class RestServerStreamingCall implements \Google\ApiCore\ServerStreamingCallInterface.
*
* @experimental
*/
class RestServerStreamingCall implements ServerStreamingCallInterface
{
/** @var callable */
private $httpHandler;
/** @var array<mixed> */
private array $decoderOptions;
private RequestInterface $originalRequest;
private ?JsonStreamDecoder $decoder;
private string $decodeType;
private ?ResponseInterface $response;
private stdClass $status;
/**
* @param callable $httpHandler
* @param string $decodeType
* @param array<mixed> $decoderOptions
*/
public function __construct(callable $httpHandler, string $decodeType, array $decoderOptions)
{
$this->httpHandler = $httpHandler;
$this->decodeType = $decodeType;
$this->decoderOptions = $decoderOptions;
}
/**
* {@inheritdoc}
*/
public function start($request, array $headers = [], array $callOptions = [])
{
$this->originalRequest = $this->appendHeaders($request, $headers);
try {
$handler = $this->httpHandler;
$response = $handler($this->originalRequest, $callOptions)->wait();
} catch (\Exception $ex) {
if ($ex instanceof RequestException && $ex->hasResponse()) {
$ex = ApiException::createFromRequestException(
$ex,
/* isStream */
\true
);
}
throw $ex;
}
// Create an OK Status for a successful request just so that it
// has a return value.
$this->status = new stdClass();
$this->status->code = Code::OK;
$this->status->message = ApiStatus::OK;
$this->status->details = [];
$this->response = $response;
}
/**
* @param RequestInterface $request
* @param array<mixed> $headers
* @return RequestInterface
*/
private function appendHeaders(RequestInterface $request, array $headers)
{
foreach ($headers as $key => $value) {
$request = $request->hasHeader($key) ? $request->withAddedHeader($key, $value) : $request->withHeader($key, $value);
}
return $request;
}
/**
* {@inheritdoc}
*/
public function responses()
{
if (\is_null($this->response)) {
throw new \Exception('Stream has not been started.');
}
// Decode the stream and yield responses as they are read.
$this->decoder = new JsonStreamDecoder($this->response->getBody(), $this->decodeType, $this->decoderOptions);
foreach ($this->decoder->decode() as $message) {
(yield $message);
}
}
/**
* Return the status of the server stream. If the call has not been started
* this will be null.
*
* @return stdClass The status, with integer $code, string
* $details, and array $metadata members
*/
public function getStatus()
{
return $this->status;
}
/**
* {@inheritdoc}
*/
public function getMetadata()
{
return \is_null($this->response) ? null : $this->response->getHeaders();
}
/**
* The Rest transport does not support trailing metadata. This is a
* passthrough to getMetadata().
*/
public function getTrailingMetadata()
{
return $this->getMetadata();
}
/**
* {@inheritdoc}
*/
public function getPeer()
{
return $this->originalRequest->getUri();
}
/**
* {@inheritdoc}
*/
public function cancel()
{
if (!\is_null($this->decoder)) {
$this->decoder->close();
}
}
/**
* For the REST transport this is a no-op.
* {@inheritdoc}
*/
public function setCallCredentials($call_credentials)
{
// Do nothing.
}
}

View File

@@ -0,0 +1,200 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport;
use BadMethodCallException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ApiException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\RequestBuilder;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServerStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServiceAddressTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport\Rest\RestServerStreamingCall;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationTrait;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\Protobuf\Internal\Message;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Exception\RequestException;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\RequestInterface;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\ResponseInterface;
/**
* A REST based transport implementation.
*/
class RestTransport implements TransportInterface
{
use ValidationTrait;
use ServiceAddressTrait;
use HttpUnaryTransportTrait {
startServerStreamingCall as protected unsupportedServerStreamingCall;
}
private RequestBuilder $requestBuilder;
/**
* @param RequestBuilder $requestBuilder A builder responsible for creating
* a PSR-7 request from a set of request information.
* @param callable $httpHandler A handler used to deliver PSR-7 requests.
*/
public function __construct(RequestBuilder $requestBuilder, callable $httpHandler)
{
$this->requestBuilder = $requestBuilder;
$this->httpHandler = $httpHandler;
$this->transportName = 'REST';
}
/**
* Builds a RestTransport.
*
* @param string $apiEndpoint
* The address of the API remote host, for example "example.googleapis.com".
* @param string $restConfigPath
* Path to rest config file.
* @param array<mixed> $config {
* Config options used to construct the gRPC transport.
*
* @type callable $httpHandler A handler used to deliver PSR-7 requests.
* @type callable $clientCertSource A callable which returns the client cert as a string.
* }
* @return RestTransport
* @throws ValidationException
*/
public static function build(string $apiEndpoint, string $restConfigPath, array $config = [])
{
$config += ['httpHandler' => null, 'clientCertSource' => null];
list($baseUri, $port) = self::normalizeServiceAddress($apiEndpoint);
$requestBuilder = new RequestBuilder("{$baseUri}:{$port}", $restConfigPath);
$httpHandler = $config['httpHandler'] ?: self::buildHttpHandlerAsync();
$transport = new RestTransport($requestBuilder, $httpHandler);
if ($config['clientCertSource']) {
$transport->configureMtlsChannel($config['clientCertSource']);
}
return $transport;
}
/**
* {@inheritdoc}
*/
public function startUnaryCall(Call $call, array $options)
{
$headers = self::buildCommonHeaders($options);
// call the HTTP handler
$httpHandler = $this->httpHandler;
return $httpHandler($this->requestBuilder->build($call->getMethod(), $call->getMessage(), $headers), $this->getCallOptions($options))->then(function (ResponseInterface $response) use($call, $options) {
$decodeType = $call->getDecodeType();
/** @var Message $return */
$return = new $decodeType();
$body = (string) $response->getBody();
// In some rare cases LRO response metadata may not be loaded
// in the descriptor pool, triggering an exception. The catch
// statement handles this case and attempts to add the LRO
// metadata type to the pool by directly instantiating the
// metadata class.
try {
$return->mergeFromJsonString($body, \true);
} catch (\Exception $ex) {
if (!isset($options['metadataReturnType'])) {
throw $ex;
}
if (\strpos($ex->getMessage(), 'Error occurred during parsing:') !== 0) {
throw $ex;
}
new $options['metadataReturnType']();
$return->mergeFromJsonString($body, \true);
}
if (isset($options['metadataCallback'])) {
$metadataCallback = $options['metadataCallback'];
$metadataCallback($response->getHeaders());
}
return $return;
}, function (\Throwable $ex) {
if ($ex instanceof RequestException && $ex->hasResponse()) {
throw ApiException::createFromRequestException($ex);
}
throw $ex;
});
}
/**
* {@inheritdoc}
* @throws \BadMethodCallException for forwards compatibility with older GAPIC clients
*/
public function startServerStreamingCall(Call $call, array $options)
{
$message = $call->getMessage();
if (!$message) {
throw new \InvalidArgumentException('A message is required for ServerStreaming calls.');
}
// Maintain forwards compatibility with older GAPIC clients not configured for REST server streaming
// @see https://github.com/googleapis/gax-php/issues/370
if (!$this->requestBuilder->pathExists($call->getMethod())) {
$this->unsupportedServerStreamingCall($call, $options);
}
$headers = self::buildCommonHeaders($options);
$callOptions = $this->getCallOptions($options);
$request = $this->requestBuilder->build($call->getMethod(), $call->getMessage());
$decoderOptions = [];
if (isset($options['decoderOptions'])) {
$decoderOptions = $options['decoderOptions'];
}
return new ServerStream($this->_serverStreamRequest($this->httpHandler, $request, $headers, $call->getDecodeType(), $callOptions, $decoderOptions), $call->getDescriptor());
}
/**
* Creates and starts a RestServerStreamingCall.
*
* @param callable $httpHandler The HTTP Handler to invoke the request with.
* @param RequestInterface $request The request to invoke.
* @param array<mixed> $headers The headers to include in the request.
* @param string $decodeType The response stream message type to decode.
* @param array<mixed> $callOptions The call options to use when making the call.
* @param array<mixed> $decoderOptions The options to use for the JsonStreamDecoder.
*
* @return RestServerStreamingCall
*/
private function _serverStreamRequest($httpHandler, $request, $headers, $decodeType, $callOptions, $decoderOptions = [])
{
$call = new RestServerStreamingCall($httpHandler, $decodeType, $decoderOptions);
$call->start($request, $headers, $callOptions);
return $call;
}
/**
* @param array<mixed> $options
*
* @return array<mixed>
*/
private function getCallOptions(array $options)
{
$callOptions = $options['transportOptions']['restOptions'] ?? [];
if (isset($options['timeoutMillis'])) {
$callOptions['timeout'] = $options['timeoutMillis'] / 1000;
}
if ($this->clientCertSource) {
list($cert, $key) = self::loadClientCertSource($this->clientCertSource);
$callOptions['cert'] = $cert;
$callOptions['key'] = $key;
}
return $callOptions;
}
}

View File

@@ -0,0 +1,86 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Transport;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\BidiStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\Call;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ClientStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ServerStream;
use DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore\ValidationException;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Promise\PromiseInterface;
interface TransportInterface
{
/**
* Starts a bidi streaming call.
*
* @param Call $call
* @param array<mixed> $options
*
* @return BidiStream
*/
public function startBidiStreamingCall(Call $call, array $options);
/**
* Starts a client streaming call.
*
* @param Call $call
* @param array<mixed> $options
*
* @return ClientStream
*/
public function startClientStreamingCall(Call $call, array $options);
/**
* Starts a server streaming call.
*
* @param Call $call
* @param array<mixed> $options
*
* @return ServerStream
*/
public function startServerStreamingCall(Call $call, array $options);
/**
* Returns a promise used to execute network requests.
*
* @param Call $call
* @param array<mixed> $options
*
* @return PromiseInterface
* @throws ValidationException
*/
public function startUnaryCall(Call $call, array $options);
/**
* Closes the connection, if one exists.
*
* @return void
*/
public function close();
}

63
vendor/Gcp/google/gax/src/UriTrait.php vendored Normal file
View File

@@ -0,0 +1,63 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Query;
use DeliciousBrains\WP_Offload_Media\Gcp\GuzzleHttp\Psr7\Utils;
use DeliciousBrains\WP_Offload_Media\Gcp\Psr\Http\Message\UriInterface;
/**
* Provides a light wrapper around often used URI related functions.
*
* @internal
*/
trait UriTrait
{
/**
* @param string|UriInterface $uri
* @param array $query
* @return UriInterface
*/
public function buildUriWithQuery($uri, array $query)
{
$query = \array_filter($query, function ($v) {
return $v !== null;
});
// Casts bools to their string representation
foreach ($query as $k => &$v) {
if (\is_bool($v)) {
$v = $v ? 'true' : 'false';
}
}
return Utils::uriFor($uri)->withQuery(Query::build($query));
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* Copyright 2016 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
use Exception;
/**
* ValidationException represents a local error (i.e. not during an RPC call).
*/
class ValidationException extends Exception
{
}

View File

@@ -0,0 +1,78 @@
<?php
/*
* Copyright 2017 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* @internal
*/
trait ValidationTrait
{
/**
* @param array $arr Associative array
* @param array $requiredKeys List of keys to check for in $arr
* @return array Returns $arr for fluent use
*/
public static function validate(array $arr, array $requiredKeys)
{
return self::validateImpl($arr, $requiredKeys, \true);
}
/**
* @param array $arr Associative array
* @param array $requiredKeys List of keys to check for in $arr
* @return array Returns $arr for fluent use
*/
public static function validateNotNull(array $arr, array $requiredKeys)
{
return self::validateImpl($arr, $requiredKeys, \false);
}
private static function validateImpl($arr, $requiredKeys, $allowNull)
{
foreach ($requiredKeys as $requiredKey) {
$valid = \array_key_exists($requiredKey, $arr) && ($allowNull || !\is_null($arr[$requiredKey]));
if (!$valid) {
throw new ValidationException("Missing required argument {$requiredKey}");
}
}
return $arr;
}
/**
* @param string $filePath
* @throws ValidationException
*/
private static function validateFileExists(string $filePath)
{
if (!\file_exists($filePath)) {
throw new ValidationException("Could not find specified file: {$filePath}");
}
}
}

73
vendor/Gcp/google/gax/src/Version.php vendored Normal file
View File

@@ -0,0 +1,73 @@
<?php
/*
* Copyright 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DeliciousBrains\WP_Offload_Media\Gcp\Google\ApiCore;
/**
* @internal
*/
class Version
{
/**
* @var ?string
*/
private static $version = null;
/**
* @return string The version of the ApiCore library.
*/
public static function getApiCoreVersion()
{
if (\is_null(self::$version)) {
$versionFile = \implode(\DIRECTORY_SEPARATOR, [__DIR__, '..', 'VERSION']);
self::$version = self::readVersionFile($versionFile);
}
return self::$version;
}
/**
* Reads a VERSION file and returns the contents. If the file does not
* exist, returns "".
*
* @param string $file
* @return string
*/
public static function readVersionFile(string $file)
{
$versionString = \file_exists($file) ? (string) \file_get_contents($file) : "";
return \trim($versionString);
}
/**
* Private constructor.
*/
private function __construct()
{
}
}