blob: 2de1b337e53260a458f489a5725abf853ebfcbac [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 Cheungd5b20562015-10-27 13:27:05 -070055 */
56 public function __construct($hostname, $opts)
57 {
58 $this->hostname = $hostname;
59 $this->update_metadata = null;
60 if (isset($opts['update_metadata'])) {
61 if (is_callable($opts['update_metadata'])) {
62 $this->update_metadata = $opts['update_metadata'];
63 }
64 unset($opts['update_metadata']);
65 }
66 $package_config = json_decode(
67 file_get_contents(dirname(__FILE__).'/../../composer.json'), true);
Stanley Cheung3baf7672015-11-08 18:16:58 -080068 if (!empty($opts['grpc.primary_user_agent'])) {
69 $opts['grpc.primary_user_agent'] .= ' ';
70 } else {
71 $opts['grpc.primary_user_agent'] = '';
72 }
73 $opts['grpc.primary_user_agent'] .=
Stanley Cheungd5b20562015-10-27 13:27:05 -070074 'grpc-php/'.$package_config['version'];
Stanley Cheung6bd31802015-12-16 12:58:19 -080075 if (!array_key_exists('credentials', $opts)) {
76 throw new \Exception("The opts['credentials'] key is now ".
77 'required. Please see one of the '.
78 'ChannelCredentials::create methods');
79 }
Stanley Cheungd5b20562015-10-27 13:27:05 -070080 $this->channel = new Channel($hostname, $opts);
Stanley Cheung04b7a412015-08-13 09:39:04 -070081 }
82
Stanley Cheungd5b20562015-10-27 13:27:05 -070083 /**
84 * @return string The URI of the endpoint.
85 */
86 public function getTarget()
87 {
88 return $this->channel->getTarget();
Stanley Cheung04b7a412015-08-13 09:39:04 -070089 }
Stanley Cheung04b7a412015-08-13 09:39:04 -070090
Stanley Cheungd5b20562015-10-27 13:27:05 -070091 /**
92 * @param $try_to_connect bool
93 *
94 * @return int The grpc connectivity state
95 */
96 public function getConnectivityState($try_to_connect = false)
97 {
98 return $this->channel->getConnectivityState($try_to_connect);
Stanley Cheung04b7a412015-08-13 09:39:04 -070099 }
Stanley Cheungd5b20562015-10-27 13:27:05 -0700100
101 /**
102 * @param $timeout in microseconds
103 *
104 * @return bool true if channel is ready
105 * @throw Exception if channel is in FATAL_ERROR state
106 */
107 public function waitForReady($timeout)
108 {
109 $new_state = $this->getConnectivityState(true);
110 if ($this->_checkConnectivityState($new_state)) {
111 return true;
112 }
113
114 $now = Timeval::now();
115 $delta = new Timeval($timeout);
116 $deadline = $now->add($delta);
117
118 while ($this->channel->watchConnectivityState($new_state, $deadline)) {
119 // state has changed before deadline
120 $new_state = $this->getConnectivityState();
121 if ($this->_checkConnectivityState($new_state)) {
122 return true;
123 }
124 }
125 // deadline has passed
126 $new_state = $this->getConnectivityState();
127
128 return $this->_checkConnectivityState($new_state);
Stanley Cheung04b7a412015-08-13 09:39:04 -0700129 }
Stanley Cheung04b7a412015-08-13 09:39:04 -0700130
Stanley Cheungd5b20562015-10-27 13:27:05 -0700131 private function _checkConnectivityState($new_state)
132 {
133 if ($new_state == \Grpc\CHANNEL_READY) {
134 return true;
135 }
136 if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
137 throw new \Exception('Failed to connect to server');
138 }
mlumishb892a272014-12-09 16:28:23 -0800139
Stanley Cheungd5b20562015-10-27 13:27:05 -0700140 return false;
Stanley Cheungf4206872015-05-12 17:39:30 -0700141 }
Stanley Cheungf4206872015-05-12 17:39:30 -0700142
Stanley Cheungd5b20562015-10-27 13:27:05 -0700143 /**
144 * Close the communication channel associated with this stub.
145 */
146 public function close()
147 {
148 $this->channel->close();
Stanley Cheungcc019af2015-06-15 11:45:00 -0700149 }
Stanley Cheungcc019af2015-06-15 11:45:00 -0700150
Stanley Cheungd5b20562015-10-27 13:27:05 -0700151 /**
152 * constructs the auth uri for the jwt.
153 */
154 private function _get_jwt_aud_uri($method)
155 {
156 $last_slash_idx = strrpos($method, '/');
157 if ($last_slash_idx === false) {
158 throw new \InvalidArgumentException(
159 'service name must have a slash');
160 }
161 $service_name = substr($method, 0, $last_slash_idx);
162
163 return 'https://'.$this->hostname.$service_name;
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700164 }
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700165
Stanley Cheungd5b20562015-10-27 13:27:05 -0700166 /**
Stanley Cheungd5b20562015-10-27 13:27:05 -0700167 * validate and normalize the metadata array.
168 *
169 * @param $metadata The metadata map
170 *
171 * @return $metadata Validated and key-normalized metadata map
172 * @throw InvalidArgumentException if key contains invalid characters
173 */
174 private function _validate_and_normalize_metadata($metadata)
175 {
176 $metadata_copy = [];
177 foreach ($metadata as $key => $value) {
178 if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
179 throw new \InvalidArgumentException(
180 'Metadata keys must be nonempty strings containing only '.
181 'alphanumeric characters, hyphens and underscores');
182 }
183 $metadata_copy[strtolower($key)] = $value;
184 }
185
186 return $metadata_copy;
187 }
188
189 /* This class is intended to be subclassed by generated code, so
190 * all functions begin with "_" to avoid name collisions. */
191
192 /**
193 * Call a remote method that takes a single argument and has a
194 * single output.
195 *
196 * @param string $method The name of the method to call
197 * @param $argument The argument to the method
198 * @param callable $deserialize A function that deserializes the response
199 * @param array $metadata A metadata map to send to the server
200 *
201 * @return SimpleSurfaceActiveCall The active call object
202 */
203 public function _simpleRequest($method,
204 $argument,
Parker Moore513a6882015-12-01 16:59:49 -0800205 $deserialize,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700206 $metadata = [],
207 $options = [])
208 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700209 $call = new UnaryCall($this->channel,
210 $method,
211 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800212 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700213 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
214 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800215 $metadata = call_user_func($this->update_metadata,
216 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700217 $jwt_aud_uri);
218 }
Stanley Cheung35805802015-12-10 11:42:55 -0800219 $metadata = $this->_validate_and_normalize_metadata(
220 $metadata);
221 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700222
223 return $call;
224 }
225
226 /**
227 * Call a remote method that takes a stream of arguments and has a single
228 * output.
229 *
230 * @param string $method The name of the method to call
231 * @param $arguments An array or Traversable of arguments to stream to the
232 * server
233 * @param callable $deserialize A function that deserializes the response
234 * @param array $metadata A metadata map to send to the server
235 *
236 * @return ClientStreamingSurfaceActiveCall The active call object
237 */
238 public function _clientStreamRequest($method,
239 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800240 $metadata = [],
241 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700242 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700243 $call = new ClientStreamingCall($this->channel,
244 $method,
245 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800246 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700247 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
248 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800249 $metadata = call_user_func($this->update_metadata,
250 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700251 $jwt_aud_uri);
252 }
Stanley Cheung35805802015-12-10 11:42:55 -0800253 $metadata = $this->_validate_and_normalize_metadata(
254 $metadata);
255 $call->start($metadata);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700256
257 return $call;
258 }
259
260 /**
261 * Call a remote method that takes a single argument and returns a stream of
262 * responses.
263 *
264 * @param string $method The name of the method to call
265 * @param $argument The argument to the method
266 * @param callable $deserialize A function that deserializes the responses
267 * @param array $metadata A metadata map to send to the server
268 *
269 * @return ServerStreamingSurfaceActiveCall The active call object
270 */
271 public function _serverStreamRequest($method,
272 $argument,
273 callable $deserialize,
274 $metadata = [],
275 $options = [])
276 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700277 $call = new ServerStreamingCall($this->channel,
278 $method,
279 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800280 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700281 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
282 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800283 $metadata = call_user_func($this->update_metadata,
284 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700285 $jwt_aud_uri);
286 }
Stanley Cheung35805802015-12-10 11:42:55 -0800287 $metadata = $this->_validate_and_normalize_metadata(
288 $metadata);
289 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700290
291 return $call;
292 }
293
294 /**
295 * Call a remote method with messages streaming in both directions.
296 *
297 * @param string $method The name of the method to call
298 * @param callable $deserialize A function that deserializes the responses
299 * @param array $metadata A metadata map to send to the server
300 *
301 * @return BidiStreamingSurfaceActiveCall The active call object
302 */
303 public function _bidiRequest($method,
murgatroid9914d2ce22015-01-30 15:36:23 -0800304 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800305 $metadata = [],
306 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700307 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700308 $call = new BidiStreamingCall($this->channel,
309 $method,
310 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800311 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700312 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
313 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800314 $metadata = call_user_func($this->update_metadata,
315 $metadata,
Stanley Cheungf4206872015-05-12 17:39:30 -0700316 $jwt_aud_uri);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700317 }
Stanley Cheung35805802015-12-10 11:42:55 -0800318 $metadata = $this->_validate_and_normalize_metadata(
319 $metadata);
320 $call->start($metadata);
mlumishb892a272014-12-09 16:28:23 -0800321
Stanley Cheungd5b20562015-10-27 13:27:05 -0700322 return $call;
Stanley Cheung2c9c7632015-04-20 14:13:54 -0700323 }
mlumishb892a272014-12-09 16:28:23 -0800324}