22 private $selectTimeout;
24 private $handles = [];
26 private $options = [];
41 $this->factory = isset($options[
'handle_factory'])
44 if (isset($options[
'select_timeout'])) {
45 $this->selectTimeout = $options[
'select_timeout'];
46 } elseif ($selectTimeout = getenv(
'GUZZLE_CURL_SELECT_TIMEOUT')) {
47 $this->selectTimeout = $selectTimeout;
49 $this->selectTimeout = 1;
52 $this->options = isset($options[
'options']) ? $options[
'options'] : [];
55 public function __get($name)
57 if ($name ===
'_mh') {
58 $this->_mh = curl_multi_init();
60 foreach ($this->options as $option => $value) {
62 curl_multi_setopt($this->_mh, $option, $value);
70 throw new \BadMethodCallException();
75 if (isset($this->_mh)) {
76 curl_multi_close($this->_mh);
83 $easy = $this->factory->create($request, $options);
84 $id = (int) $easy->handle;
88 function () use ($id) {
89 return $this->cancel($id);
93 $this->addRequest([
'easy' => $easy,
'deferred' => $promise]);
101 public function tick()
106 foreach ($this->delays as $id => $delay) {
107 if ($currentTime >= $delay) {
108 unset($this->delays[$id]);
109 curl_multi_add_handle(
111 $this->handles[$id][
'easy']->handle
121 curl_multi_select($this->_mh, $this->selectTimeout) === -1
128 while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
130 $this->processMessages();
140 while ($this->handles || !$queue->isEmpty()) {
142 if (!$this->active && $this->delays) {
143 usleep($this->timeToNext());
149 private function addRequest(array $entry)
151 $easy = $entry[
'easy'];
152 $id = (int) $easy->handle;
153 $this->handles[$id] = $entry;
154 if (empty($easy->options[
'delay'])) {
155 curl_multi_add_handle($this->_mh, $easy->handle);
168 private function cancel($id)
171 if (!isset($this->handles[$id])) {
175 $handle = $this->handles[$id][
'easy']->handle;
176 unset($this->delays[$id], $this->handles[$id]);
177 curl_multi_remove_handle($this->_mh, $handle);
183 private function processMessages()
185 while ($done = curl_multi_info_read($this->_mh)) {
186 $id = (int) $done[
'handle'];
187 curl_multi_remove_handle($this->_mh, $done[
'handle']);
189 if (!isset($this->handles[$id])) {
194 $entry = $this->handles[$id];
195 unset($this->handles[$id], $this->delays[$id]);
196 $entry[
'easy']->errno = $done[
'result'];
197 $entry[
'deferred']->resolve(
207 private function timeToNext()
210 $nextTime = PHP_INT_MAX;
211 foreach ($this->delays as $time) {
212 if ($time < $nextTime) {
217 return max(0, $nextTime - $currentTime) * 1000000;