Uploader::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 3
cts 3
cp 1
crap 1
1
<?php
2
namespace Upyun;
3
4
use Upyun\Api\Rest;
5
use Upyun\Api\Form;
6
use GuzzleHttp\Psr7;
7
use GuzzleHttp\Pool;
8
use GuzzleHttp\Client;
9
10
class Uploader
11
{
12
    /**
13
     * @var Config
14
     */
15
    protected $config;
16
17
    protected $useBlock = false;
18
19
20 15
    public function __construct(Config $config)
21
    {
22 15
        $this->config = $config;
23 15
    }
24
25 15
    public function upload($path, $file, $params, $withAsyncProcess)
26
    {
27 15
        $stream = Psr7\stream_for($file);
28 15
        $size = $stream->getSize();
29 15
        $useBlock = $this->needUseBlock($size);
30
31 15
        if ($withAsyncProcess) {
32 1
            $req = new Form($this->config);
33 1
            return $req->upload($path, $stream, $params);
34
        }
35
36 14
        if (! $useBlock) {
37 13
            $req = new Rest($this->config);
38 13
            return $req->request('PUT', $path)
39 13
                       ->withHeaders($params)
40 13
                       ->withFile($stream)
41 13
                       ->send();
42 1
        } elseif ($this->config->uploadType === 'BLOCK_PARALLEL') {
43 1
            return $this->concurrentPointUpload($path, $stream, $params);
44
        } else {
45
            return $this->pointUpload($path, $stream, $params);
46
        }
47
    }
48
49
    /**
50
     * 串行式断点续传
51
     * @param $path
52
     * @param $stream
53
     * @param $params
54
     *
55
     * @return mixed|\Psr\Http\Message\ResponseInterface
56
     * @throws \Exception
57
     */
58 1
    private function pointUpload($path, $stream, $params)
59
    {
60
        $req = new Rest($this->config);
61 1
        $headers = array();
62
        if (is_array($params)) {
63
            foreach ($params as $key => $val) {
64
                $headers['X-Upyun-Meta-' . $key] = $val;
65
            }
66
        }
67
        $res = $req->request('PUT', $path)
68
            ->withHeaders(array_merge(array(
69
                'X-Upyun-Multi-Stage' => 'initiate',
70 1
                'X-Upyun-Multi-Type' => Psr7\mimetype_from_filename($path),
71 1
                'X-Upyun-Multi-Length' => $stream->getSize(),
72
            ), $headers))
73 1
            ->send();
74
        if ($res->getStatusCode() !== 204) {
75
            throw new \Exception('init request failed when poinit upload!');
76
        }
77
78
        $init      = Util::getHeaderParams($res->getHeaders());
79
        $uuid      = $init['x-upyun-multi-uuid'];
80
        $blockSize = 1024 * 1024;
81
        $partId    = 0;
82
        do {
83
            $fileBlock = $stream->read($blockSize);
84
            $res = $req->request('PUT', $path)
85
                ->withHeaders(array(
86 1
                    'X-Upyun-Multi-Stage' => 'upload',
87
                    'X-Upyun-Multi-Uuid' => $uuid,
88
                    'X-Upyun-Part-Id' => $partId
89
                ))
90
                ->withFile(Psr7\stream_for($fileBlock))
91
                ->send();
92
93
            if ($res->getStatusCode() !== 204) {
94
                throw new \Exception('upload request failed when poinit upload!');
95
            }
96
            $data   = Util::getHeaderParams($res->getHeaders());
97
            $partId = $data['x-upyun-next-part-id'];
98
        } while ($partId != -1);
99
100
        $res = $req->request('PUT', $path)
101
            ->withHeaders(array(
102
                'X-Upyun-Multi-Uuid' => $uuid,
103
                'X-Upyun-Multi-Stage' => 'complete'
104
            ))
105
            ->send();
106
107
        if ($res->getStatusCode() != 204 && $res->getStatusCode() != 201) {
108
            throw new \Exception('end request failed when poinit upload!');
109
        }
110
        return $res;
111
    }
112
113 15
    private function needUseBlock($fileSize)
114
    {
115 15
        if ($this->config->uploadType === 'BLOCK' ||
116 15
            $this->config->uploadType === 'BLOCK_PARALLEL') {
117 1
            return true;
118 14
        } elseif ($this->config->uploadType === 'AUTO' &&
119 14
                  $fileSize >= $this->config->sizeBoundary) {
120
            return true;
121
        } else {
122 14
            return false;
123
        }
124
    }
125
126
    /**
127
     * 并行式断点续传
128
     * @param $path
129
     * @param $stream
130
     * @param $params
131
     *
132
     * @return mixed|\Psr\Http\Message\ResponseInterface
133
     * @throws \Exception
134
     */
135 1
    private function concurrentPointUpload($path, $stream, $params)
136
    {
137 1
        $req = new Rest($this->config);
138
139 1
        $headers = array();
140 1
        if (is_array($params)) {
141 1
            foreach ($params as $key => $val) {
142
                $headers['X-Upyun-Meta-' . $key] = $val;
143 1
            }
144 1
        }
145 1
        $res = $req->request('PUT', $path)
146 1
            ->withHeaders(array_merge(array(
147 1
                'X-Upyun-Multi-Disorder' => 'true',
148 1
                'X-Upyun-Multi-Stage' => 'initiate',
149 1
                'X-Upyun-Multi-Type' => Psr7\mimetype_from_filename($path),
150 1
                'X-Upyun-Multi-Length' => $stream->getSize(),
151 1
            ), $headers))
152 1
            ->send();
153 1
        if ($res->getStatusCode() !== 204) {
154
            throw new \Exception('init request failed when poinit upload!');
155
        }
156
157 1
        $init = Util::getHeaderParams($res->getHeaders());
158 1
        $uuid = $init['x-upyun-multi-uuid'];
159
        $requests = function ($req, $path, $stream, $uuid) {
160 1
            $blockSize = 1024 * 1024;
161 1
            $total = ceil($stream->getSize() / $blockSize);
162 1
            for ($i = 0; $i < $total; $i++) {
163 1
                $fileBlock = $stream->read($blockSize);
164 1
                yield $req->request('PUT', $path)
165 1
                    ->withHeaders(array(
166 1
                        'X-Upyun-Multi-Stage' => 'upload',
167 1
                        'X-Upyun-Multi-Uuid' => $uuid,
168
                        'X-Upyun-Part-Id' => $i
169 1
                    ))
170 1
                    ->withFile(Psr7\stream_for($fileBlock))
171 1
                    ->toRequest();
172 1
            }
173 1
        };
174 1
        $client = new Client([
175 1
            'timeout' => $this->config->timeout,
176 1
        ]);
177 1
        $pool = new Pool($client, $requests($req, $path, $stream, $uuid), [
178 1
            'concurrency' => $this->config->concurrency,
179
            'fulfilled' => function ($res) {
180 1
                if ($res->getStatusCode() !== 204) {
181
                    throw new \Exception('upload request failed when poinit upload!');
182
                }
183 1
            },
184 1
            'rejected' => function () {
185
                throw new \Exception('upload request failed when poinit upload!');
186 1
            },
187 1
        ]);
188 1
        $promise = $pool->promise();
189 1
        $promise->wait();
190
191 1
        $res = $req->request('PUT', $path)
192 1
            ->withHeaders(array(
193 1
                'X-Upyun-Multi-Uuid' => $uuid,
194
                'X-Upyun-Multi-Stage' => 'complete'
195 1
            ))
196 1
            ->send();
197 1
        if ($res->getStatusCode() != 204 && $res->getStatusCode() != 201) {
198
            throw new \Exception('end request failed when poinit upload!');
199
        }
200 1
        return $res;
201
    }
202
}
203