├── .github
├── release-please.yml
└── workflows
│ └── tests.yml
├── .gitmodules
├── .php_cs.dist
├── LICENSE
├── README.md
├── cloudprober
├── bins
│ └── opt
│ │ └── grpc_php_plugin
├── cloudprober.cfg
├── codegen.sh
├── composer.json
└── grpc_gpc_prober
│ ├── firestore_probes.php
│ ├── prober.php
│ ├── spanner_probes.php
│ └── stackdriver_util.php
├── composer.json
├── doc
└── gRPC-client-user-guide.md
└── src
├── ChannelRef.php
├── Config.php
├── CreatedByDeserializeCheck.php
├── GCPBidiStreamingCall.php
├── GCPCallInvoker.php
├── GCPClientStreamCall.php
├── GCPServerStreamCall.php
├── GCPUnaryCall.php
├── GcpBaseCall.php
├── GcpExtensionChannel.php
├── generated
├── GPBMetadata
│ └── GrpcGcp.php
└── Grpc
│ └── Gcp
│ ├── AffinityConfig.php
│ ├── AffinityConfig_Command.php
│ ├── ApiConfig.php
│ ├── ChannelPoolConfig.php
│ └── MethodConfig.php
└── grpc_gcp.proto
/.github/release-please.yml:
--------------------------------------------------------------------------------
1 | releaseType: simple
2 | handleGHRelease: true
3 | primaryBranch: main
4 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Test Suite
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | jobs:
8 | test:
9 | runs-on: ubuntu-latest
10 | strategy:
11 | matrix:
12 | php: [ "8.0", "8.1", "8.2", "8.3", "8.4" ]
13 | name: "PHP ${{ matrix.php }} Unit Test"
14 | steps:
15 | - uses: actions/checkout@v2
16 | - uses: codecov/codecov-action@v1
17 | - name: Setup PHP
18 | uses: shivammathur/setup-php@v2
19 | with:
20 | php-version: ${{ matrix.php }}
21 | tools: pecl
22 | extensions: grpc-1.49.0
23 | - name: Install composer dependencies
24 | uses: nick-invision/retry@v1
25 | with:
26 | timeout_minutes: 10
27 | max_attempts: 3
28 | command: composer install
29 | - name: Run PHPUnit
30 | run: vendor/bin/phpunit -v
31 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "third_party/googleapis"]
2 | path = third_party/googleapis
3 | url = https://github.com/googleapis/googleapis.git
4 |
--------------------------------------------------------------------------------
/.php_cs.dist:
--------------------------------------------------------------------------------
1 | setRules([
4 | '@PSR2' => true,
5 | 'concat_space' => ['spacing' => 'one'],
6 | 'no_unused_imports' => true,
7 | 'method_argument_space' => false,
8 | ])
9 | ->setFinder(
10 | PhpCsFixer\Finder::create()
11 | ->notPath('firestore')
12 | ->in(__DIR__)
13 | )
14 | ;
15 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gRPC for GCP extensions
2 |
3 | Copyright 2018
4 | [The gRPC Authors](https://github.com/grpc/grpc/blob/master/AUTHORS)
5 |
6 | ## About This Repository
7 |
8 | This repo is created to support GCP specific extensions for gRPC. To use the extension features, please refer to [src](src).
9 |
10 | This repo also contains supporting infrastructures such as end2end tests and benchmarks for accessing cloud APIs with gRPC client libraries.
11 |
12 | ## License
13 |
14 | Apache 2.0 - See [LICENSE](LICENSE) for more information.
15 |
--------------------------------------------------------------------------------
/cloudprober/bins/opt/grpc_php_plugin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleCloudPlatform/grpc-gcp-php/e585b7721bbe806ef45b5c52ae43dfc2bff89968/cloudprober/bins/opt/grpc_php_plugin
--------------------------------------------------------------------------------
/cloudprober/cloudprober.cfg:
--------------------------------------------------------------------------------
1 | probe {
2 | type: EXTERNAL
3 | name: "spanner"
4 | interval_msec: 1800000
5 | timeout_msec: 30000
6 | targets { dummy_targets {} } # No targets for external probe
7 | external_probe {
8 | mode: ONCE
9 | command: "php grpc_gpc_prober/prober.php --api=spanner"
10 | }
11 | }
12 |
13 | probe {
14 | type: EXTERNAL
15 | name: "firestore"
16 | interval_msec: 1800000
17 | timeout_msec: 30000
18 | targets { dummy_targets {} } # No targets for external probe
19 | external_probe {
20 | mode: ONCE
21 | command: "php grpc_gpc_prober/prober.php --api=firestore"
22 | }
23 | }
24 |
25 | surfacer {
26 | type: STACKDRIVER
27 | name: "stackdriver"
28 | stackdriver_surfacer {
29 | monitoring_url: "custom.googleapis.com/cloudprober/"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/cloudprober/codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd "$(dirname "$0")"
3 |
4 | rm -rf google
5 |
6 | for p in $(find ../third_party/googleapis/google -type f -name *.proto); do
7 | protoc \
8 | --proto_path=../third_party/googleapis \
9 | --php_out=./ \
10 | --grpc_out=./ \
11 | --plugin=protoc-gen-grpc="$(which grpc_php_plugin)" \
12 | "$p"
13 | done
14 |
--------------------------------------------------------------------------------
/cloudprober/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grpc_gcp_prober",
3 | "description": "grpc cloudprober for PHP",
4 | "require": {
5 | "grpc/grpc": "^v1.15.0",
6 | "google/auth": "^v1.4.0",
7 | "google/cloud": "^v0.86.0"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/cloudprober/grpc_gpc_prober/firestore_probes.php:
--------------------------------------------------------------------------------
1 | setParent($_PARENT_RESOURCE);
20 | $time_start = microtime_float();
21 |
22 | $client->ListDocuments($list_document_request);
23 |
24 | $lantency = (microtime_float()- $time_start) * 1000;
25 | $metrics['list_documents_latency_ms'] = $lantency;
26 |
27 | }
28 |
29 | $probFunctions = [
30 | 'documents' => 'document'
31 | ];
32 |
33 | return $probFunctions;
--------------------------------------------------------------------------------
/cloudprober/grpc_gpc_prober/prober.php:
--------------------------------------------------------------------------------
1 | AuthMetadataPlugin($credentials, $request);
28 | $ssl_credentials = Grpc\ChannelCredentials::createSsl();
29 | $composit_credentials = $grpc->composite_channel_credentials($ssl_credentials, $google_auth_credentials);
30 | return $grpc_gcp->secure_channel($target, $composit_credentials, $kwargs);
31 | }
32 |
33 | function getStubChannel($target){
34 | $res = $auth->default([$_OAUTH_SCOPE]);
35 | $cred = $res[0];
36 | return secureAuthorizedChannel($cred, Request(), $target);
37 | }*/
38 |
39 | function executeProbes($api){
40 | global $_OAUTH_SCOPE;
41 | global $_SPANNER_TARGET;
42 | global $_FIRESTORE_TARGET;
43 |
44 | global $spanner_probes;
45 | global $firestore_probes;
46 |
47 | $util = new StackdriverUtil($api);
48 | $auth = Google\Auth\ApplicationDefaultCredentials::getCredentials($_OAUTH_SCOPE);
49 | $opts = [
50 | 'credentials' => Grpc\ChannelCredentials::createSsl(),
51 | 'update_metadata' => $auth->getUpdateMetadataFunc(),
52 | ];
53 |
54 | if($api == 'spanner'){
55 | $client = new SpannerGrpcClient($_SPANNER_TARGET, $opts);
56 | $probe_functions = $spanner_probes;
57 | }
58 | else if($api == 'firestore'){
59 | $client = new FirestoreGrpcClient($_FIRESTORE_TARGET, $opts);
60 | $probe_functions = $firestore_probes;
61 | }
62 | else{
63 | echo 'grpc not implemented for '.$api;
64 | exit(1);
65 | }
66 |
67 | $total = sizeof($probe_functions);
68 | $success = 0;
69 | $metrics = [];
70 |
71 | # Execute all probes for given api
72 | foreach ($probe_functions as $probe_name => $probe_function) {
73 | try{
74 | $probe_function($client, $metrics);
75 | $success++;
76 | }
77 | catch(Exception $e){
78 | $util->reportError($e);
79 | }
80 |
81 | }
82 |
83 | if($success == $total){
84 | $util->setSuccess(True);
85 | }
86 |
87 | $util->addMetrics($metrics);
88 | $util->outputMetrics();
89 |
90 | if($success != $total){
91 | # TODO: exit system
92 | exit(1);
93 | }
94 |
95 | }
96 |
97 | function main(){
98 | $args = getArgs();
99 | executeProbes($args['api']);
100 | }
101 |
102 | main();
103 |
--------------------------------------------------------------------------------
/cloudprober/grpc_gpc_prober/spanner_probes.php:
--------------------------------------------------------------------------------
1 | code !== Grpc\STATUS_OK) {
18 | echo "Call did not complete successfully. Status object:\n";
19 | var_dump($status);
20 | exit(1);
21 | }
22 | }
23 |
24 | function microtime_float()
25 | {
26 | list($usec, $sec) = explode(" ", microtime());
27 | return ((float)$usec + (float)$sec);
28 | }
29 |
30 | /*
31 | Probes to test session related grpc call from Spanner stub.
32 |
33 | Includes tests against CreateSession, GetSession, ListSessions, and
34 | DeleteSession of Spanner stub.
35 |
36 | Args:
37 | stub: An object of SpannerStub.
38 | metrics: A list of metrics.
39 |
40 | */
41 |
42 | function sessionManagement($client, &$metrics){
43 | global $_DATABASE;
44 |
45 | $createSessionRequest = new Google\Cloud\Spanner\V1\CreateSessionRequest();
46 | $createSessionRequest->setDatabase($_DATABASE);
47 | #Create Session test
48 | #Create
49 | $time_start = microtime_float();
50 | list($session, $status) = $client->CreateSession($createSessionRequest)->wait();
51 |
52 | hardAssertIfStatusOk($status);
53 | hardAssert($session !== null, 'Call completed with a null response');
54 |
55 | $lantency = (microtime_float()- $time_start) * 1000;
56 | $metrics['create_session_latency_ms'] = $lantency;
57 |
58 | #Get Session
59 | $getSessionRequest = new Google\Cloud\Spanner\V1\GetSessionRequest();
60 | $getSessionRequest->setName($session->getName());
61 | $time_start = microtime_float();
62 | $response = $client->GetSession($getSessionRequest);
63 | $response->wait();
64 | $lantency = (microtime_float() - $time_start) * 1000;
65 | $metrics['get_session_latency_ms'] = $lantency;
66 |
67 | #List session
68 | $listSessionsRequest = new Google\Cloud\Spanner\V1\ListSessionsRequest();
69 | $listSessionsRequest->setDatabase($_DATABASE);
70 | $time_start = microtime_float();
71 | $response = $client->ListSessions($listSessionsRequest);
72 | $lantency = (microtime_float() - $time_start) * 1000;
73 | $metrics['list_sessions_latency_ms'] = $lantency;
74 |
75 | #Delete session
76 | $deleteSessionRequest = new Google\Cloud\Spanner\V1\DeleteSessionRequest();
77 | $deleteSessionRequest->setName($session->getName());
78 | $time_start = microtime_float();
79 | $client->deleteSession($deleteSessionRequest);
80 | $lantency = (microtime_float() - $time_start) * 1000;
81 | $metrics['delete_session_latency_ms'] = $lantency;
82 |
83 | }
84 |
85 | /*
86 | Probes to test ExecuteSql and ExecuteStreamingSql call from Spanner stub.
87 |
88 | Args:
89 | stub: An object of SpannerStub.
90 | metrics: A list of metrics.
91 |
92 | */
93 | function executeSql($client, &$metrics){
94 | global $_DATABASE;
95 |
96 | $createSessionRequest = new Google\Cloud\Spanner\V1\CreateSessionRequest();
97 | $createSessionRequest->setDatabase($_DATABASE);
98 | list($session, $status) = $client->CreateSession($createSessionRequest)->wait();
99 |
100 | hardAssertIfStatusOk($status);
101 | hardAssert($session !== null, 'Call completed with a null response');
102 |
103 | # Probing ExecuteSql call
104 | $time_start = microtime_float();
105 | $executeSqlRequest = new Google\Cloud\Spanner\V1\ExecuteSqlRequest();
106 | $executeSqlRequest->setSession($session->getName());
107 | $executeSqlRequest->setSql('select * FROM users');
108 | $result_set = $client->ExecuteSql($executeSqlRequest);
109 | $lantency = (microtime_float() - $time_start) * 1000;
110 | $metrics['execute_sql_latency_ms'] = $lantency;
111 |
112 | // TODO: Error check result_set
113 |
114 | # Probing ExecuteStreamingSql call
115 | $partial_result_set = $client->ExecuteStreamingSql($executeSqlRequest);
116 |
117 | $time_start = microtime_float();
118 | $first_result = array_values($partial_result_set->getMetadata())[0];
119 | $lantency = (microtime_float() - $time_start) * 1000;
120 | $metrics['execute_streaming_sql_latency_ms'] = $lantency;
121 |
122 | // TODO: Error Check for sreaming sql first result
123 |
124 | $deleteSessionRequest = new Google\Cloud\Spanner\V1\DeleteSessionRequest();
125 | $deleteSessionRequest->setName($session->getName());
126 | $client->deleteSession($deleteSessionRequest);
127 | }
128 |
129 | /*
130 | Probe to test Read and StreamingRead grpc call from Spanner stub.
131 |
132 | Args:
133 | stub: An object of SpannerStub.
134 | metrics: A list of metrics.
135 | */
136 |
137 | function read($client, &$metrics){
138 | global $_DATABASE;
139 |
140 | $createSessionRequest = new Google\Cloud\Spanner\V1\CreateSessionRequest();
141 | $createSessionRequest->setDatabase($_DATABASE);
142 | list($session, $status) = $client->CreateSession($createSessionRequest)->wait();
143 |
144 | hardAssertIfStatusOk($status);
145 | hardAssert($session !== null, 'Call completed with a null response');
146 |
147 | # Probing Read call
148 | $time_start = microtime_float();
149 | $readRequest = new Google\Cloud\Spanner\V1\ReadRequest();
150 | $readRequest->setSession($session->getName());
151 | $readRequest->setTable('users');
152 | $readRequest->setColumns(['username', 'firstname', 'lastname']);
153 | $keyset = new Google\Cloud\Spanner\V1\KeySet();
154 | $keyset->setAll(True);
155 | $readRequest->setKeySet($keyset);
156 | $result_set = $client->Read($readRequest);
157 | $lantency = (microtime_float() - $time_start) * 1000;
158 | $metrics['read_latency_ms'] = $lantency;
159 |
160 | // TODO: Error Check for result_set
161 |
162 | # Probing StreamingRead call
163 | $partial_result_set = $client->StreamingRead($readRequest);
164 | $time_start = microtime_float();
165 | $first_result = array_values($partial_result_set->getMetadata())[0];
166 | $lantency = (microtime_float() - $time_start) * 1000;
167 | $metrics['streaming_read_latency_ms'] = $lantency;
168 |
169 | //TODO: Error Check for streaming read first result
170 |
171 | $deleteSessionRequest = new Google\Cloud\Spanner\V1\DeleteSessionRequest();
172 | $deleteSessionRequest->setName($session->getName());
173 | $client->deleteSession($deleteSessionRequest);
174 | }
175 |
176 | /*
177 | Probe to test BeginTransaction, Commit and Rollback grpc from Spanner stub.
178 |
179 | Args:
180 | stub: An object of SpannerStub.
181 | metrics: A list of metrics.
182 | */
183 |
184 | function transaction($client, &$metrics){
185 | global $_DATABASE;
186 |
187 | $createSessionRequest = new Google\Cloud\Spanner\V1\CreateSessionRequest();
188 | $createSessionRequest->setDatabase($_DATABASE);
189 | list($session, $status) = $client->CreateSession($createSessionRequest)->wait();
190 |
191 | hardAssertIfStatusOk($status);
192 | hardAssert($session !== null, 'Call completed with a null response');
193 |
194 | $txn_options = new Google\Cloud\Spanner\V1\TransactionOptions();
195 | $rw = new Google\Cloud\Spanner\V1\TransactionOptions\ReadWrite();
196 | $txn_options->setReadWrite($rw);
197 | $txn_request = new Google\Cloud\Spanner\V1\BeginTransactionRequest();
198 | $txn_request->setSession($session->getName());
199 | $txn_request->setOptions($txn_options);
200 |
201 | # Probing BeginTransaction call
202 | $time_start = microtime_float();
203 | list($txn, $status) = $client->BeginTransaction($txn_request)->wait();
204 | $lantency = (microtime_float() - $time_start) * 1000;
205 | $metrics['begin_transaction_latency_ms'] = $lantency;
206 |
207 | hardAssertIfStatusOk($status);
208 | hardAssert($txn !== null, 'Call completed with a null response');
209 |
210 | # Probing Commit Call
211 | $commit_request = new Google\Cloud\Spanner\V1\CommitRequest();
212 | $commit_request->setSession($session->getName());
213 | $commit_request->setTransactionId($txn->getId());
214 |
215 | $time_start = microtime_float();
216 | $client->Commit($commit_request);
217 | $latency = (microtime_float() - $time_start) * 1000;
218 | $metrics['commit_latency_ms'] = $lantency;
219 |
220 | # Probing Rollback call
221 | list($txn, $status) = $client->BeginTransaction($txn_request)->wait();
222 | $rollback_request = new Google\Cloud\Spanner\V1\RollbackRequest();
223 | $rollback_request->setSession($session->getName());
224 | $rollback_request->setTransactionId($txn->getId());
225 |
226 | hardAssertIfStatusOk($status);
227 | hardAssert($txn !== null, 'Call completed with a null response');
228 |
229 | $time_start = microtime_float();
230 | $client->Rollback($rollback_request);
231 | $latency = (microtime_float() - $time_start) * 1000;
232 | $metrics['rollback_latency_ms'] = $latency;
233 |
234 | $deleteSessionRequest = new Google\Cloud\Spanner\V1\DeleteSessionRequest();
235 | $deleteSessionRequest->setName($session->getName());
236 | $client->deleteSession($deleteSessionRequest);
237 | }
238 |
239 | /*
240 | Probe to test PartitionQuery and PartitionRead grpc call from Spanner stub.
241 |
242 | Args:
243 | stub: An object of SpannerStub.
244 | metrics: A list of metrics.
245 | */
246 |
247 | function partition($client, &$metrics){
248 | global $_DATABASE;
249 | global $_TEST_USERNAME;
250 |
251 | $createSessionRequest = new Google\Cloud\Spanner\V1\CreateSessionRequest();
252 | $createSessionRequest->setDatabase($_DATABASE);
253 | list($session, $status) = $client->CreateSession($createSessionRequest)->wait();
254 |
255 | hardAssertIfStatusOk($status);
256 | hardAssert($session !== null, 'Call completed with a null response');
257 |
258 | $txn_options = new Google\Cloud\Spanner\V1\TransactionOptions();
259 | $ro = new Google\Cloud\Spanner\V1\TransactionOptions\PBReadOnly();
260 | $txn_options->setReadOnly($ro);
261 | $txn_selector = new Google\Cloud\Spanner\V1\TransactionSelector();
262 | $txn_selector->setBegin($txn_options);
263 |
264 | #Probing PartitionQuery call
265 | $ptn_query_request = new Google\Cloud\Spanner\V1\PartitionQueryRequest();
266 | $ptn_query_request->setSession($session->getName());
267 | $ptn_query_request->setSql('select * FROM users');
268 | $ptn_query_request->setTransaction($txn_selector);
269 |
270 | $time_start = microtime_float();
271 | $client->PartitionQuery($ptn_query_request);
272 | $lantency = (microtime_float() - $time_start) * 1000;
273 | $metrics['partition_query_latency_ms'] = $lantency;
274 |
275 | #Probing PartitionRead call
276 | $ptn_read_request = new Google\Cloud\Spanner\V1\PartitionReadRequest();
277 | $ptn_read_request->setSession($session->getName());
278 | $ptn_read_request->setTable('users');
279 | $ptn_read_request->setTransaction($txn_selector);
280 | $keyset = new Google\Cloud\Spanner\V1\KeySet();
281 | $keyset->setAll(True);
282 | $ptn_read_request->setKeySet($keyset);
283 | $ptn_read_request->setColumns(['username', 'firstname', 'lastname']);
284 |
285 | $time_start = microtime_float();
286 | $client->PartitionRead($ptn_read_request);
287 | $latency = (microtime_float() - $time_start) * 1000;
288 | $metrics['partition_read_latency_ms'] = $latency;
289 |
290 | # Delete Session
291 | $deleteSessionRequest = new Google\Cloud\Spanner\V1\DeleteSessionRequest();
292 | $deleteSessionRequest->setName($session->getName());
293 | $client->deleteSession($deleteSessionRequest);
294 | }
295 |
296 | $PROBE_FUNCTIONS = [
297 | 'session_management' => 'sessionManagement',
298 | 'execute_sql' => 'executeSql',
299 | 'read' => 'read',
300 | 'transaction' => 'transaction',
301 | 'partition' => 'partition'
302 | ];
303 |
304 | return $PROBE_FUNCTIONS;
305 |
306 |
307 |
308 |
--------------------------------------------------------------------------------
/cloudprober/grpc_gpc_prober/stackdriver_util.php:
--------------------------------------------------------------------------------
1 | api = $api;
18 | $this->metrics = [];
19 | $this->success = FALSE;
20 | $this->err_client = new ReportErrorsServiceClient();
21 | }
22 |
23 | function addMetric($key, $value){
24 | $this->matrics[$key] = $value;
25 | }
26 |
27 | function addMetrics($metrics){
28 | $this->metrics = array_merge($metrics, $this->metrics);
29 | }
30 |
31 | function setSuccess($result){
32 | $this->success = $result;
33 | }
34 |
35 | function outputMetrics(){
36 | if ($this->success){
37 | echo $this->api.'_success 1'."\n";
38 | }
39 | else{
40 | echo $this->api.'_success 0'."\n";
41 | }
42 | foreach ($this->metrics as $key => $value) {
43 | echo $key.' '.$value."\n";
44 | }
45 | }
46 |
47 | function reportError($err){
48 | error_log($err);
49 | $projectId = '434076015357';
50 | $project_name = $this->err_client->projectName($projectId);
51 |
52 | $location = (new SourceLocation())
53 | ->setFunctionName($this->api);
54 | $context = (new ErrorContext())
55 | ->setReportLocation($location);
56 |
57 | $error_event = new ReportedErrorEvent();
58 | $error_event->setMessage('PHPProbeFailure: fails on '.$this->api.' API. Details: '.(string)$err."\n");
59 | $error_event->setContext($context);
60 |
61 | $this->err_client->reportErrorEvent($project_name, $error_event);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "google/grpc-gcp",
3 | "description": "gRPC GCP library for channel management",
4 | "license": "Apache-2.0",
5 | "require": {
6 | "php": "^8.0",
7 | "google/protobuf": "^v3.25.3||^4.26.1",
8 | "grpc/grpc": "^v1.13.0",
9 | "google/auth": "^1.3",
10 | "psr/cache": "^1.0.1||^2.0.0||^3.0.0"
11 | },
12 | "require-dev": {
13 | "phpunit/phpunit": "^9.0",
14 | "google/cloud-spanner": "^1.7"
15 | },
16 | "autoload": {
17 | "psr-4": {
18 | "Grpc\\Gcp\\": "src/"
19 | },
20 | "classmap": [
21 | "src/generated/"
22 | ]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/doc/gRPC-client-user-guide.md:
--------------------------------------------------------------------------------
1 | # Instructions for create a gRPC client for google cloud services
2 |
3 | ## Overview
4 |
5 | This instruction includes a step by step guide for creating a gRPC
6 | client to test the google cloud service from an empty linux
7 | VM, using GCE ubuntu 16.04 TLS instance.
8 |
9 | The main steps are followed as steps below:
10 |
11 | - Environment prerequisite
12 | - Install protobuf plugin and gRPC-PHP/protobuf extension
13 | - Generate client API from .proto files
14 | - Create the client and send/receive RPC.
15 |
16 | ## Environment Prerequisite
17 |
18 | **Linux**
19 | ```sh
20 | $ [sudo] apt-get install build-essential autoconf libtool pkg-config zip unzip zlib1g-dev
21 | ```
22 | **PHP**
23 | * `php` 5.5 or above, 7.0 or above
24 | * `pecl`
25 | * `composer`
26 | ```sh
27 | $ [sudo] apt-get install php php-dev
28 | $ curl -sS https://getcomposer.org/installer | php
29 | $ [sudo] mv composer.phar /usr/local/bin/composer
30 | ```
31 |
32 | ## Install protobuf plugin and gRPC-PHP/protobuf extension
33 | `grpc_php_plugin` is used to generate client API from `*.proto `files. Currently,
34 | The only way to install `grpc_php_plugin` is to build from the gRPC source.
35 |
36 | **Install protobuf, gRPC, which will install the plugin**
37 | ```sh
38 | $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
39 | $ cd grpc
40 | $ git submodule update --init
41 | # install protobuf
42 | $ cd third_party/protobuf
43 | $ ./autogen.sh && ./configure && make -j8
44 | $ [sudo] make install
45 | $ [sudo] ldconfig
46 | # install gRPC
47 | $ cd ../..
48 | $ make -j8
49 | $ [sudo] make install
50 | ```
51 | It will generate `grpc_php_plugin` under `/usr/local/bin`.
52 |
53 |
54 | **Install gRPC-PHP extension**
55 | ```sh
56 | $ [sudo] pecl install protobuf
57 | $ [sudo] pecl install grpc
58 | ```
59 | It will generate `protobuf.so` and `grpc.so` under PHP's extension directory.
60 | Note gRPC-PHP extension installed by pecl doesn't work on RHEL6 system.
61 |
62 | ## Generate client API from .proto files
63 | The common way to generate the client API is to use `grpc_php_plugin` directly.
64 | Since the plugin won't find the dependency by itself. It works if all your
65 | service proto files and dependent proto files are inside one directory. The
66 | command looks like:
67 | ```sh
68 | $ mkdir $HOME/project
69 | $ protoc --proto_path=./ --php_out=$HOME/project \
70 | --grpc_out=$HOME/project \
71 | --plugin=protoc-gen-grpc=./bins/opt/grpc_php_plugin \
72 | path/to/your/proto_dependency_directory1/*.proto \
73 | path/to/your/proto_dependency_directory2/*.proto \
74 | path/to/your/proto_directory/*.proto
75 |
76 | ```
77 |
78 | Take `Firestore` service under [googleapis github repo](https://github.com/googleapis/googleapis)
79 | for example. The proto files required for generating client API are
80 | ```
81 | google/api/annotations.proto
82 | google/api/http.proto
83 | google/api/httpbody.proto
84 | google/longrunning/operations.proto
85 | google/rpc/code.proto
86 | google/rpc/error_details.proto
87 | google/rpc/status.proto
88 | google/type/latlng.proto
89 | google/firestore/v1beta1/firestore.proto
90 | google/firestore/v1beta1/common.proto
91 | google/firestore/v1beta1/query.proto
92 | google/firestore/v1beta1/write.proto
93 | google/firestore/v1beta1/document.proto
94 | ```
95 | Thus the command looks like:
96 | ```sh
97 | $ protoc --proto_path=googleapis --plugin=protoc-gen-grpc=`which grpc_php_plugin` \
98 | --php_out=./ --grpc_out=./ google/api/annotations.proto google/api/http.proto \
99 | google/api/httpbody.proto google/longrunning/operations.proto google/rpc/code.proto \
100 | google/rpc/error_details.proto google/rpc/status.proto google/type/latlng.proto \
101 | google/firestore/v1beta1/firestore.proto google/firestore/v1beta1/common.proto \
102 | google/firestore/v1beta1/query.proto google/firestore/v1beta1/write.proto \
103 | google/firestore/v1beta1/document.proto
104 | ```
105 |
106 | Since most of cloud services already publish proto files under
107 | [googleapis github repo](https://github.com/googleapis/googleapis),
108 | you can use it's Makefile to generate the client API.
109 | The `Makefile` will help you generate the client API as
110 | well as find the dependencies. The command will simply be:
111 | ```sh
112 | $ cd $HOME
113 | $ mkdir project
114 | $ git clone https://github.com/googleapis/googleapis.git
115 | $ cd googleapis
116 | $ make LANGUAGE=php OUTPUT=$HOME/project
117 | # (It's okay if you see error like Please add 'syntax = "proto3";'
118 | # to the top of your .proto file.)
119 | ```
120 | The client API library is generated under `$HOME/project`.
121 | Take [`Firestore`](https://github.com/googleapis/googleapis/blob/master/google/firestore/v1beta1/firestore.proto)
122 | as example, the Client API is under
123 | `project/Google/Cloud/Firestore/V1beta1/FirestoreClient.php` depends on your
124 | package name inside .proto file. An easy way to find your client is
125 | ```sh
126 | $ find ./ -name [service_name]Client.php
127 | ```
128 |
129 | ## Create the client and send/receive RPC.
130 | Now it's time to use the client API to send and receive RPCs.
131 | ```sh
132 | $ cd $HOME/project
133 | ```
134 | **Install gRPC-PHP composer library**
135 | ```sh
136 | $ vim composer.json
137 | ######## you need to change the path and service namespace.
138 | {
139 | "require": {
140 | "google/cloud": "^0.52.1"
141 | },
142 | "autoload": {
143 | "psr-4": {
144 | "FireStore\\": "src/",
145 | "Google\\Cloud\\Firestore\\V1beta1\\": "Google/Cloud/Firestore/V1beta1/"
146 | }
147 | }
148 | }
149 | ########
150 | $ composer install
151 | ```
152 | **Set credentials file**
153 | ``` sh
154 | $ vim $HOME/key.json
155 | ## Paste you credential file downloaded from your cloud project
156 | ## which you can find in APIs&Services => credentials => create credentials
157 | ## => Service account key => your credentials
158 | $ export GOOGLE_APPLICATION_CREDENTIALS=$HOME/key.json
159 | ```
160 |
161 | **Implement Service Client**
162 | Take a unary-unary RPC `listDocument` from `FirestoreClient` as example.
163 | Create a file name `ListDocumentClient.php`.
164 | - import library
165 | ```
166 | require_once __DIR__ . '/vendor/autoload.php';
167 | use Google\Cloud\Firestore\V1beta1\FirestoreClient;
168 | use Google\Cloud\Firestore\V1beta1\ListDocumentsRequest;
169 | use Google\Auth\ApplicationDefaultCredentials;
170 | ```
171 | - Google Auth
172 | ```
173 | $host = "firestore.googleapis.com";
174 | $credentials = \Grpc\ChannelCredentials::createSsl();
175 | // WARNING: the environment variable "GOOGLE_APPLICATION_CREDENTIALS" needs to be set
176 | $auth = ApplicationDefaultCredentials::getCredentials();
177 | $opts = [
178 | 'credentials' => $credentials,
179 | 'update_metadata' => $auth->getUpdateMetadataFunc(),
180 | ]
181 | ```
182 | - Create Client
183 | ```
184 | $firestoreClient = new FirestoreClient($host, $opts);
185 | ```
186 | - Make and receive RPC call
187 | ```
188 | $argument = new ListDocumentsRequest();
189 | $project_id = xxxxxxx;
190 | $argument->setParent("projects/$project_id/databases/(default)/documents");
191 | list($Response, $error) = $firestoreClient->ListDocuments($argument)->wait();
192 | ```
193 | - print RPC response
194 | ```
195 | $documents = $Response->getDocuments();
196 | $index = 0;
197 | foreach($documents as $document) {
198 | $index++;
199 | $name = $document->getName();
200 | echo "=> Document $index: $name\n";
201 | $fields = $document->getFields();
202 | foreach ($fields as $name => $value) {
203 | echo "$name => ".$value->getStringValue()."\n";
204 | }
205 | }
206 | ```
207 |
208 | - run the script
209 | ```sh
210 | $ php -d extension=grpc.so -d extension=protobuf.so ListDocumentClient.php
211 | ```
212 |
213 | For different kinds of RPC(unary-unary, unary-stream, stream-unary, stream-stream),
214 | please check [grpc.io PHP part](https://grpc.io/docs/tutorials/basic/php.html#calling-service-methods)
215 | for reference.
216 |
217 |
218 |
--------------------------------------------------------------------------------
/src/ChannelRef.php:
--------------------------------------------------------------------------------
1 | target = $target;
41 | $this->channel_id = $channel_id;
42 | $this->affinity_ref = $affinity_ref;
43 | $this->active_stream_ref = $active_stream_ref;
44 | $this->opts = $opts;
45 | $this->has_deserialized = new CreatedByDeserializeCheck();
46 | }
47 |
48 | public function getRealChannel($credentials)
49 | {
50 | // TODO(ddyihai): remove this check once the serialize handler for
51 | // \Grpc\Channel is implemented(issue https://github.com/grpc/grpc/issues/15870).
52 | if (!$this->has_deserialized->getData()) {
53 | // $real_channel exists and is not created by the deserialization.
54 | return $this->real_channel;
55 | }
56 | // If this ChannelRef is created by deserialization, $real_channel is invalid
57 | // thus needs to be recreated becasue Grpc\Channel don't have serialize and
58 | // deserialize handler.
59 | // Since [target + augments + credentials] will be the same during the recreation,
60 | // it will reuse the underline grpc channel in C extension without creating a
61 | // new connection.
62 |
63 | // 'credentials' in the array $opts will be unset during creating the channel.
64 | if (!array_key_exists('credentials', $this->opts)) {
65 | $this->opts['credentials'] = $credentials;
66 | }
67 | $real_channel = new \Grpc\Channel($this->target, $this->opts);
68 | $this->real_channel = $real_channel;
69 | // Set deserialization to false so it won't be recreated within the same script.
70 | $this->has_deserialized->setData(0);
71 | return $real_channel;
72 | }
73 |
74 | public function getAffinityRef()
75 | {
76 | return $this->affinity_ref;
77 | }
78 | public function getActiveStreamRef()
79 | {
80 | return $this->active_stream_ref;
81 | }
82 | public function affinityRefIncr()
83 | {
84 | $this->affinity_ref += 1;
85 | }
86 | public function affinityRefDecr()
87 | {
88 | $this->affinity_ref -= 1;
89 | }
90 | public function activeStreamRefIncr()
91 | {
92 | $this->active_stream_ref += 1;
93 | }
94 | public function activeStreamRefDecr()
95 | {
96 | $this->active_stream_ref -= 1;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Config.php:
--------------------------------------------------------------------------------
1 | gcp_call_invoker = new \Grpc\DefaultCallInvoker();
45 | return;
46 | }
47 |
48 | $gcp_channel = null;
49 | $url_host = parse_url($target, PHP_URL_HOST);
50 | $this->hostname = $url_host ? $url_host : $target;
51 | $channel_pool_key = $this->hostname . '.gcp.channel.' . getmypid();
52 |
53 | if (!$cacheItemPool) {
54 | $affinity_conf = $this->parseConfObject($conf);
55 | $gcp_call_invoker = new GCPCallInvoker($affinity_conf);
56 | $this->gcp_call_invoker = $gcp_call_invoker;
57 | } else {
58 | $item = $cacheItemPool->getItem($channel_pool_key);
59 | if ($item->isHit()) {
60 | // Channel pool for the $hostname API has already created.
61 | $gcp_call_invoker = unserialize($item->get());
62 | } else {
63 | $affinity_conf = $this->parseConfObject($conf);
64 | // Create GCP channel based on the information.
65 | $gcp_call_invoker = new GCPCallInvoker($affinity_conf);
66 | }
67 | $this->gcp_call_invoker = $gcp_call_invoker;
68 | register_shutdown_function(function ($gcp_call_invoker, $cacheItemPool, $item) {
69 | // Push the current gcp_channel back into the pool when the script finishes.
70 | $item->set(serialize($gcp_call_invoker));
71 | $cacheItemPool->save($item);
72 | }, $gcp_call_invoker, $cacheItemPool, $item);
73 | }
74 | }
75 |
76 | /**
77 | * @return \Grpc\CallInvoker The call invoker to be hooked into the gRPC
78 | */
79 | public function callInvoker()
80 | {
81 | return $this->gcp_call_invoker;
82 | }
83 |
84 | /**
85 | * @return string The URI of the endpoint
86 | */
87 | public function getTarget()
88 | {
89 | return $this->channel->getTarget();
90 | }
91 |
92 | private function parseConfObject($conf_object)
93 | {
94 | $config = json_decode($conf_object->serializeToJsonString(), true);
95 | if (isset($config['channelPool'])) {
96 | $affinity_conf['channelPool'] = $config['channelPool'];
97 | }
98 | $aff_by_method = array();
99 | if (isset($config['method'])) {
100 | for ($i = 0; $i < count($config['method']); $i++) {
101 | // In proto3, if the value is default, eg 0 for int, it won't be serialized.
102 | // Thus serialized string may not have `command` if the value is default 0(BOUND).
103 | if (!array_key_exists('command', $config['method'][$i]['affinity'])) {
104 | $config['method'][$i]['affinity']['command'] = 'BOUND';
105 | }
106 | $aff_by_method[$config['method'][$i]['name'][0]] = $config['method'][$i]['affinity'];
107 | }
108 | }
109 | $affinity_conf['affinity_by_method'] = $aff_by_method;
110 | return $affinity_conf;
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/src/CreatedByDeserializeCheck.php:
--------------------------------------------------------------------------------
1 | data = 1;
35 | }
36 |
37 | /**
38 | * @return string
39 | */
40 | public function serialize()
41 | {
42 | return '0';
43 | }
44 |
45 | /**
46 | * @return string
47 | */
48 | public function __serialize()
49 | {
50 | return $this->serialize();
51 | }
52 |
53 | /**
54 | * @param string $data
55 | */
56 | public function unserialize($data)
57 | {
58 | $this->data = 1;
59 | }
60 |
61 | /**
62 | * @param string $data
63 | */
64 | public function __unserialize($data)
65 | {
66 | $this->unserialize($data);
67 | }
68 |
69 | /**
70 | * @param $data
71 | */
72 | public function setData($data)
73 | {
74 | $this->data = $data;
75 | }
76 |
77 | /**
78 | * @return int
79 | */
80 | public function getData()
81 | {
82 | return $this->data;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/GCPBidiStreamingCall.php:
--------------------------------------------------------------------------------
1 | _rpcPreProcess($data);
32 | $this->real_call = new \Grpc\BidiStreamingCall($channel_ref->getRealChannel(
33 | $this->gcp_channel->credentials), $this->method, $this->deserialize, $this->options);
34 | $this->real_call->start($this->metadata_rpc);
35 | return $this->real_call;
36 | }
37 |
38 | /**
39 | * Pick a channel and start the call.
40 | *
41 | * @param array $metadata Metadata to send with the call, if applicable
42 | * (optional)
43 | */
44 | public function start(array $metadata = [])
45 | {
46 | $this->metadata_rpc = $metadata;
47 | }
48 |
49 | /**
50 | * Reads the next value from the server.
51 | *
52 | * @return mixed The next value from the server, or null if there is none
53 | */
54 | public function read()
55 | {
56 | if (!$this->has_real_call) {
57 | $this->createRealCall();
58 | $this->has_real_call = true;
59 | }
60 | $response = $this->real_call->read();
61 | if ($response) {
62 | $this->response = $response;
63 | }
64 | return $response;
65 | }
66 |
67 | /**
68 | * Write a single message to the server. This cannot be called after
69 | * writesDone is called.
70 | *
71 | * @param ByteBuffer $data The data to write
72 | * @param array $options An array of options, possible keys:
73 | * 'flags' => a number (optional)
74 | */
75 | public function write($data, array $options = [])
76 | {
77 | if (!$this->has_real_call) {
78 | $this->createRealCall($data);
79 | $this->has_real_call = true;
80 | }
81 | $this->real_call->write($data, $options);
82 | }
83 |
84 | /**
85 | * Indicate that no more writes will be sent.
86 | */
87 | public function writesDone()
88 | {
89 | if (!$this->has_real_call) {
90 | $this->createRealCall();
91 | $this->has_real_call = true;
92 | }
93 | $this->real_call->writesDone();
94 | }
95 |
96 | /**
97 | * Wait for the server to send the status, and return it.
98 | *
99 | * @return \stdClass The status object, with integer $code, string
100 | * $details, and array $metadata members
101 | */
102 | public function getStatus()
103 | {
104 | $status = $this->real_call->getStatus();
105 | $this->_rpcPostProcess($status, $this->response);
106 | return $status;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/GCPCallInvoker.php:
--------------------------------------------------------------------------------
1 | affinity_conf = $affinity_conf;
43 | }
44 |
45 | /**
46 | * @param string $hostname
47 | * @param array $opts
48 | * @return GcpExtensionChannel
49 | */
50 | public function createChannelFactory($hostname, $opts)
51 | {
52 | if ($this->channel) {
53 | // $call_invoker object has already created from previews PHP-FPM scripts.
54 | // Only need to update the $opts including the credentials.
55 | $this->channel->updateOpts($opts);
56 | } else {
57 | $opts['affinity_conf'] = $this->affinity_conf;
58 | $channel = new GcpExtensionChannel($hostname, $opts);
59 | $this->channel = $channel;
60 | }
61 | return $this->channel;
62 | }
63 |
64 | // _getChannel is used for testing only.
65 | public function GetChannel()
66 | {
67 | return $this->channel;
68 | }
69 |
70 | public function UnaryCall($channel, $method, $deserialize, $options)
71 | {
72 | return new GCPUnaryCall($channel, $method, $deserialize, $options);
73 | }
74 | public function ClientStreamingCall($channel, $method, $deserialize, $options)
75 | {
76 | return new GCPClientStreamCall($channel, $method, $deserialize, $options);
77 | }
78 | public function ServerStreamingCall($channel, $method, $deserialize, $options)
79 | {
80 | return new GCPServerStreamCall($channel, $method, $deserialize, $options);
81 | }
82 | public function BidiStreamingCall($channel, $method, $deserialize, $options)
83 | {
84 | return new GCPBidiStreamingCall($channel, $method, $deserialize, $options);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/GCPClientStreamCall.php:
--------------------------------------------------------------------------------
1 | _rpcPreProcess($data);
30 | $this->real_call = new \Grpc\ClientStreamingCall($channel_ref->getRealChannel(
31 | $this->gcp_channel->credentials), $this->method, $this->deserialize, $this->options);
32 | $this->real_call->start($this->metadata_rpc);
33 | return $this->real_call;
34 | }
35 | /**
36 | * Pick a channel and start the call.
37 | *
38 | * @param array $metadata Metadata to send with the call, if applicable
39 | * (optional)
40 | */
41 | public function start(array $metadata = [])
42 | {
43 | // Postpone first rpc to write function(), where we can pick a channel
44 | // from the channel pool.
45 | $this->metadata_rpc = $metadata;
46 | }
47 |
48 | /**
49 | * Write a single message to the server. This cannot be called after
50 | * wait is called.
51 | *
52 | * @param ByteBuffer $data The data to write
53 | * @param array $options An array of options, possible keys:
54 | * 'flags' => a number (optional)
55 | */
56 | public function write($data, array $options = [])
57 | {
58 | if (!$this->has_real_call) {
59 | $this->createRealCall($data);
60 | $this->has_real_call = true;
61 | }
62 | $this->real_call->write($data, $options);
63 | }
64 |
65 | /**
66 | * Wait for the server to respond with data and a status.
67 | *
68 | * @return array [response data, status]
69 | */
70 | public function wait()
71 | {
72 | list($response, $status) = $this->real_call->wait();
73 | $this->_rpcPostProcess($status, $response);
74 | return [$response, $status];
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/GCPServerStreamCall.php:
--------------------------------------------------------------------------------
1 | real_call = new \Grpc\ServerStreamingCall($channel, $this->method, $this->deserialize, $this->options);
32 | $this->has_real_call = true;
33 | return $this->real_call;
34 | }
35 |
36 | /**
37 | * Pick a channel and start the call.
38 | *
39 | * @param mixed $data The data to send
40 | * @param array $metadata Metadata to send with the call, if applicable
41 | * (optional)
42 | * @param array $options An array of options, possible keys:
43 | * 'flags' => a number (optional)
44 | */
45 | public function start($argument, $metadata, $options)
46 | {
47 | $channel_ref = $this->_rpcPreProcess($argument);
48 | $this->createRealCall($channel_ref->getRealChannel(
49 | $this->gcp_channel->credentials));
50 | $this->real_call->start($argument, $metadata, $options);
51 | }
52 |
53 | /**
54 | * @return mixed An iterator of response values
55 | */
56 | public function responses()
57 | {
58 | $response = $this->real_call->responses();
59 | // Since the last response is empty for the server streaming RPC,
60 | // the second last one is the last RPC response with payload.
61 | // Use this one for searching the affinity key.
62 | // The same as BidiStreaming.
63 | if ($response) {
64 | $this->response = $response;
65 | }
66 | return $response;
67 | }
68 |
69 | /**
70 | * Wait for the server to send the status, and return it.
71 | *
72 | * @return \stdClass The status object, with integer $code, string
73 | * $details, and array $metadata members
74 | */
75 | public function getStatus()
76 | {
77 | $status = $this->real_call->getStatus();
78 | $this->_rpcPostProcess($status, $this->response);
79 | return $status;
80 | }
81 |
82 | /**
83 | * @return mixed The metadata sent by the server
84 | */
85 | public function getMetadata()
86 | {
87 | return $this->real_call->getMetadata();
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/GCPUnaryCall.php:
--------------------------------------------------------------------------------
1 | real_call = new \Grpc\UnaryCall($channel, $this->method, $this->deserialize, $this->options);
30 | $this->has_real_call = true;
31 | return $this->real_call;
32 | }
33 |
34 | /**
35 | * Pick a channel and start the call.
36 | *
37 | * @param mixed $data The data to send
38 | * @param array $metadata Metadata to send with the call, if applicable
39 | * (optional)
40 | * @param array $options An array of options, possible keys:
41 | * 'flags' => a number (optional)
42 | */
43 | public function start($argument, $metadata, $options)
44 | {
45 | $channel_ref = $this->_rpcPreProcess($argument);
46 | $real_channel = $channel_ref->getRealChannel($this->gcp_channel->credentials);
47 | $this->createRealCall($real_channel);
48 | $this->real_call->start($argument, $metadata, $options);
49 | }
50 |
51 | /**
52 | * Wait for the server to respond with data and a status.
53 | *
54 | * @return array [response data, status]
55 | */
56 | public function wait()
57 | {
58 | list($response, $status) = $this->real_call->wait();
59 | $this->_rpcPostProcess($status, $response);
60 | return [$response, $status];
61 | }
62 |
63 | /**
64 | * @return mixed The metadata sent by the server
65 | */
66 | public function getMetadata()
67 | {
68 | return $this->real_call->getMetadata();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/GcpBaseCall.php:
--------------------------------------------------------------------------------
1 | gcp_channel = $channel;
65 | $this->method = $method;
66 | $this->deserialize = $deserialize;
67 | $this->options = $options;
68 | $this->_affinity = null;
69 |
70 | if (isset($this->gcp_channel->affinity_conf['affinity_by_method'][$method])) {
71 | $this->_affinity = $this->gcp_channel->affinity_conf['affinity_by_method'][$method];
72 | }
73 | }
74 |
75 | /**
76 | * Pick a ChannelRef from the channel pool based on the request and
77 | * the affinity config.
78 | *
79 | * @param mixed $argument Requests.
80 | *
81 | * @return ChannelRef
82 | */
83 | protected function _rpcPreProcess($argument)
84 | {
85 | $this->affinity_key = null;
86 | if ($this->_affinity) {
87 | $command = $this->_affinity['command'];
88 | if ($command == self::BOUND || $command == self::UNBIND) {
89 | $this->affinity_key = $this->getAffinityKeyFromProto($argument);
90 | }
91 | }
92 | $this->channel_ref = $this->gcp_channel->getChannelRef($this->affinity_key);
93 | $this->channel_ref->activeStreamRefIncr();
94 | return $this->channel_ref;
95 | }
96 |
97 | /**
98 | * Update ChannelRef when RPC finishes.
99 | *
100 | * @param \stdClass $status The status object, with integer $code, string
101 | * $details, and array $metadata members
102 | * @param mixed $response Response.
103 | */
104 | protected function _rpcPostProcess($status, $response)
105 | {
106 | if ($this->_affinity) {
107 | $command = $this->_affinity['command'];
108 | if ($command == self::BIND) {
109 | if ($status->code != \Grpc\STATUS_OK) {
110 | return;
111 | }
112 | $affinity_key = $this->getAffinityKeyFromProto($response);
113 | $this->gcp_channel->bind($this->channel_ref, $affinity_key);
114 | } elseif ($command == self::UNBIND) {
115 | $this->gcp_channel->unbind($this->affinity_key);
116 | }
117 | }
118 | $this->channel_ref->activeStreamRefDecr();
119 | }
120 |
121 | /**
122 | * Get the affinity key based on the affinity config.
123 | *
124 | * @param mixed $proto Objects may contain the affinity key.
125 | *
126 | * @return string Affinity key.
127 | */
128 | protected function getAffinityKeyFromProto($proto)
129 | {
130 | if ($this->_affinity) {
131 | $names = $this->_affinity['affinityKey'];
132 | $names_arr = explode(".", $names);
133 | foreach ($names_arr as $name) {
134 | $getAttrMethod = 'get' . ucfirst($name);
135 | $proto = call_user_func_array(array($proto, $getAttrMethod), array());
136 | }
137 | return $proto;
138 | }
139 | echo "Cannot find the field in the proto\n";
140 | }
141 |
142 | /**
143 | * @return mixed The metadata sent by the server
144 | */
145 | public function getMetadata()
146 | {
147 | if (!$this->has_real_call) {
148 | $this->createRealCall();
149 | $this->has_real_call = true;
150 | }
151 | return $this->real_call->getMetadata();
152 | }
153 |
154 | /**
155 | * @return mixed The trailing metadata sent by the server
156 | */
157 | public function getTrailingMetadata()
158 | {
159 | if (!$this->has_real_call) {
160 | $this->createRealCall();
161 | $this->has_real_call = true;
162 | }
163 | return $this->real_call->getTrailingMetadata();
164 | }
165 |
166 | /**
167 | * @return string The URI of the endpoint
168 | */
169 | public function getPeer()
170 | {
171 | if (!$this->has_real_call) {
172 | $this->createRealCall();
173 | $this->has_real_call = true;
174 | }
175 | return $this->real_call->getPeer();
176 | }
177 |
178 | /**
179 | * Cancels the call.
180 | */
181 | public function cancel()
182 | {
183 | if (!$this->has_real_call) {
184 | $this->has_real_call = true;
185 | $this->createRealCall();
186 | }
187 | $this->real_call->cancel();
188 | }
189 |
190 | /**
191 | * Serialize a message to the protobuf binary format.
192 | *
193 | * @param mixed $data The Protobuf message
194 | *
195 | * @return string The protobuf binary format
196 | */
197 | protected function _serializeMessage($data)
198 | {
199 | return $this->real_call->_serializeMessage($data);
200 | }
201 |
202 | /**
203 | * Deserialize a response value to an object.
204 | *
205 | * @param string $value The binary value to deserialize
206 | *
207 | * @return mixed The deserialized value
208 | */
209 | protected function _deserializeResponse($value)
210 | {
211 | return $this->real_call->_deserializeResponse($value);
212 | }
213 |
214 | /**
215 | * Set the CallCredentials for the underlying Call.
216 | *
217 | * @param CallCredentials $call_credentials The CallCredentials object
218 | */
219 | public function setCallCredentials($call_credentials)
220 | {
221 | $this->call->setCredentials($call_credentials);
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/src/GcpExtensionChannel.php:
--------------------------------------------------------------------------------
1 | channel_refs;
44 | }
45 |
46 | /**
47 | * @param string $hostname
48 | * @param array $opts Options to create a \Grpc\Channel and affinity config
49 | */
50 | public function __construct($hostname = null, $opts = array())
51 | {
52 | if ($hostname == null || !is_array($opts)) {
53 | throw new \InvalidArgumentException("Expected hostname is empty");
54 | }
55 | $this->max_size = 10;
56 | $this->max_concurrent_streams_low_watermark = 100;
57 | if (isset($opts['affinity_conf'])) {
58 | if (isset($opts['affinity_conf']['channelPool'])) {
59 | if (isset($opts['affinity_conf']['channelPool']['maxSize'])) {
60 | $this->max_size = $opts['affinity_conf']['channelPool']['maxSize'];
61 | }
62 | if (isset($opts['affinity_conf']['channelPool']['maxConcurrentStreamsLowWatermark'])) {
63 | $this->max_concurrent_streams_low_watermark =
64 | $opts['affinity_conf']['channelPool']['maxConcurrentStreamsLowWatermark'];
65 | }
66 | }
67 | $this->affinity_by_method = $opts['affinity_conf']['affinity_by_method'];
68 | $this->affinity_conf = $opts['affinity_conf'];
69 | }
70 | $this->target = $hostname;
71 | $this->affinity_key_to_channel_ref = array();
72 | $this->channel_refs = array();
73 | $this->updateOpts($opts);
74 | // Initiate a Grpc\Channel at the beginning in order to keep the same
75 | // behavior as the Grpc.
76 | $channel_ref = $this->getChannelRef();
77 | $channel_ref->getRealChannel($this->credentials);
78 | }
79 |
80 | /**
81 | * @param array $opts Options to create a \Grpc\Channel
82 | */
83 | public function updateOpts($opts)
84 | {
85 | if (isset($opts['credentials'])) {
86 | $this->credentials = $opts['credentials'];
87 | }
88 | unset($opts['affinity_conf']);
89 | unset($opts['credentials']);
90 | $this->options = $opts;
91 | $this->is_closed = false;
92 | }
93 |
94 | /**
95 | * Bind the ChannelRef with the affinity key. This is a private method.
96 | *
97 | * @param ChannelRef $channel_ref
98 | * @param string $affinity_key
99 | *
100 | * @return ChannelRef
101 | */
102 | public function bind($channel_ref, $affinity_key)
103 | {
104 | if (!array_key_exists($affinity_key, $this->affinity_key_to_channel_ref)) {
105 | $this->affinity_key_to_channel_ref[$affinity_key] = $channel_ref;
106 | }
107 | $channel_ref->affinityRefIncr();
108 | return $channel_ref;
109 | }
110 |
111 | /**
112 | * Unbind the affinity key. This is a private method.
113 | *
114 | * @param string $affinity_key
115 | *
116 | * @return ChannelRef
117 | */
118 | public function unbind($affinity_key)
119 | {
120 | $channel_ref = null;
121 | if (array_key_exists($affinity_key, $this->affinity_key_to_channel_ref)) {
122 | $channel_ref = $this->affinity_key_to_channel_ref[$affinity_key];
123 | $channel_ref->affinityRefDecr();
124 | }
125 | unset($this->affinity_key_to_channel_ref[$affinity_key]);
126 | return $channel_ref;
127 | }
128 |
129 |
130 | public function cmp_by_active_stream_ref($a, $b)
131 | {
132 | return $a->getActiveStreamRef() - $b->getActiveStreamRef();
133 | }
134 |
135 | /**
136 | * Pick or create a ChannelRef from the pool by affinity key.
137 | *
138 | * @param string $affinity_key
139 | *
140 | * @return ChannelRef
141 | */
142 | public function getChannelRef($affinity_key = null)
143 | {
144 | if ($affinity_key) {
145 | if (array_key_exists($affinity_key, $this->affinity_key_to_channel_ref)) {
146 | return $this->affinity_key_to_channel_ref[$affinity_key];
147 | }
148 | return $this->getChannelRef();
149 | }
150 | usort($this->channel_refs, array($this, 'cmp_by_active_stream_ref'));
151 |
152 | if (count($this->channel_refs) > 0 && $this->channel_refs[0]->getActiveStreamRef() <
153 | $this->max_concurrent_streams_low_watermark) {
154 | return $this->channel_refs[0];
155 | }
156 | $num_channel_refs = count($this->channel_refs);
157 | if ($num_channel_refs < $this->max_size) {
158 | // grpc_target_persist_bound stands for how many channels can be persisted for
159 | // the same target in the C extension. It is possible that the user use the pure
160 | // gRPC and this GCP extension at the same time, which share the same target. In this case
161 | // pure gRPC channel may occupy positions in C extension, which deletes some channels created
162 | // by this GCP extension.
163 | // If that happens, it won't cause the script failure because we saves all arguments for creating
164 | // a channel instead of a channel itself. If we watch to fetch a GCP channel already deleted,
165 | // it will create a new channel. The only cons is the latency of the first RPC will high because
166 | // it will establish the connection again.
167 | if (!isset($this->options['grpc_target_persist_bound']) ||
168 | $this->options['grpc_target_persist_bound'] < $this->max_size) {
169 | $this->options['grpc_target_persist_bound'] = $this->max_size;
170 | }
171 | $cur_opts = array_merge($this->options,
172 | ['grpc_gcp_channel_id' => $num_channel_refs]);
173 | $channel_ref = new ChannelRef($this->target, $num_channel_refs, $cur_opts);
174 | array_unshift($this->channel_refs, $channel_ref);
175 | }
176 | return $this->channel_refs[0];
177 | }
178 |
179 | /**
180 | * Get the connectivity state of the channel
181 | *
182 | * @param bool $try_to_connect try to connect on the channel
183 | *
184 | * @return int The grpc connectivity state
185 | * @throws \InvalidArgumentException
186 | */
187 | public function getConnectivityState($try_to_connect = false)
188 | {
189 | // Since getRealChannel is creating a PHP Channel object. However in gRPC, when a Channel
190 | // object is closed, we only mark this Object to be invalid. Thus, we need a global variable
191 | // to mark whether this GCPExtensionChannel is close or not.
192 | if ($this->is_closed) {
193 | throw new \RuntimeException("Channel has already been closed");
194 | }
195 | $ready = 0;
196 | $idle = 0;
197 | $connecting = 0;
198 | $transient_failure = 0;
199 | $shutdown = 0;
200 | foreach ($this->channel_refs as $channel_ref) {
201 | $state = $channel_ref->getRealChannel($this->credentials)->getConnectivityState($try_to_connect);
202 | switch ($state) {
203 | case \Grpc\CHANNEL_READY:
204 | $ready += 1;
205 | break 2;
206 | case \Grpc\CHANNEL_FATAL_FAILURE:
207 | $shutdown += 1;
208 | break;
209 | case \Grpc\CHANNEL_CONNECTING:
210 | $connecting += 1;
211 | break;
212 | case \Grpc\CHANNEL_TRANSIENT_FAILURE:
213 | $transient_failure += 1;
214 | break;
215 | case \Grpc\CHANNEL_IDLE:
216 | $idle += 1;
217 | break;
218 | }
219 | }
220 | if ($ready > 0) {
221 | return \Grpc\CHANNEL_READY;
222 | } elseif ($idle > 0) {
223 | return \Grpc\CHANNEL_IDLE;
224 | } elseif ($connecting > 0) {
225 | return \Grpc\CHANNEL_CONNECTING;
226 | } elseif ($transient_failure > 0) {
227 | return \Grpc\CHANNEL_TRANSIENT_FAILURE;
228 | } elseif ($shutdown > 0) {
229 | return \Grpc\CHANNEL_SHUTDOWN;
230 | }
231 | }
232 |
233 | /**
234 | * Watch the connectivity state of the channel until it changed
235 | *
236 | * @param int $last_state The previous connectivity state of the channel
237 | * @param Timeval $deadline_obj The deadline this function should wait until
238 | *
239 | * @return bool If the connectivity state changes from last_state
240 | * before deadline
241 | * @throws \InvalidArgumentException
242 | */
243 | public function watchConnectivityState($last_state, $deadline_obj = null)
244 | {
245 | if ($deadline_obj == null || !is_a($deadline_obj, '\Grpc\Timeval')) {
246 | throw new \InvalidArgumentException("");
247 | }
248 | // Since getRealChannel is creating a PHP Channel object. However in gRPC, when a Channel
249 | // object is closed, we only mark this Object to be invalid. Thus, we need a global variable
250 | // to mark whether this GCPExtensionChannel is close or not.
251 | if ($this->is_closed) {
252 | throw new \RuntimeException("Channel has already been closed");
253 | }
254 | $state = 0;
255 | foreach ($this->channel_refs as $channel_ref) {
256 | $state = $channel_ref->getRealChannel($this->credentials)->watchConnectivityState($last_state, $deadline_obj);
257 | }
258 | return $state;
259 | }
260 |
261 | /**
262 | * Get the endpoint this call/stream is connected to
263 | *
264 | * @return string The URI of the endpoint
265 | */
266 | public function getTarget()
267 | {
268 | return $this->target;
269 | }
270 |
271 | /**
272 | * Close the channel
273 | */
274 | public function close()
275 | {
276 | foreach ($this->channel_refs as $channel_ref) {
277 | $channel_ref->getRealChannel($this->credentials)->close();
278 | }
279 | $this->is_closed = true;
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/src/generated/GPBMetadata/GrpcGcp.php:
--------------------------------------------------------------------------------
1 | internalAddGeneratedFile(hex2bin(
19 | "0ac9030a0e677270635f6763702e70726f746f1208677270632e67637022" .
20 | "670a09417069436f6e66696712310a0c6368616e6e656c5f706f6f6c1802" .
21 | "2001280b321b2e677270632e6763702e4368616e6e656c506f6f6c436f6e" .
22 | "66696712270a066d6574686f6418e9072003280b32162e677270632e6763" .
23 | "702e4d6574686f64436f6e66696722690a114368616e6e656c506f6f6c43" .
24 | "6f6e66696712100a086d61785f73697a6518012001280d12140a0c69646c" .
25 | "655f74696d656f7574180220012804122c0a246d61785f636f6e63757272" .
26 | "656e745f73747265616d735f6c6f775f77617465726d61726b1803200128" .
27 | "0d22490a0c4d6574686f64436f6e666967120c0a046e616d651801200328" .
28 | "09122b0a08616666696e69747918e9072001280b32182e677270632e6763" .
29 | "702e416666696e697479436f6e6669672285010a0e416666696e69747943" .
30 | "6f6e66696712310a07636f6d6d616e6418022001280e32202e677270632e" .
31 | "6763702e416666696e697479436f6e6669672e436f6d6d616e6412140a0c" .
32 | "616666696e6974795f6b6579180320012809222a0a07436f6d6d616e6412" .
33 | "090a05424f554e44100012080a0442494e441001120a0a06554e42494e44" .
34 | "1002620670726f746f33"
35 | ));
36 |
37 | static::$is_initialized = true;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/generated/Grpc/Gcp/AffinityConfig.php:
--------------------------------------------------------------------------------
1 | grpc.gcp.AffinityConfig
11 | */
12 | class AffinityConfig extends \Google\Protobuf\Internal\Message
13 | {
14 | /**
15 | * The affinity command applies on the selected gRPC methods.
16 | *
17 | * Generated from protobuf field .grpc.gcp.AffinityConfig.Command command = 2;
18 | */
19 | private $command = 0;
20 | /**
21 | * The field path of the affinity key in the request/response message.
22 | * For example: "f.a", "f.b.d", etc.
23 | *
24 | * Generated from protobuf field string affinity_key = 3;
25 | */
26 | private $affinity_key = '';
27 |
28 | public function __construct()
29 | {
30 | \GPBMetadata\GrpcGcp::initOnce();
31 | parent::__construct();
32 | }
33 |
34 | /**
35 | * The affinity command applies on the selected gRPC methods.
36 | *
37 | * Generated from protobuf field .grpc.gcp.AffinityConfig.Command command = 2;
38 | * @return int
39 | */
40 | public function getCommand()
41 | {
42 | return $this->command;
43 | }
44 |
45 | /**
46 | * The affinity command applies on the selected gRPC methods.
47 | *
48 | * Generated from protobuf field .grpc.gcp.AffinityConfig.Command command = 2;
49 | * @param int $var
50 | * @return $this
51 | */
52 | public function setCommand($var)
53 | {
54 | GPBUtil::checkEnum($var, \Grpc\Gcp\AffinityConfig_Command::class);
55 | $this->command = $var;
56 |
57 | return $this;
58 | }
59 |
60 | /**
61 | * The field path of the affinity key in the request/response message.
62 | * For example: "f.a", "f.b.d", etc.
63 | *
64 | * Generated from protobuf field string affinity_key = 3;
65 | * @return string
66 | */
67 | public function getAffinityKey()
68 | {
69 | return $this->affinity_key;
70 | }
71 |
72 | /**
73 | * The field path of the affinity key in the request/response message.
74 | * For example: "f.a", "f.b.d", etc.
75 | *
76 | * Generated from protobuf field string affinity_key = 3;
77 | * @param string $var
78 | * @return $this
79 | */
80 | public function setAffinityKey($var)
81 | {
82 | GPBUtil::checkString($var, true);
83 | $this->affinity_key = $var;
84 |
85 | return $this;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/generated/Grpc/Gcp/AffinityConfig_Command.php:
--------------------------------------------------------------------------------
1 | Grpc\Gcp\AffinityConfig\Command
9 | */
10 | class AffinityConfig_Command
11 | {
12 | /**
13 | * The annotated method will be required to be bound to an existing session
14 | * to execute the RPC. The corresponding will be
15 | * used to find the affinity key from the request message.
16 | *
17 | * Generated from protobuf enum BOUND = 0;
18 | */
19 | const BOUND = 0;
20 | /**
21 | * The annotated method will establish the channel affinity with the channel
22 | * which is used to execute the RPC. The corresponding
23 | * will be used to find the affinity key from the
24 | * response message.
25 | *
26 | * Generated from protobuf enum BIND = 1;
27 | */
28 | const BIND = 1;
29 | /**
30 | * The annotated method will remove the channel affinity with the channel
31 | * which is used to execute the RPC. The corresponding
32 | * will be used to find the affinity key from the
33 | * request message.
34 | *
35 | * Generated from protobuf enum UNBIND = 2;
36 | */
37 | const UNBIND = 2;
38 | }
39 |
--------------------------------------------------------------------------------
/src/generated/Grpc/Gcp/ApiConfig.php:
--------------------------------------------------------------------------------
1 | grpc.gcp.ApiConfig
11 | */
12 | class ApiConfig extends \Google\Protobuf\Internal\Message
13 | {
14 | /**
15 | * The channel pool configurations.
16 | *
17 | * Generated from protobuf field .grpc.gcp.ChannelPoolConfig channel_pool = 2;
18 | */
19 | private $channel_pool = null;
20 | /**
21 | * The method configurations.
22 | *
23 | * Generated from protobuf field repeated .grpc.gcp.MethodConfig method = 1001;
24 | */
25 | private $method;
26 |
27 | public function __construct()
28 | {
29 | \GPBMetadata\GrpcGcp::initOnce();
30 | parent::__construct();
31 | }
32 |
33 | /**
34 | * The channel pool configurations.
35 | *
36 | * Generated from protobuf field .grpc.gcp.ChannelPoolConfig channel_pool = 2;
37 | * @return \Grpc\Gcp\ChannelPoolConfig
38 | */
39 | public function getChannelPool()
40 | {
41 | return $this->channel_pool;
42 | }
43 |
44 | /**
45 | * The channel pool configurations.
46 | *
47 | * Generated from protobuf field .grpc.gcp.ChannelPoolConfig channel_pool = 2;
48 | * @param \Grpc\Gcp\ChannelPoolConfig $var
49 | * @return $this
50 | */
51 | public function setChannelPool($var)
52 | {
53 | GPBUtil::checkMessage($var, \Grpc\Gcp\ChannelPoolConfig::class);
54 | $this->channel_pool = $var;
55 |
56 | return $this;
57 | }
58 |
59 | /**
60 | * The method configurations.
61 | *
62 | * Generated from protobuf field repeated .grpc.gcp.MethodConfig method = 1001;
63 | * @return \Google\Protobuf\Internal\RepeatedField
64 | */
65 | public function getMethod()
66 | {
67 | return $this->method;
68 | }
69 |
70 | /**
71 | * The method configurations.
72 | *
73 | * Generated from protobuf field repeated .grpc.gcp.MethodConfig method = 1001;
74 | * @param \Grpc\Gcp\MethodConfig[]|\Google\Protobuf\Internal\RepeatedField $var
75 | * @return $this
76 | */
77 | public function setMethod($var)
78 | {
79 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \Grpc\Gcp\MethodConfig::class);
80 | $this->method = $arr;
81 |
82 | return $this;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/generated/Grpc/Gcp/ChannelPoolConfig.php:
--------------------------------------------------------------------------------
1 | grpc.gcp.ChannelPoolConfig
11 | */
12 | class ChannelPoolConfig extends \Google\Protobuf\Internal\Message
13 | {
14 | /**
15 | * The max number of channels in the pool.
16 | *
17 | * Generated from protobuf field uint32 max_size = 1;
18 | */
19 | private $max_size = 0;
20 | /**
21 | * The idle timeout (seconds) of channels without bound affinity sessions.
22 | *
23 | * Generated from protobuf field uint64 idle_timeout = 2;
24 | */
25 | private $idle_timeout = 0;
26 | /**
27 | * The low watermark of max number of concurrent streams in a channel.
28 | * New channel will be created once it get hit, until we reach the max size
29 | * of the channel pool.
30 | *
31 | * Generated from protobuf field uint32 max_concurrent_streams_low_watermark = 3;
32 | */
33 | private $max_concurrent_streams_low_watermark = 0;
34 |
35 | public function __construct()
36 | {
37 | \GPBMetadata\GrpcGcp::initOnce();
38 | parent::__construct();
39 | }
40 |
41 | /**
42 | * The max number of channels in the pool.
43 | *
44 | * Generated from protobuf field uint32 max_size = 1;
45 | * @return int
46 | */
47 | public function getMaxSize()
48 | {
49 | return $this->max_size;
50 | }
51 |
52 | /**
53 | * The max number of channels in the pool.
54 | *
55 | * Generated from protobuf field uint32 max_size = 1;
56 | * @param int $var
57 | * @return $this
58 | */
59 | public function setMaxSize($var)
60 | {
61 | GPBUtil::checkUint32($var);
62 | $this->max_size = $var;
63 |
64 | return $this;
65 | }
66 |
67 | /**
68 | * The idle timeout (seconds) of channels without bound affinity sessions.
69 | *
70 | * Generated from protobuf field uint64 idle_timeout = 2;
71 | * @return int|string
72 | */
73 | public function getIdleTimeout()
74 | {
75 | return $this->idle_timeout;
76 | }
77 |
78 | /**
79 | * The idle timeout (seconds) of channels without bound affinity sessions.
80 | *
81 | * Generated from protobuf field uint64 idle_timeout = 2;
82 | * @param int|string $var
83 | * @return $this
84 | */
85 | public function setIdleTimeout($var)
86 | {
87 | GPBUtil::checkUint64($var);
88 | $this->idle_timeout = $var;
89 |
90 | return $this;
91 | }
92 |
93 | /**
94 | * The low watermark of max number of concurrent streams in a channel.
95 | * New channel will be created once it get hit, until we reach the max size
96 | * of the channel pool.
97 | *
98 | * Generated from protobuf field uint32 max_concurrent_streams_low_watermark = 3;
99 | * @return int
100 | */
101 | public function getMaxConcurrentStreamsLowWatermark()
102 | {
103 | return $this->max_concurrent_streams_low_watermark;
104 | }
105 |
106 | /**
107 | * The low watermark of max number of concurrent streams in a channel.
108 | * New channel will be created once it get hit, until we reach the max size
109 | * of the channel pool.
110 | *
111 | * Generated from protobuf field uint32 max_concurrent_streams_low_watermark = 3;
112 | * @param int $var
113 | * @return $this
114 | */
115 | public function setMaxConcurrentStreamsLowWatermark($var)
116 | {
117 | GPBUtil::checkUint32($var);
118 | $this->max_concurrent_streams_low_watermark = $var;
119 |
120 | return $this;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/generated/Grpc/Gcp/MethodConfig.php:
--------------------------------------------------------------------------------
1 | grpc.gcp.MethodConfig
11 | */
12 | class MethodConfig extends \Google\Protobuf\Internal\Message
13 | {
14 | /**
15 | * A fully qualified name of a gRPC method, or a wildcard pattern ending
16 | * with .*, such as foo.bar.A, foo.bar.*. Method configs are evaluated
17 | * sequentially, and the first one takes precedence.
18 | *
19 | * Generated from protobuf field repeated string name = 1;
20 | */
21 | private $name;
22 | /**
23 | * The channel affinity configurations.
24 | *
25 | * Generated from protobuf field .grpc.gcp.AffinityConfig affinity = 1001;
26 | */
27 | private $affinity = null;
28 |
29 | public function __construct()
30 | {
31 | \GPBMetadata\GrpcGcp::initOnce();
32 | parent::__construct();
33 | }
34 |
35 | /**
36 | * A fully qualified name of a gRPC method, or a wildcard pattern ending
37 | * with .*, such as foo.bar.A, foo.bar.*. Method configs are evaluated
38 | * sequentially, and the first one takes precedence.
39 | *
40 | * Generated from protobuf field repeated string name = 1;
41 | * @return \Google\Protobuf\Internal\RepeatedField
42 | */
43 | public function getName()
44 | {
45 | return $this->name;
46 | }
47 |
48 | /**
49 | * A fully qualified name of a gRPC method, or a wildcard pattern ending
50 | * with .*, such as foo.bar.A, foo.bar.*. Method configs are evaluated
51 | * sequentially, and the first one takes precedence.
52 | *
53 | * Generated from protobuf field repeated string name = 1;
54 | * @param string[]|\Google\Protobuf\Internal\RepeatedField $var
55 | * @return $this
56 | */
57 | public function setName($var)
58 | {
59 | $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::STRING);
60 | $this->name = $arr;
61 |
62 | return $this;
63 | }
64 |
65 | /**
66 | * The channel affinity configurations.
67 | *
68 | * Generated from protobuf field .grpc.gcp.AffinityConfig affinity = 1001;
69 | * @return \Grpc\Gcp\AffinityConfig
70 | */
71 | public function getAffinity()
72 | {
73 | return $this->affinity;
74 | }
75 |
76 | /**
77 | * The channel affinity configurations.
78 | *
79 | * Generated from protobuf field .grpc.gcp.AffinityConfig affinity = 1001;
80 | * @param \Grpc\Gcp\AffinityConfig $var
81 | * @return $this
82 | */
83 | public function setAffinity($var)
84 | {
85 | GPBUtil::checkMessage($var, \Grpc\Gcp\AffinityConfig::class);
86 | $this->affinity = $var;
87 |
88 | return $this;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/grpc_gcp.proto:
--------------------------------------------------------------------------------
1 | // Copyright 2018 gRPC authors.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | syntax = "proto3";
16 |
17 | package grpc.gcp;
18 |
19 | message ApiConfig {
20 | // The channel pool configurations.
21 | ChannelPoolConfig channel_pool = 2;
22 |
23 | // The method configurations.
24 | repeated MethodConfig method = 1001;
25 | }
26 |
27 | message ChannelPoolConfig {
28 | // The max number of channels in the pool.
29 | uint32 max_size = 1;
30 | // The idle timeout (seconds) of channels without bound affinity sessions.
31 | uint64 idle_timeout = 2;
32 | // The low watermark of max number of concurrent streams in a channel.
33 | // New channel will be created once it get hit, until we reach the max size
34 | // of the channel pool.
35 | uint32 max_concurrent_streams_low_watermark = 3;
36 | }
37 |
38 | message MethodConfig {
39 | // A fully qualified name of a gRPC method, or a wildcard pattern ending
40 | // with .*, such as foo.bar.A, foo.bar.*. Method configs are evaluated
41 | // sequentially, and the first one takes precedence.
42 | repeated string name = 1;
43 |
44 | // The channel affinity configurations.
45 | AffinityConfig affinity = 1001;
46 | }
47 |
48 | message AffinityConfig {
49 | enum Command {
50 | // The annotated method will be required to be bound to an existing session
51 | // to execute the RPC. The corresponding will be
52 | // used to find the affinity key from the request message.
53 | BOUND = 0;
54 | // The annotated method will establish the channel affinity with the channel
55 | // which is used to execute the RPC. The corresponding
56 | // will be used to find the affinity key from the
57 | // response message.
58 | BIND = 1;
59 | // The annotated method will remove the channel affinity with the channel
60 | // which is used to execute the RPC. The corresponding
61 | // will be used to find the affinity key from the
62 | // request message.
63 | UNBIND = 2;
64 | }
65 | // The affinity command applies on the selected gRPC methods.
66 | Command command = 2;
67 | // The field path of the affinity key in the request/response message.
68 | // For example: "f.a", "f.b.d", etc.
69 | string affinity_key = 3;
70 | }
71 |
--------------------------------------------------------------------------------