blob: d0baeae955bb4a07a807861e8db1df054fe0be5e [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 /**
Stanislav Pavlovichev4407a942016-10-27 10:35:08 +0700119 * @param int $timeout in microseconds
Stanley Cheungd5b20562015-10-27 13:27:05 -0700120 *
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 }
thinkerou9392b042016-09-09 17:43:00 +0800185
Stanley Cheungcde12a52016-09-01 22:03:20 -0700186 return 'https://'.$hostname.$service_name;
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700187 }
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700188
Stanley Cheungd5b20562015-10-27 13:27:05 -0700189 /**
Stanley Cheungd5b20562015-10-27 13:27:05 -0700190 * validate and normalize the metadata array.
191 *
Stanislav Pavlovichev4407a942016-10-27 10:35:08 +0700192 * @param array $metadata The metadata map
Stanley Cheungd5b20562015-10-27 13:27:05 -0700193 *
194 * @return $metadata Validated and key-normalized metadata map
195 * @throw InvalidArgumentException if key contains invalid characters
196 */
197 private function _validate_and_normalize_metadata($metadata)
198 {
199 $metadata_copy = [];
200 foreach ($metadata as $key => $value) {
201 if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
202 throw new \InvalidArgumentException(
203 'Metadata keys must be nonempty strings containing only '.
204 'alphanumeric characters, hyphens and underscores');
205 }
206 $metadata_copy[strtolower($key)] = $value;
207 }
208
209 return $metadata_copy;
210 }
211
212 /* This class is intended to be subclassed by generated code, so
213 * all functions begin with "_" to avoid name collisions. */
214
215 /**
216 * Call a remote method that takes a single argument and has a
217 * single output.
218 *
Stanislav Pavlovichev4407a942016-10-27 10:35:08 +0700219 * @param string $method The name of the method to call
220 * @param mixed $argument The argument to the method
Stanley Cheungd5b20562015-10-27 13:27:05 -0700221 * @param callable $deserialize A function that deserializes the response
222 * @param array $metadata A metadata map to send to the server
223 *
224 * @return SimpleSurfaceActiveCall The active call object
225 */
226 public function _simpleRequest($method,
227 $argument,
Parker Moore513a6882015-12-01 16:59:49 -0800228 $deserialize,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700229 $metadata = [],
230 $options = [])
231 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700232 $call = new UnaryCall($this->channel,
233 $method,
234 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800235 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700236 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
237 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800238 $metadata = call_user_func($this->update_metadata,
239 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700240 $jwt_aud_uri);
241 }
Stanley Cheung35805802015-12-10 11:42:55 -0800242 $metadata = $this->_validate_and_normalize_metadata(
243 $metadata);
244 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700245
246 return $call;
247 }
248
249 /**
250 * Call a remote method that takes a stream of arguments and has a single
251 * output.
252 *
Stanislav Pavlovichev4407a942016-10-27 10:35:08 +0700253 * @param string $method The name of the method to call
254 * @param array $arguments An array or Traversable of arguments to stream to the
thinkerou9a669b62016-11-01 21:31:43 +0800255 * server
Stanley Cheungd5b20562015-10-27 13:27:05 -0700256 * @param callable $deserialize A function that deserializes the response
257 * @param array $metadata A metadata map to send to the server
258 *
259 * @return ClientStreamingSurfaceActiveCall The active call object
260 */
261 public function _clientStreamRequest($method,
262 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800263 $metadata = [],
264 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700265 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700266 $call = new ClientStreamingCall($this->channel,
267 $method,
268 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800269 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700270 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
271 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800272 $metadata = call_user_func($this->update_metadata,
273 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700274 $jwt_aud_uri);
275 }
Stanley Cheung35805802015-12-10 11:42:55 -0800276 $metadata = $this->_validate_and_normalize_metadata(
277 $metadata);
278 $call->start($metadata);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700279
280 return $call;
281 }
282
283 /**
284 * Call a remote method that takes a single argument and returns a stream of
285 * responses.
286 *
Stanislav Pavlovichev4407a942016-10-27 10:35:08 +0700287 * @param string $method The name of the method to call
288 * @param mixed $argument The argument to the method
Stanley Cheungd5b20562015-10-27 13:27:05 -0700289 * @param callable $deserialize A function that deserializes the responses
290 * @param array $metadata A metadata map to send to the server
291 *
292 * @return ServerStreamingSurfaceActiveCall The active call object
293 */
294 public function _serverStreamRequest($method,
295 $argument,
296 callable $deserialize,
297 $metadata = [],
298 $options = [])
299 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700300 $call = new ServerStreamingCall($this->channel,
301 $method,
302 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800303 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700304 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
305 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800306 $metadata = call_user_func($this->update_metadata,
307 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700308 $jwt_aud_uri);
309 }
Stanley Cheung35805802015-12-10 11:42:55 -0800310 $metadata = $this->_validate_and_normalize_metadata(
311 $metadata);
312 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700313
314 return $call;
315 }
316
317 /**
318 * Call a remote method with messages streaming in both directions.
319 *
320 * @param string $method The name of the method to call
321 * @param callable $deserialize A function that deserializes the responses
322 * @param array $metadata A metadata map to send to the server
323 *
324 * @return BidiStreamingSurfaceActiveCall The active call object
325 */
326 public function _bidiRequest($method,
murgatroid9914d2ce22015-01-30 15:36:23 -0800327 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800328 $metadata = [],
329 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700330 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700331 $call = new BidiStreamingCall($this->channel,
332 $method,
333 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800334 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700335 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
336 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800337 $metadata = call_user_func($this->update_metadata,
338 $metadata,
Stanley Cheungf4206872015-05-12 17:39:30 -0700339 $jwt_aud_uri);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700340 }
Stanley Cheung35805802015-12-10 11:42:55 -0800341 $metadata = $this->_validate_and_normalize_metadata(
342 $metadata);
343 $call->start($metadata);
mlumishb892a272014-12-09 16:28:23 -0800344
Stanley Cheungd5b20562015-10-27 13:27:05 -0700345 return $call;
Stanley Cheung2c9c7632015-04-20 14:13:54 -0700346 }
mlumishb892a272014-12-09 16:28:23 -0800347}