Tea.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 (!isset($retryTimes) || null === $retryTimes || !\is_numeric($retryTimes)) {
  154. return false;
  155. }
  156. if ($retryTimes > 0 && (empty($runtime) || !isset($runtime['retryable']) || !$runtime['retryable'] || !isset($runtime['maxAttempts']))) {
  157. return false;
  158. }
  159. $maxAttempts = $runtime['maxAttempts'];
  160. $retry = empty($maxAttempts) ? 0 : (int) $maxAttempts;
  161. return $retry >= $retryTimes;
  162. }
  163. /**
  164. * @param int $retryTimes
  165. *
  166. * @return int
  167. */
  168. public static function getBackoffTime(array $runtime, $retryTimes)
  169. {
  170. $backOffTime = 0;
  171. $policy = isset($runtime['policy']) ? $runtime['policy'] : '';
  172. if (empty($policy) || 'no' == $policy) {
  173. return $backOffTime;
  174. }
  175. $period = isset($runtime['period']) ? $runtime['period'] : '';
  176. if (null !== $period && '' !== $period) {
  177. $backOffTime = (int) $period;
  178. if ($backOffTime <= 0) {
  179. return $retryTimes;
  180. }
  181. }
  182. return $backOffTime;
  183. }
  184. public static function sleep($time)
  185. {
  186. sleep($time);
  187. }
  188. public static function isRetryable($retry, $retryTimes = 0)
  189. {
  190. if ($retry instanceof TeaError) {
  191. return true;
  192. }
  193. if (\is_array($retry)) {
  194. $max = isset($retry['maxAttempts']) ? (int) ($retry['maxAttempts']) : 3;
  195. return $retryTimes <= $max;
  196. }
  197. return false;
  198. }
  199. /**
  200. * @param mixed|Model[] ...$item
  201. *
  202. * @return mixed
  203. */
  204. public static function merge(...$item)
  205. {
  206. $tmp = [];
  207. $n = 0;
  208. foreach ($item as $i) {
  209. if (\is_object($i)) {
  210. if ($i instanceof Model) {
  211. $i = $i->toMap();
  212. } else {
  213. $i = json_decode(json_encode($i), true);
  214. }
  215. }
  216. if (null === $i) {
  217. continue;
  218. }
  219. if (\is_array($i)) {
  220. $tmp[$n++] = $i;
  221. }
  222. }
  223. if (\count($tmp)) {
  224. return \call_user_func_array('array_merge', $tmp);
  225. }
  226. return [];
  227. }
  228. private static function resolveConfig(array $config = [])
  229. {
  230. $options = new Dot(['http_errors' => false]);
  231. if (isset($config['httpProxy']) && !empty($config['httpProxy'])) {
  232. $options->set('proxy.http', $config['httpProxy']);
  233. }
  234. if (isset($config['httpsProxy']) && !empty($config['httpsProxy'])) {
  235. $options->set('proxy.https', $config['httpsProxy']);
  236. }
  237. if (isset($config['noProxy']) && !empty($config['noProxy'])) {
  238. $options->set('proxy.no', $config['noProxy']);
  239. }
  240. // readTimeout&connectTimeout unit is millisecond
  241. $read_timeout = isset($config['readTimeout']) && !empty($config['readTimeout']) ? (int) $config['readTimeout'] : 0;
  242. $con_timeout = isset($config['connectTimeout']) && !empty($config['connectTimeout']) ? (int) $config['connectTimeout'] : 0;
  243. // timeout unit is second
  244. $options->set('timeout', ($read_timeout + $con_timeout) / 1000);
  245. return $options->all();
  246. }
  247. }