blob: 8e9dedf73b5a58c0db34218ea9c0e5f4ec6b5c2a [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'];
75 $this->channel = new Channel($hostname, $opts);
Stanley Cheung04b7a412015-08-13 09:39:04 -070076 }
77
Stanley Cheungd5b20562015-10-27 13:27:05 -070078 /**
79 * @return string The URI of the endpoint.
80 */
81 public function getTarget()
82 {
83 return $this->channel->getTarget();
Stanley Cheung04b7a412015-08-13 09:39:04 -070084 }
Stanley Cheung04b7a412015-08-13 09:39:04 -070085
Stanley Cheungd5b20562015-10-27 13:27:05 -070086 /**
87 * @param $try_to_connect bool
88 *
89 * @return int The grpc connectivity state
90 */
91 public function getConnectivityState($try_to_connect = false)
92 {
93 return $this->channel->getConnectivityState($try_to_connect);
Stanley Cheung04b7a412015-08-13 09:39:04 -070094 }
Stanley Cheungd5b20562015-10-27 13:27:05 -070095
96 /**
97 * @param $timeout in microseconds
98 *
99 * @return bool true if channel is ready
100 * @throw Exception if channel is in FATAL_ERROR state
101 */
102 public function waitForReady($timeout)
103 {
104 $new_state = $this->getConnectivityState(true);
105 if ($this->_checkConnectivityState($new_state)) {
106 return true;
107 }
108
109 $now = Timeval::now();
110 $delta = new Timeval($timeout);
111 $deadline = $now->add($delta);
112
113 while ($this->channel->watchConnectivityState($new_state, $deadline)) {
114 // state has changed before deadline
115 $new_state = $this->getConnectivityState();
116 if ($this->_checkConnectivityState($new_state)) {
117 return true;
118 }
119 }
120 // deadline has passed
121 $new_state = $this->getConnectivityState();
122
123 return $this->_checkConnectivityState($new_state);
Stanley Cheung04b7a412015-08-13 09:39:04 -0700124 }
Stanley Cheung04b7a412015-08-13 09:39:04 -0700125
Stanley Cheungd5b20562015-10-27 13:27:05 -0700126 private function _checkConnectivityState($new_state)
127 {
128 if ($new_state == \Grpc\CHANNEL_READY) {
129 return true;
130 }
131 if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
132 throw new \Exception('Failed to connect to server');
133 }
mlumishb892a272014-12-09 16:28:23 -0800134
Stanley Cheungd5b20562015-10-27 13:27:05 -0700135 return false;
Stanley Cheungf4206872015-05-12 17:39:30 -0700136 }
Stanley Cheungf4206872015-05-12 17:39:30 -0700137
Stanley Cheungd5b20562015-10-27 13:27:05 -0700138 /**
139 * Close the communication channel associated with this stub.
140 */
141 public function close()
142 {
143 $this->channel->close();
Stanley Cheungcc019af2015-06-15 11:45:00 -0700144 }
Stanley Cheungcc019af2015-06-15 11:45:00 -0700145
Stanley Cheungd5b20562015-10-27 13:27:05 -0700146 /**
147 * constructs the auth uri for the jwt.
148 */
149 private function _get_jwt_aud_uri($method)
150 {
151 $last_slash_idx = strrpos($method, '/');
152 if ($last_slash_idx === false) {
153 throw new \InvalidArgumentException(
154 'service name must have a slash');
155 }
156 $service_name = substr($method, 0, $last_slash_idx);
157
158 return 'https://'.$this->hostname.$service_name;
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700159 }
Stanley Cheungb0cd08a2015-10-09 16:58:01 -0700160
Stanley Cheungd5b20562015-10-27 13:27:05 -0700161 /**
Stanley Cheungd5b20562015-10-27 13:27:05 -0700162 * validate and normalize the metadata array.
163 *
164 * @param $metadata The metadata map
165 *
166 * @return $metadata Validated and key-normalized metadata map
167 * @throw InvalidArgumentException if key contains invalid characters
168 */
169 private function _validate_and_normalize_metadata($metadata)
170 {
171 $metadata_copy = [];
172 foreach ($metadata as $key => $value) {
173 if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
174 throw new \InvalidArgumentException(
175 'Metadata keys must be nonempty strings containing only '.
176 'alphanumeric characters, hyphens and underscores');
177 }
178 $metadata_copy[strtolower($key)] = $value;
179 }
180
181 return $metadata_copy;
182 }
183
184 /* This class is intended to be subclassed by generated code, so
185 * all functions begin with "_" to avoid name collisions. */
186
187 /**
188 * Call a remote method that takes a single argument and has a
189 * single output.
190 *
191 * @param string $method The name of the method to call
192 * @param $argument The argument to the method
193 * @param callable $deserialize A function that deserializes the response
194 * @param array $metadata A metadata map to send to the server
195 *
196 * @return SimpleSurfaceActiveCall The active call object
197 */
198 public function _simpleRequest($method,
199 $argument,
Parker Moore513a6882015-12-01 16:59:49 -0800200 $deserialize,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700201 $metadata = [],
202 $options = [])
203 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700204 $call = new UnaryCall($this->channel,
205 $method,
206 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800207 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700208 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
209 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800210 $metadata = call_user_func($this->update_metadata,
211 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700212 $jwt_aud_uri);
213 }
Stanley Cheung35805802015-12-10 11:42:55 -0800214 $metadata = $this->_validate_and_normalize_metadata(
215 $metadata);
216 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700217
218 return $call;
219 }
220
221 /**
222 * Call a remote method that takes a stream of arguments and has a single
223 * output.
224 *
225 * @param string $method The name of the method to call
226 * @param $arguments An array or Traversable of arguments to stream to the
227 * server
228 * @param callable $deserialize A function that deserializes the response
229 * @param array $metadata A metadata map to send to the server
230 *
231 * @return ClientStreamingSurfaceActiveCall The active call object
232 */
233 public function _clientStreamRequest($method,
234 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800235 $metadata = [],
236 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700237 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700238 $call = new ClientStreamingCall($this->channel,
239 $method,
240 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800241 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700242 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
243 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800244 $metadata = call_user_func($this->update_metadata,
245 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700246 $jwt_aud_uri);
247 }
Stanley Cheung35805802015-12-10 11:42:55 -0800248 $metadata = $this->_validate_and_normalize_metadata(
249 $metadata);
250 $call->start($metadata);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700251
252 return $call;
253 }
254
255 /**
256 * Call a remote method that takes a single argument and returns a stream of
257 * responses.
258 *
259 * @param string $method The name of the method to call
260 * @param $argument The argument to the method
261 * @param callable $deserialize A function that deserializes the responses
262 * @param array $metadata A metadata map to send to the server
263 *
264 * @return ServerStreamingSurfaceActiveCall The active call object
265 */
266 public function _serverStreamRequest($method,
267 $argument,
268 callable $deserialize,
269 $metadata = [],
270 $options = [])
271 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700272 $call = new ServerStreamingCall($this->channel,
273 $method,
274 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800275 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700276 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
277 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800278 $metadata = call_user_func($this->update_metadata,
279 $metadata,
Stanley Cheungd5b20562015-10-27 13:27:05 -0700280 $jwt_aud_uri);
281 }
Stanley Cheung35805802015-12-10 11:42:55 -0800282 $metadata = $this->_validate_and_normalize_metadata(
283 $metadata);
284 $call->start($argument, $metadata, $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700285
286 return $call;
287 }
288
289 /**
290 * Call a remote method with messages streaming in both directions.
291 *
292 * @param string $method The name of the method to call
293 * @param callable $deserialize A function that deserializes the responses
294 * @param array $metadata A metadata map to send to the server
295 *
296 * @return BidiStreamingSurfaceActiveCall The active call object
297 */
298 public function _bidiRequest($method,
murgatroid9914d2ce22015-01-30 15:36:23 -0800299 callable $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800300 $metadata = [],
301 $options = [])
Stanley Cheungd5b20562015-10-27 13:27:05 -0700302 {
Stanley Cheungd5b20562015-10-27 13:27:05 -0700303 $call = new BidiStreamingCall($this->channel,
304 $method,
305 $deserialize,
Stanley Cheung35805802015-12-10 11:42:55 -0800306 $options);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700307 $jwt_aud_uri = $this->_get_jwt_aud_uri($method);
308 if (is_callable($this->update_metadata)) {
Stanley Cheung35805802015-12-10 11:42:55 -0800309 $metadata = call_user_func($this->update_metadata,
310 $metadata,
Stanley Cheungf4206872015-05-12 17:39:30 -0700311 $jwt_aud_uri);
Stanley Cheungd5b20562015-10-27 13:27:05 -0700312 }
Stanley Cheung35805802015-12-10 11:42:55 -0800313 $metadata = $this->_validate_and_normalize_metadata(
314 $metadata);
315 $call->start($metadata);
mlumishb892a272014-12-09 16:28:23 -0800316
Stanley Cheungd5b20562015-10-27 13:27:05 -0700317 return $call;
Stanley Cheung2c9c7632015-04-20 14:13:54 -0700318 }
mlumishb892a272014-12-09 16:28:23 -0800319}