Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace Guzzle\Http\Curl;
4
 
5
use Guzzle\Common\AbstractHasDispatcher;
6
use Guzzle\Http\Message\RequestInterface;
7
 
8
/**
9
 * Proxies requests and connections to a pool of internal curl_multi handles. Each recursive call will add requests
10
 * to the next available CurlMulti handle.
11
 */
12
class CurlMultiProxy extends AbstractHasDispatcher implements CurlMultiInterface
13
{
14
    protected $handles = array();
15
    protected $groups = array();
16
    protected $queued = array();
17
    protected $maxHandles;
18
    protected $selectTimeout;
19
 
20
    /**
21
     * @param int   $maxHandles The maximum number of idle CurlMulti handles to allow to remain open
22
     * @param float $selectTimeout timeout for curl_multi_select
23
     */
24
    public function __construct($maxHandles = 3, $selectTimeout = 1.0)
25
    {
26
        $this->maxHandles = $maxHandles;
27
        $this->selectTimeout = $selectTimeout;
28
        // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel.
29
        // These two statements autoload classes before a system runs out of file descriptors so that you can get back
30
        // valuable error messages if you run out.
31
        class_exists('Guzzle\Http\Message\Response');
32
        class_exists('Guzzle\Http\Exception\CurlException');
33
    }
34
 
35
    public function add(RequestInterface $request)
36
    {
37
        $this->queued[] = $request;
38
 
39
        return $this;
40
    }
41
 
42
    public function all()
43
    {
44
        $requests = $this->queued;
45
        foreach ($this->handles as $handle) {
46
            $requests = array_merge($requests, $handle->all());
47
        }
48
 
49
        return $requests;
50
    }
51
 
52
    public function remove(RequestInterface $request)
53
    {
54
        foreach ($this->queued as $i => $r) {
55
            if ($request === $r) {
56
                unset($this->queued[$i]);
57
                return true;
58
            }
59
        }
60
 
61
        foreach ($this->handles as $handle) {
62
            if ($handle->remove($request)) {
63
                return true;
64
            }
65
        }
66
 
67
        return false;
68
    }
69
 
70
    public function reset($hard = false)
71
    {
72
        $this->queued = array();
73
        $this->groups = array();
74
        foreach ($this->handles as $handle) {
75
            $handle->reset();
76
        }
77
        if ($hard) {
78
            $this->handles = array();
79
        }
80
 
81
        return $this;
82
    }
83
 
84
    public function send()
85
    {
86
        if ($this->queued) {
87
            $group = $this->getAvailableHandle();
88
            // Add this handle to a list of handles than is claimed
89
            $this->groups[] = $group;
90
            while ($request = array_shift($this->queued)) {
91
                $group->add($request);
92
            }
93
            try {
94
                $group->send();
95
                array_pop($this->groups);
96
                $this->cleanupHandles();
97
            } catch (\Exception $e) {
98
                // Remove the group and cleanup if an exception was encountered and no more requests in group
99
                if (!$group->count()) {
100
                    array_pop($this->groups);
101
                    $this->cleanupHandles();
102
                }
103
                throw $e;
104
            }
105
        }
106
    }
107
 
108
    public function count()
109
    {
110
        return count($this->all());
111
    }
112
 
113
    /**
114
     * Get an existing available CurlMulti handle or create a new one
115
     *
116
     * @return CurlMulti
117
     */
118
    protected function getAvailableHandle()
119
    {
120
        // Grab a handle that is not claimed
121
        foreach ($this->handles as $h) {
122
            if (!in_array($h, $this->groups, true)) {
123
                return $h;
124
            }
125
        }
126
 
127
        // All are claimed, so create one
128
        $handle = new CurlMulti($this->selectTimeout);
129
        $handle->setEventDispatcher($this->getEventDispatcher());
130
        $this->handles[] = $handle;
131
 
132
        return $handle;
133
    }
134
 
135
    /**
136
     * Trims down unused CurlMulti handles to limit the number of open connections
137
     */
138
    protected function cleanupHandles()
139
    {
140
        if ($diff = max(0, count($this->handles) - $this->maxHandles)) {
141
            for ($i = count($this->handles) - 1; $i > 0 && $diff > 0; $i--) {
142
                if (!count($this->handles[$i])) {
143
                    unset($this->handles[$i]);
144
                    $diff--;
145
                }
146
            }
147
            $this->handles = array_values($this->handles);
148
        }
149
    }
150
}