Tea.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. <?php
  2. namespace AlibabaCloud\Tea;
  3. use Adbar\Dot;
  4. use AlibabaCloud\Tea\Exception\TeaError;
  5. use GuzzleHttp\Client;
  6. use GuzzleHttp\Exception\GuzzleException;
  7. use GuzzleHttp\HandlerStack;
  8. use GuzzleHttp\Middleware;
  9. use GuzzleHttp\Promise\PromiseInterface;
  10. use GuzzleHttp\TransferStats;
  11. use Psr\Http\Message\RequestInterface;
  12. use Psr\Http\Message\ResponseInterface;
  13. use Psr\Http\Message\UriInterface;
  14. /**
  15. * Class Tea.
  16. */
  17. class Tea
  18. {
  19. /**
  20. * @var array
  21. */
  22. private static $config = [];
  23. public static function config(array $config)
  24. {
  25. self::$config = $config;
  26. }
  27. /**
  28. * @throws GuzzleException
  29. *
  30. * @return Response
  31. */
  32. public static function send(Request $request, array $config = [])
  33. {
  34. if (method_exists($request, 'getPsrRequest')) {
  35. $request = $request->getPsrRequest();
  36. }
  37. $config = self::resolveConfig($config);
  38. $res = self::client()->send(
  39. $request,
  40. $config
  41. );
  42. return new Response($res);
  43. }
  44. /**
  45. * @return PromiseInterface
  46. */
  47. public static function sendAsync(RequestInterface $request, array $config = [])
  48. {
  49. if (method_exists($request, 'getPsrRequest')) {
  50. $request = $request->getPsrRequest();
  51. }
  52. $config = self::resolveConfig($config);
  53. return self::client()->sendAsync(
  54. $request,
  55. $config
  56. );
  57. }
  58. /**
  59. * @return Client
  60. */
  61. public static function client(array $config = [])
  62. {
  63. if (isset(self::$config['handler'])) {
  64. $stack = self::$config['handler'];
  65. } else {
  66. $stack = HandlerStack::create();
  67. $stack->push(Middleware::mapResponse(static function (ResponseInterface $response) {
  68. return new Response($response);
  69. }));
  70. }
  71. self::$config['handler'] = $stack;
  72. if (!isset(self::$config['on_stats'])) {
  73. self::$config['on_stats'] = function (TransferStats $stats) {
  74. Response::$info = $stats->getHandlerStats();
  75. };
  76. }
  77. $new_config = Helper::merge([self::$config, $config]);
  78. return new Client($new_config);
  79. }
  80. /**
  81. * @param string $method
  82. * @param string|UriInterface $uri
  83. * @param array $options
  84. *
  85. * @throws GuzzleException
  86. *
  87. * @return ResponseInterface
  88. */
  89. public static function request($method, $uri, $options = [])
  90. {
  91. return self::client()->request($method, $uri, $options);
  92. }
  93. /**
  94. * @param string $method
  95. * @param string $uri
  96. * @param array $options
  97. *
  98. * @throws GuzzleException
  99. *
  100. * @return string
  101. */
  102. public static function string($method, $uri, $options = [])
  103. {
  104. return (string) self::client()->request($method, $uri, $options)
  105. ->getBody();
  106. }
  107. /**
  108. * @param string $method
  109. * @param string|UriInterface $uri
  110. * @param array $options
  111. *
  112. * @return PromiseInterface
  113. */
  114. public static function requestAsync($method, $uri, $options = [])
  115. {
  116. return self::client()->requestAsync($method, $uri, $options);
  117. }
  118. /**
  119. * @param string|UriInterface $uri
  120. * @param array $options
  121. *
  122. * @throws GuzzleException
  123. *
  124. * @return null|mixed
  125. */
  126. public static function getHeaders($uri, $options = [])
  127. {
  128. return self::request('HEAD', $uri, $options)->getHeaders();
  129. }
  130. /**
  131. * @param string|UriInterface $uri
  132. * @param string $key
  133. * @param null|mixed $default
  134. *
  135. * @throws GuzzleException
  136. *
  137. * @return null|mixed
  138. */
  139. public static function getHeader($uri, $key, $default = null)
  140. {
  141. $headers = self::getHeaders($uri);
  142. return isset($headers[$key][0]) ? $headers[$key][0] : $default;
  143. }
  144. /**
  145. * @param int $retryTimes
  146. * @param float $now
  147. *
  148. * @return bool
  149. */
  150. public static function allowRetry(array $runtime, $retryTimes, $now)
  151. {
  152. unset($now);
  153. if (empty($runtime) || !isset($runtime['maxAttempts'])) {
  154. return false;
  155. }
  156. $maxAttempts = $runtime['maxAttempts'];
  157. $retry = empty($maxAttempts) ? 0 : (int) $maxAttempts;
  158. return $retry >= $retryTimes;
  159. }
  160. /**
  161. * @param int $retryTimes
  162. *
  163. * @return int
  164. */
  165. public static function getBackoffTime(array $runtime, $retryTimes)
  166. {
  167. $backOffTime = 0;
  168. $policy = isset($runtime['policy']) ? $runtime['policy'] : '';
  169. if (empty($policy) || 'no' == $policy) {
  170. return $backOffTime;
  171. }
  172. $period = isset($runtime['period']) ? $runtime['period'] : '';
  173. if (null !== $period && '' !== $period) {
  174. $backOffTime = (int) $period;
  175. if ($backOffTime <= 0) {
  176. return $retryTimes;
  177. }
  178. }
  179. return $backOffTime;
  180. }
  181. public static function sleep($time)
  182. {
  183. sleep($time);
  184. }
  185. public static function isRetryable($retry, $retryTimes = 0)
  186. {
  187. if ($retry instanceof TeaError) {
  188. return true;
  189. }
  190. if (\is_array($retry)) {
  191. $max = isset($retry['maxAttempts']) ? (int) ($retry['maxAttempts']) : 3;
  192. return $retryTimes <= $max;
  193. }
  194. return false;
  195. }
  196. /**
  197. * @param mixed|Model[] ...$item
  198. *
  199. * @return mixed
  200. */
  201. public static function merge(...$item)
  202. {
  203. $tmp = [];
  204. $n = 0;
  205. foreach ($item as $i) {
  206. if (\is_object($i)) {
  207. if ($i instanceof Model) {
  208. $i = $i->toMap();
  209. } else {
  210. $i = json_decode(json_encode($i), true);
  211. }
  212. }
  213. if (null === $i) {
  214. continue;
  215. }
  216. if (\is_array($i)) {
  217. $tmp[$n++] = $i;
  218. }
  219. }
  220. if (\count($tmp)) {
  221. return \call_user_func_array('array_merge', $tmp);
  222. }
  223. return [];
  224. }
  225. private static function resolveConfig(array $config = [])
  226. {
  227. $options = new Dot(['http_errors' => false]);
  228. if (isset($config['httpProxy']) && !empty($config['httpProxy'])) {
  229. $options->set('proxy.http', $config['httpProxy']);
  230. }
  231. if (isset($config['httpsProxy']) && !empty($config['httpsProxy'])) {
  232. $options->set('proxy.https', $config['httpsProxy']);
  233. }
  234. if (isset($config['noProxy']) && !empty($config['noProxy'])) {
  235. $options->set('proxy.no', $config['noProxy']);
  236. }
  237. // readTimeout&connectTimeout unit is millisecond
  238. $read_timeout = isset($config['readTimeout']) && !empty($config['readTimeout']) ? (int) $config['readTimeout'] : 0;
  239. $con_timeout = isset($config['connectTimeout']) && !empty($config['connectTimeout']) ? (int) $config['connectTimeout'] : 0;
  240. // timeout unit is second
  241. $options->set('timeout', ($read_timeout + $con_timeout) / 1000);
  242. return $options->all();
  243. }
  244. }