Completed
Pull Request — master (#29)
by
unknown
05:32
created

Queue::request()   D

Complexity

Conditions 9
Paths 8

Size

Total Lines 37
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 4.909
c 0
b 0
f 0
cc 9
eloc 29
nc 8
nop 3
1
<?php
2
3
namespace h4kuna\Fio\Request;
4
5
use GuzzleHttp,
6
	h4kuna\Fio,
7
	h4kuna\Fio\Response\Pay,
8
	Nette\Utils;
9
10
class Queue implements IQueue
11
{
12
13
	/** @var string[] */
14
	private static $tokens = [];
15
16
	/** @var int */
17
	private $limitLoop = 5;
18
19
	/** @var bool */
20
	private $sleep = true;
21
22
	/** @var array */
23
	private $downloadOptions = [];
24
25
	/** @var string */
26
	private $tempDir;
27
28
	public function __construct($tempDir)
29
	{
30
		$this->tempDir = $tempDir;
31
	}
32
33
	/**
34
	 * @param int $limitLoop
35
	 */
36
	public function setLimitLoop($limitLoop)
37
	{
38
		$this->limitLoop = (int) $limitLoop;
39
	}
40
41
	/**
42
	 * @param array|\Iterator $downloadOptions
43
	 */
44
	public function setDownloadOptions($downloadOptions)
45
	{
46
		foreach ($downloadOptions as $define => $value) {
47
			if (is_string($define) && defined($define)) {
48
				$define = constant($define);
49
			}
50
			$this->downloadOptions[$define] = $value;
51
		}
52
	}
53
54
	public function setSleep($sleep)
55
	{
56
		$this->sleep = (bool) $sleep;
57
	}
58
59
	/**
60
	 * @param $token
61
	 * @param string $url
62
	 * @return mixed|string
63
	 * @throws Fio\QueueLimitException
64
	 * @throws Fio\ServiceUnavailableException
65
	 */
66
	public function download($token, $url)
67
	{
68
		return $this->request($token, function (GuzzleHttp\Client $client) use ($url) {
69
			return $client->request('GET', $url, $this->downloadOptions);
70
		}, 'download');
71
	}
72
73
    /**
74
     * @return Pay\IResponse
75
     * @throws Fio\QueueLimitException
76
     * @throws Fio\ServiceUnavailableException
77
     */
78
	public function upload($url, $token, array $post, $filename)
79
	{
80
		$newPost = [];
81
		foreach ($post as $name => $value) {
82
			$newPost[] = ['name' => $name, 'contents' => $value];
83
		}
84
		$newPost[] = ['name' => 'file', 'contents' => fopen($filename, 'r')];
85
86
		$response = $this->request($token, function (GuzzleHttp\Client $client) use ($url, $newPost) {
87
			return $client->request('POST', $url, [GuzzleHttp\RequestOptions::MULTIPART => $newPost]);
88
		}, 'upload');
89
		return self::createXmlResponse($response);
90
	}
91
92
	/**
93
	 * @param $token
94
	 * @param $fallback
95
	 * @param string $action
96
	 * @return GuzzleHttp\Psr7\Stream
97
	 * @throws Fio\QueueLimitException
98
	 * @throws Fio\ServiceUnavailableException
99
	 */
100
	private function request($token, $fallback, $action)
101
	{
102
		$request = new GuzzleHttp\Client(['headers' => ['X-Powered-By' => 'h4kuna/fio']]);
103
		$tempFile = $this->loadFileName($token);
104
		$file = fopen(self::safeProtocol($tempFile), 'w');
105
		$i = 0;
106
		do {
107
			$next = false;
108
			++$i;
109
			try {
110
				$response = $fallback($request);
111
			} catch (GuzzleHttp\Exception\ClientException $e) {
112
				if ($e->getCode() !== self::HEADER_CONFLICT || !$this->sleep) {
113
					fclose($file);
114
					throw $e;
115
				} elseif ($i >= $this->limitLoop) {
116
					fclose($file);
117
					throw new Fio\QueueLimitException('You have limit up requests to server ' . $this->limitLoop);
118
				}
119
				self::sleep($tempFile);
120
				$next = true;
121
			} catch (GuzzleHttp\Exception\ServerException $e) {
122
			    if($e->hasResponse()) {
123
			        self::detectDownloadResponse( $e->getResponse() );
124
                }
125
                throw new Fio\ServiceUnavailableException('Service is currently unavailable');
126
            }
127
		} while ($next);
128
		fclose($file);
129
		touch($tempFile);
130
131
		if ($action === 'download') {
132
			self::detectDownloadResponse($response);
133
		}
134
135
		return $response->getBody();
136
	}
137
138
    /**
139
     * @param $response
140
     * @throws Fio\ServiceUnavailableException
141
     */
142
    private static function detectDownloadResponse($response)
143
	{
144
		/* @var $contentTypeHeaders array */
145
		$contentTypeHeaders = $response->getHeader('Content-Type');
146
		$contentType = array_shift($contentTypeHeaders);
147
		if ($contentType === 'text/xml;charset=UTF-8') {
148
			$xmlResponse = self::createXmlResponse($response);
149
			if ($xmlResponse->getErrorCode() !== 0) {
150
				throw new Fio\ServiceUnavailableException($xmlResponse->getError(), $xmlResponse->getErrorCode());
151
			}
152
		}
153
	}
154
155
	private static function sleep($filename)
156
	{
157
		$criticalTime = time() - filemtime($filename);
158
		if ($criticalTime < self::WAIT_TIME) {
159
			sleep(self::WAIT_TIME - $criticalTime);
160
		}
161
	}
162
163
	/**
164
	 * @param string $token
165
	 * @return string
166
	 */
167
	private function loadFileName($token)
168
	{
169
		$key = substr($token, 10, -10);
170
		if (!isset(self::$tokens[$key])) {
171
			self::$tokens[$key] = $this->tempDir . DIRECTORY_SEPARATOR . md5($key);
172
		}
173
174
		return self::$tokens[$key];
175
	}
176
177
	private static function safeProtocol($filename)
178
	{
179
		return Utils\SafeStream::PROTOCOL . '://' . $filename;
180
	}
181
182
	/**
183
	 * @param $response
184
	 * @return Pay\XMLResponse
185
	 */
186
	private static function createXmlResponse($response)
187
	{
188
		return new Pay\XMLResponse($response->getBody()->getContents());
189
	}
190
191
}
192