PluginProbe
Media Cloud Sync / 1.0.2
Media Cloud Sync v1.0.2
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / sdk / s3 / GuzzleHttp / Handler / CurlMultiHandler.php

CurlMultiHandler.php in Media Cloud Sync 1.0.2, at includes/sdk/s3/GuzzleHttp/Handler/CurlMultiHandler.php

178 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Dudlewebs\WPMCS\s3\GuzzleHttp\Handler;
4
5 use Dudlewebs\WPMCS\s3\GuzzleHttp\Promise as P;
6 use Dudlewebs\WPMCS\s3\GuzzleHttp\Promise\Promise;
7 use Dudlewebs\WPMCS\s3\GuzzleHttp\Utils;
8 use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface;
9 /**
10 * Returns an asynchronous response using curl_multi_* functions.
11 *
12 * When using the CurlMultiHandler, custom curl options can be specified as an
13 * associative array of curl option constants mapping to values in the
14 * **curl** key of the provided request options.
15 *
16 * @property resource $_mh Internal use only. Lazy loaded multi-handle.
17 */
18 class CurlMultiHandler
19 {
20 /** @var CurlFactoryInterface */
21 private $factory;
22 private $selectTimeout;
23 private $active;
24 private $handles = [];
25 private $delays = [];
26 private $options = [];
27 /**
28 * This handler accepts the following options:
29 *
30 * - handle_factory: An optional factory used to create curl handles
31 * - select_timeout: Optional timeout (in seconds) to block before timing
32 * out while selecting curl handles. Defaults to 1 second.
33 * - options: An associative array of CURLMOPT_* options and
34 * corresponding values for curl_multi_setopt()
35 *
36 * @param array $options
37 */
38 public function __construct(array $options = [])
39 {
40 $this->factory = isset($options['handle_factory']) ? $options['handle_factory'] : new CurlFactory(50);
41 if (isset($options['select_timeout'])) {
42 $this->selectTimeout = $options['select_timeout'];
43 } elseif ($selectTimeout = \getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
44 $this->selectTimeout = $selectTimeout;
45 } else {
46 $this->selectTimeout = 1;
47 }
48 $this->options = isset($options['options']) ? $options['options'] : [];
49 }
50 public function __get($name)
51 {
52 if ($name === '_mh') {
53 $this->_mh = \curl_multi_init();
54 foreach ($this->options as $option => $value) {
55 // A warning is raised in case of a wrong option.
56 \curl_multi_setopt($this->_mh, $option, $value);
57 }
58 // Further calls to _mh will return the value directly, without entering the
59 // __get() method at all.
60 return $this->_mh;
61 }
62 throw new \BadMethodCallException();
63 }
64 public function __destruct()
65 {
66 if (isset($this->_mh)) {
67 \curl_multi_close($this->_mh);
68 unset($this->_mh);
69 }
70 }
71 public function __invoke(RequestInterface $request, array $options)
72 {
73 $easy = $this->factory->create($request, $options);
74 $id = (int) $easy->handle;
75 $promise = new Promise([$this, 'execute'], function () use($id) {
76 return $this->cancel($id);
77 });
78 $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
79 return $promise;
80 }
81 /**
82 * Ticks the curl event loop.
83 */
84 public function tick()
85 {
86 // Add any delayed handles if needed.
87 if ($this->delays) {
88 $currentTime = Utils::currentTime();
89 foreach ($this->delays as $id => $delay) {
90 if ($currentTime >= $delay) {
91 unset($this->delays[$id]);
92 \curl_multi_add_handle($this->_mh, $this->handles[$id]['easy']->handle);
93 }
94 }
95 }
96 // Step through the task queue which may add additional requests.
97 P\queue()->run();
98 if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) {
99 // Perform a usleep if a select returns -1.
100 // See: https://bugs.php.net/bug.php?id=61141
101 \usleep(250);
102 }
103 while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
104 }
105 $this->processMessages();
106 }
107 /**
108 * Runs until all outstanding connections have completed.
109 */
110 public function execute()
111 {
112 $queue = P\queue();
113 while ($this->handles || !$queue->isEmpty()) {
114 // If there are no transfers, then sleep for the next delay
115 if (!$this->active && $this->delays) {
116 \usleep($this->timeToNext());
117 }
118 $this->tick();
119 }
120 }
121 private function addRequest(array $entry)
122 {
123 $easy = $entry['easy'];
124 $id = (int) $easy->handle;
125 $this->handles[$id] = $entry;
126 if (empty($easy->options['delay'])) {
127 \curl_multi_add_handle($this->_mh, $easy->handle);
128 } else {
129 $this->delays[$id] = Utils::currentTime() + $easy->options['delay'] / 1000;
130 }
131 }
132 /**
133 * Cancels a handle from sending and removes references to it.
134 *
135 * @param int $id Handle ID to cancel and remove.
136 *
137 * @return bool True on success, false on failure.
138 */
139 private function cancel($id)
140 {
141 // Cannot cancel if it has been processed.
142 if (!isset($this->handles[$id])) {
143 return \false;
144 }
145 $handle = $this->handles[$id]['easy']->handle;
146 unset($this->delays[$id], $this->handles[$id]);
147 \curl_multi_remove_handle($this->_mh, $handle);
148 \curl_close($handle);
149 return \true;
150 }
151 private function processMessages()
152 {
153 while ($done = \curl_multi_info_read($this->_mh)) {
154 $id = (int) $done['handle'];
155 \curl_multi_remove_handle($this->_mh, $done['handle']);
156 if (!isset($this->handles[$id])) {
157 // Probably was cancelled.
158 continue;
159 }
160 $entry = $this->handles[$id];
161 unset($this->handles[$id], $this->delays[$id]);
162 $entry['easy']->errno = $done['result'];
163 $entry['deferred']->resolve(CurlFactory::finish($this, $entry['easy'], $this->factory));
164 }
165 }
166 private function timeToNext()
167 {
168 $currentTime = Utils::currentTime();
169 $nextTime = \PHP_INT_MAX;
170 foreach ($this->delays as $time) {
171 if ($time < $nextTime) {
172 $nextTime = $time;
173 }
174 }
175 return \max(0, $nextTime - $currentTime) * 1000000;
176 }
177 }
178