blob: 70644fac87259ad6d056c2eeeff8827087a63bf2 [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;
44 private $channel;
mlumishb892a272014-12-09 16:28:23 -080045
Stanley Cheungd5b20562015-10-27 13:27:05 -070046 // a callback function
47 private $update_metadata;
mlumishb892a272014-12-09 16:28:23 -080048
Stanley Cheungd5b20562015-10-27 13:27:05 -070049 /**
50 * @param $hostname string
51 * @param $opts array
52 * - 'update_metadata': (optional) a callback function which takes in a
53 * metadata array, and returns an updated metadata array
Stanley Cheung3baf7672015-11-08 18:16:58 -080054 * - 'grpc.primary_user_agent': (optional) a user-agent string
Stanley Cheunge05d3192016-05-18 15:06:39 -070055 * @param $channel Channel An already created Channel object
Stanley Cheungd5b20562015-10-27 13:27:05 -070056 */
Stanley Cheunge05d3192016-05-18 15:06:39 -070057 public function __construct($hostname, $opts, $channel = null)
Stanley Cheungd5b20562015-10-27 13:27:05 -070058 {
59 $this->hostname = $hostname;
60 $this->update_metadata = null;
61 if (isset($opts['update_metadata'])) {
62 if (is_callable($opts['update_metadata'])) {
63 $this->update_metadata = $opts['update_metadata'];
64 }
65 unset($opts['update_metadata']);
66 }
67 $package_config = json_decode(
68 file_get_contents(dirname(__FILE__).'/../../composer.json'), true);
Stanley Cheung3baf7672015-11-08 18:16:58 -080069 if (!empty($opts['grpc.primary_user_agent'])) {
70 $opts['grpc.primary_user_agent'] .= ' ';
71 } else {
72 $opts['grpc.primary_user_agent'] = '';
73 }
74 $opts['grpc.primary_user_agent'] .=
Stanley Cheungd5b20562015-10-27 13:27:05 -070075 'grpc-php/'.$package_config['version'];
Stanley Cheung6bd31802015-12-16 12:58:19 -080076 if (!array_key_exists('credentials', $opts)) {
77 throw new \Exception("The opts['credentials'] key is now ".
78 'required. Please see one of the '.
79 'ChannelCredentials::create methods');
80 }
Stanley Cheunge05d3192016-05-18 15:06:39 -070081 if ($channel) {
82 if (!is_a($channel, 'Channel')) {
83 throw new \Exception("The channel argument is not a".
84 "Channel object");
85 }
86 $this->channel = $channel;
87 } else {
88 $this->channel = new Channel($hostname, $opts);
89 }
Stanley Cheung04b7a412015-08-13 09:39:04 -070090 }
91
Stanley Cheungd5b20562015-10-27 13:27:05 -070092 /**
93 * @return string The URI of the endpoint.
94 */
95 public function getTarget()
96 {
97 return $this->channel->getTarget();
Stanley Cheung04b7a412015-08-13 09:39:04 -070098 }
Stanley Cheung04b7a412015-08-13 09:39:04 -070099
Stanley Cheungd5b20562015-10-27 13:27:05 -0700100 /**
101 * @param $try_to_connect bool
102 *
103 * @return int The grpc connectivity state
104 */
105 public function getConnectivityState($try_to_connect = false)
106 {
107 return $this->channel->getConnectivityState($try_to_connect);
Stanley Cheung04b7a412015-08-13 09:39:04 -0700108 }
Stanley Cheungd5b20562015-10-27 13:27:05 -0700109
110 /**
111 * @param $timeout in microseconds
112 *
113 * @return bool true if channel is ready
114 * @throw Exception if channel is in FATAL_ERROR state
115 */
116 public function waitForReady($timeout)
117 {
118 $new_state = $this->getConnectivityState(true);
119 if ($this->_checkConnectivityState($new_state)) {
120 return true;
121 }
122
123 $now = Timeval::now();
124 $delta = new Timeval($timeout);
125 $deadline = $now->add($delta);
126
127 while ($this->channel->watchConnectivityState($new_state, $deadline)) {
128 // state has changed before deadline
129 $new_state = $this->getConnectivityState();
130 if ($this->_checkConnectivityState($new_state)) {
131 return true;
132 }
133 }
134 // deadline has passed
135 $new_state = $this->getConnectivityState();
136
137 return $this->_checkConnectivityState($new_state);
Stanley Cheung04b7a412015-08-13 09:39:04 -0700138 }
Stanley Cheung04b7a412015-08-13 09:39:04 -0700139
Stanley Cheungd5b20562015-10-27 13:27:05 -0700140 private function _checkConnectivityState($new_state)
141 {
142 if ($new_state == \Grpc\CHANNEL_READY) {
143 return true;
144 }
145 if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
146 throw new \Exception('Failed to connect to server');
147 }
mlumishb892a272014-12-09 16:28:23 -0800148
Stanley Cheungd5b20562015-10-27 13:27:05 -0700149 return false;
Stanley Cheungf4206872015-05-12 17:39:30 -0700150 }
Stanley Cheungf4206872015-05-12 17:39:30 -0700151
Stanley Cheungd5b20562015-10-27 13:27:05 -0700152 /**
153 * Close the communication channel associated with this stub.
154 */
155 public function close()
156 {
157 $this->channel->close();
Stanley Cheungcc019af2015-06-15 11:45:00 -0700158 }
Stanley Cheungcc019af2015-06-15 11:45:00 -0700159
Stanley Cheungd5b20562015-10-27 13:27:05 -0700160 /**
161 * constructs the auth uri for the jwt.
162 */
163 private function _get_jwt_aud_uri($method)
164 {
165 $last_slash_idx = strrpos($method, '/');
166 if ($last_slash_idx === false) {
167 throw new \InvalidArgumentException(
168 'service name must have a slash');
169 }
170 $service_name = substr($method, 0, $last_slash_idx);
171
172 return 'https://'.$this->hostname.$service_name;
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700173 }
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700174
Stanley Cheungd5b20562015-10-27 13:27:05 -0700175 /**
Stanley Cheungd5b20562015-10-27 13:27:05 -0700176 * validate and normalize the metadata array.
177 *
178 * @param $metadata The metadata map
179 *
180 * @return $metadata Validated and key-normalized metadata map
181 * @throw InvalidArgumentException if key contains invalid characters
182 */
183 private function _validate_and_normalize_metadata($metadata)
184 {
185 $metadata_copy = [];
186 foreach ($metadata as $key => $value) {
187 if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
188 throw new \InvalidArgumentException(
189 'Metadata keys must be nonempty strings containing only '.
190 'alphanumeric characters, hyphens and underscores');
191 }
192 $metadata_copy[strtolower($key)] = $value;
193 }
194
195 return $metadata_copy;
196 }
197
198 /* This class is intended to be subclassed by generated code, so
199 * all functions begin with "_" to avoid name collisions. */
200
201 /**
202 * Call a remote method that takes a single argument and has a
203 * single output.
204 *
205 * @param string $method The name of the method to call
206 * @param $argument The argument to the method
207 * @param callable $deserialize A function that deserializes the response
208 * @param array $metadata A metadata map to send to the server
209 *
210 * @return SimpleSurfaceActiveCall The active call object
211 */
212 public function _simpleRequest($method,
213 $argument,
Parker Moore513a6882015-12-01 16:59:49 -0800214 $deserialize,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700215 $metadata = [],
216 $options = [])
217 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700218 $call = new UnaryCall($this->channel,
219 $method,
220 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800221 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700222 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
223 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800224 $metadata = call_user_func($this->update_metadata,
225 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700226 $jwt_aud_uri);
227 }
Stanley Cheung35805802015-12-10 11:42:55 -0800228 $metadata = $this->_validate_and_normalize_metadata(
229 $metadata);
230 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700231
232 return $call;
233 }
234
235 /**
236 * Call a remote method that takes a stream of arguments and has a single
237 * output.
238 *
239 * @param string $method The name of the method to call
240 * @param $arguments An array or Traversable of arguments to stream to the
241 * server
242 * @param callable $deserialize A function that deserializes the response
243 * @param array $metadata A metadata map to send to the server
244 *
245 * @return ClientStreamingSurfaceActiveCall The active call object
246 */
247 public function _clientStreamRequest($method,
248 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800249 $metadata = [],
250 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700251 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700252 $call = new ClientStreamingCall($this->channel,
253 $method,
254 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800255 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700256 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
257 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800258 $metadata = call_user_func($this->update_metadata,
259 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700260 $jwt_aud_uri);
261 }
Stanley Cheung35805802015-12-10 11:42:55 -0800262 $metadata = $this->_validate_and_normalize_metadata(
263 $metadata);
264 $call->start($metadata);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700265
266 return $call;
267 }
268
269 /**
270 * Call a remote method that takes a single argument and returns a stream of
271 * responses.
272 *
273 * @param string $method The name of the method to call
274 * @param $argument The argument to the method
275 * @param callable $deserialize A function that deserializes the responses
276 * @param array $metadata A metadata map to send to the server
277 *
278 * @return ServerStreamingSurfaceActiveCall The active call object
279 */
280 public function _serverStreamRequest($method,
281 $argument,
282 callable $deserialize,
283 $metadata = [],
284 $options = [])
285 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700286 $call = new ServerStreamingCall($this->channel,
287 $method,
288 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800289 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700290 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
291 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800292 $metadata = call_user_func($this->update_metadata,
293 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700294 $jwt_aud_uri);
295 }
Stanley Cheung35805802015-12-10 11:42:55 -0800296 $metadata = $this->_validate_and_normalize_metadata(
297 $metadata);
298 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700299
300 return $call;
301 }
302
303 /**
304 * Call a remote method with messages streaming in both directions.
305 *
306 * @param string $method The name of the method to call
307 * @param callable $deserialize A function that deserializes the responses
308 * @param array $metadata A metadata map to send to the server
309 *
310 * @return BidiStreamingSurfaceActiveCall The active call object
311 */
312 public function _bidiRequest($method,
murgatroid9914d2ce22015-01-30 15:36:23 -0800313 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800314 $metadata = [],
315 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700316 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700317 $call = new BidiStreamingCall($this->channel,
318 $method,
319 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800320 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700321 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
322 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800323 $metadata = call_user_func($this->update_metadata,
324 $metadata,
Stanley Cheungf4206872015-05-12 17:39:30 -0700325 $jwt_aud_uri);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700326 }
Stanley Cheung35805802015-12-10 11:42:55 -0800327 $metadata = $this->_validate_and_normalize_metadata(
328 $metadata);
329 $call->start($metadata);
mlumishb892a272014-12-09 16:28:23 -0800330
Stanley Cheungd5b20562015-10-27 13:27:05 -0700331 return $call;
Stanley Cheung2c9c7632015-04-20 14:13:54 -0700332 }
mlumishb892a272014-12-09 16:28:23 -0800333}