blob: d850eebc78890ed1a3a194779a8492e93388bddf [file] [log] [blame]
mlumishb892a272014-12-09 16:28:23 -08001<?php
Craig Tiller2e498aa2015-02-16 12:09:31 -08002/*
3 *
4 * Copyright 2015, Google Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following disclaimer
15 * in the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Google Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
Stanley Cheungd5b20562015-10-27 13:27:05 -070034
mlumishb892a272014-12-09 16:28:23 -080035namespace Grpc;
mlumishb892a272014-12-09 16:28:23 -080036
37/**
38 * Base class for generated client stubs. Stub methods are expected to call
39 * _simpleRequest or _streamRequest and return the result.
40 */
Stanley Cheungd5b20562015-10-27 13:27:05 -070041class BaseStub
42{
43 private $hostname;
Stanley Cheungcde12a52016-09-01 22:03:20 -070044 private $hostname_override;
Stanley Cheungd5b20562015-10-27 13:27:05 -070045 private $channel;
mlumishb892a272014-12-09 16:28:23 -080046
Stanley Cheungd5b20562015-10-27 13:27:05 -070047 // a callback function
48 private $update_metadata;
mlumishb892a272014-12-09 16:28:23 -080049
Stanley Cheungd5b20562015-10-27 13:27:05 -070050 /**
51 * @param $hostname string
52 * @param $opts array
53 * - 'update_metadata': (optional) a callback function which takes in a
54 * metadata array, and returns an updated metadata array
Stanley Cheung3baf7672015-11-08 18:16:58 -080055 * - 'grpc.primary_user_agent': (optional) a user-agent string
Stanley Cheunge05d3192016-05-18 15:06:39 -070056 * @param $channel Channel An already created Channel object
Stanley Cheungd5b20562015-10-27 13:27:05 -070057 */
Stanley Cheunge05d3192016-05-18 15:06:39 -070058 public function __construct($hostname, $opts, $channel = null)
Stanley Cheungd5b20562015-10-27 13:27:05 -070059 {
thinkerouf3bc3b62016-06-09 11:57:15 +080060 $ssl_roots = file_get_contents(
61 dirname(__FILE__).'/../../../../etc/roots.pem');
62 ChannelCredentials::setDefaultRootsPem($ssl_roots);
63
Stanley Cheungd5b20562015-10-27 13:27:05 -070064 $this->hostname = $hostname;
65 $this->update_metadata = null;
66 if (isset($opts['update_metadata'])) {
67 if (is_callable($opts['update_metadata'])) {
68 $this->update_metadata = $opts['update_metadata'];
69 }
70 unset($opts['update_metadata']);
71 }
72 $package_config = json_decode(
73 file_get_contents(dirname(__FILE__).'/../../composer.json'), true);
Stanley Cheung3baf7672015-11-08 18:16:58 -080074 if (!empty($opts['grpc.primary_user_agent'])) {
75 $opts['grpc.primary_user_agent'] .= ' ';
76 } else {
77 $opts['grpc.primary_user_agent'] = '';
78 }
Stanley Cheungcde12a52016-09-01 22:03:20 -070079 if (!empty($opts['grpc.ssl_target_name_override'])) {
80 $this->hostname_override = $opts['grpc.ssl_target_name_override'];
81 }
Stanley Cheung3baf7672015-11-08 18:16:58 -080082 $opts['grpc.primary_user_agent'] .=
Stanley Cheungd5b20562015-10-27 13:27:05 -070083 'grpc-php/'.$package_config['version'];
Stanley Cheung6bd31802015-12-16 12:58:19 -080084 if (!array_key_exists('credentials', $opts)) {
85 throw new \Exception("The opts['credentials'] key is now ".
86 'required. Please see one of the '.
87 'ChannelCredentials::create methods');
88 }
Stanley Cheunge05d3192016-05-18 15:06:39 -070089 if ($channel) {
90 if (!is_a($channel, 'Channel')) {
thinkeroua3730b72016-07-20 16:59:54 +080091 throw new \Exception('The channel argument is not a'.
92 'Channel object');
Stanley Cheunge05d3192016-05-18 15:06:39 -070093 }
94 $this->channel = $channel;
95 } else {
96 $this->channel = new Channel($hostname, $opts);
97 }
Stanley Cheung04b7a412015-08-13 09:39:04 -070098 }
99
Stanley Cheungd5b20562015-10-27 13:27:05 -0700100 /**
101 * @return string The URI of the endpoint.
102 */
103 public function getTarget()
104 {
105 return $this->channel->getTarget();
Stanley Cheung04b7a412015-08-13 09:39:04 -0700106 }
Stanley Cheung04b7a412015-08-13 09:39:04 -0700107
Stanley Cheungd5b20562015-10-27 13:27:05 -0700108 /**
109 * @param $try_to_connect bool
110 *
111 * @return int The grpc connectivity state
112 */
113 public function getConnectivityState($try_to_connect = false)
114 {
115 return $this->channel->getConnectivityState($try_to_connect);
Stanley Cheung04b7a412015-08-13 09:39:04 -0700116 }
Stanley Cheungd5b20562015-10-27 13:27:05 -0700117
118 /**
119 * @param $timeout in microseconds
120 *
121 * @return bool true if channel is ready
122 * @throw Exception if channel is in FATAL_ERROR state
123 */
124 public function waitForReady($timeout)
125 {
126 $new_state = $this->getConnectivityState(true);
127 if ($this->_checkConnectivityState($new_state)) {
128 return true;
129 }
130
131 $now = Timeval::now();
132 $delta = new Timeval($timeout);
133 $deadline = $now->add($delta);
134
135 while ($this->channel->watchConnectivityState($new_state, $deadline)) {
136 // state has changed before deadline
137 $new_state = $this->getConnectivityState();
138 if ($this->_checkConnectivityState($new_state)) {
139 return true;
140 }
141 }
142 // deadline has passed
143 $new_state = $this->getConnectivityState();
144
145 return $this->_checkConnectivityState($new_state);
Stanley Cheung04b7a412015-08-13 09:39:04 -0700146 }
Stanley Cheung04b7a412015-08-13 09:39:04 -0700147
Stanley Cheungd5b20562015-10-27 13:27:05 -0700148 private function _checkConnectivityState($new_state)
149 {
150 if ($new_state == \Grpc\CHANNEL_READY) {
151 return true;
152 }
153 if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
154 throw new \Exception('Failed to connect to server');
155 }
mlumishb892a272014-12-09 16:28:23 -0800156
Stanley Cheungd5b20562015-10-27 13:27:05 -0700157 return false;
Stanley Cheungf4206872015-05-12 17:39:30 -0700158 }
Stanley Cheungf4206872015-05-12 17:39:30 -0700159
Stanley Cheungd5b20562015-10-27 13:27:05 -0700160 /**
161 * Close the communication channel associated with this stub.
162 */
163 public function close()
164 {
165 $this->channel->close();
Stanley Cheungcc019af2015-06-15 11:45:00 -0700166 }
Stanley Cheungcc019af2015-06-15 11:45:00 -0700167
Stanley Cheungd5b20562015-10-27 13:27:05 -0700168 /**
169 * constructs the auth uri for the jwt.
170 */
171 private function _get_jwt_aud_uri($method)
172 {
173 $last_slash_idx = strrpos($method, '/');
174 if ($last_slash_idx === false) {
175 throw new \InvalidArgumentException(
176 'service name must have a slash');
177 }
178 $service_name = substr($method, 0, $last_slash_idx);
179
Stanley Cheungcde12a52016-09-01 22:03:20 -0700180 if ($this->hostname_override) {
181 $hostname = $this->hostname_override;
182 } else {
183 $hostname = $this->hostname;
184 }
185 return 'https://'.$hostname.$service_name;
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700186 }
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700187
Stanley Cheungd5b20562015-10-27 13:27:05 -0700188 /**
Stanley Cheungd5b20562015-10-27 13:27:05 -0700189 * validate and normalize the metadata array.
190 *
191 * @param $metadata The metadata map
192 *
193 * @return $metadata Validated and key-normalized metadata map
194 * @throw InvalidArgumentException if key contains invalid characters
195 */
196 private function _validate_and_normalize_metadata($metadata)
197 {
198 $metadata_copy = [];
199 foreach ($metadata as $key => $value) {
200 if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
201 throw new \InvalidArgumentException(
202 'Metadata keys must be nonempty strings containing only '.
203 'alphanumeric characters, hyphens and underscores');
204 }
205 $metadata_copy[strtolower($key)] = $value;
206 }
207
208 return $metadata_copy;
209 }
210
211 /* This class is intended to be subclassed by generated code, so
212 * all functions begin with "_" to avoid name collisions. */
213
214 /**
215 * Call a remote method that takes a single argument and has a
216 * single output.
217 *
218 * @param string $method The name of the method to call
219 * @param $argument The argument to the method
220 * @param callable $deserialize A function that deserializes the response
221 * @param array $metadata A metadata map to send to the server
222 *
223 * @return SimpleSurfaceActiveCall The active call object
224 */
225 public function _simpleRequest($method,
226 $argument,
Parker Moore513a6882015-12-01 16:59:49 -0800227 $deserialize,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700228 $metadata = [],
229 $options = [])
230 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700231 $call = new UnaryCall($this->channel,
232 $method,
233 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800234 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700235 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
236 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800237 $metadata = call_user_func($this->update_metadata,
238 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700239 $jwt_aud_uri);
240 }
Stanley Cheung35805802015-12-10 11:42:55 -0800241 $metadata = $this->_validate_and_normalize_metadata(
242 $metadata);
243 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700244
245 return $call;
246 }
247
248 /**
249 * Call a remote method that takes a stream of arguments and has a single
250 * output.
251 *
252 * @param string $method The name of the method to call
253 * @param $arguments An array or Traversable of arguments to stream to the
254 * server
255 * @param callable $deserialize A function that deserializes the response
256 * @param array $metadata A metadata map to send to the server
257 *
258 * @return ClientStreamingSurfaceActiveCall The active call object
259 */
260 public function _clientStreamRequest($method,
261 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800262 $metadata = [],
263 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700264 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700265 $call = new ClientStreamingCall($this->channel,
266 $method,
267 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800268 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700269 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
270 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800271 $metadata = call_user_func($this->update_metadata,
272 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700273 $jwt_aud_uri);
274 }
Stanley Cheung35805802015-12-10 11:42:55 -0800275 $metadata = $this->_validate_and_normalize_metadata(
276 $metadata);
277 $call->start($metadata);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700278
279 return $call;
280 }
281
282 /**
283 * Call a remote method that takes a single argument and returns a stream of
284 * responses.
285 *
286 * @param string $method The name of the method to call
287 * @param $argument The argument to the method
288 * @param callable $deserialize A function that deserializes the responses
289 * @param array $metadata A metadata map to send to the server
290 *
291 * @return ServerStreamingSurfaceActiveCall The active call object
292 */
293 public function _serverStreamRequest($method,
294 $argument,
295 callable $deserialize,
296 $metadata = [],
297 $options = [])
298 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700299 $call = new ServerStreamingCall($this->channel,
300 $method,
301 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800302 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700303 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
304 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800305 $metadata = call_user_func($this->update_metadata,
306 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700307 $jwt_aud_uri);
308 }
Stanley Cheung35805802015-12-10 11:42:55 -0800309 $metadata = $this->_validate_and_normalize_metadata(
310 $metadata);
311 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700312
313 return $call;
314 }
315
316 /**
317 * Call a remote method with messages streaming in both directions.
318 *
319 * @param string $method The name of the method to call
320 * @param callable $deserialize A function that deserializes the responses
321 * @param array $metadata A metadata map to send to the server
322 *
323 * @return BidiStreamingSurfaceActiveCall The active call object
324 */
325 public function _bidiRequest($method,
murgatroid9914d2ce22015-01-30 15:36:23 -0800326 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800327 $metadata = [],
328 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700329 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700330 $call = new BidiStreamingCall($this->channel,
331 $method,
332 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800333 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700334 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
335 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800336 $metadata = call_user_func($this->update_metadata,
337 $metadata,
Stanley Cheungf4206872015-05-12 17:39:30 -0700338 $jwt_aud_uri);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700339 }
Stanley Cheung35805802015-12-10 11:42:55 -0800340 $metadata = $this->_validate_and_normalize_metadata(
341 $metadata);
342 $call->start($metadata);
mlumishb892a272014-12-09 16:28:23 -0800343
Stanley Cheungd5b20562015-10-27 13:27:05 -0700344 return $call;
Stanley Cheung2c9c7632015-04-20 14:13:54 -0700345 }
mlumishb892a272014-12-09 16:28:23 -0800346}