Completed
Push — master ( ab2f96...fa51a1 )
by Milan
16:08
created

Queue::detectDownloadResponse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 3
eloc 7
nc 3
nop 1
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
			}
122
		} while ($next);
123
		fclose($file);
124
		touch($tempFile);
125
126
		if ($action === 'download') {
127
			self::detectDownloadResponse($response);
128
		}
129
130
		return $response->getBody();
131
	}
132
133
	private static function detectDownloadResponse($response)
134
	{
135
		/* @var $contentTypeHeaders array */
136
		$contentTypeHeaders = $response->getHeader('Content-Type');
137
		$contentType = array_shift($contentTypeHeaders);
138
		if ($contentType === 'text/xml;charset=UTF-8') {
139
			$xmlResponse = self::createXmlResponse($response);
140
			if ($xmlResponse->getErrorCode() !== 0) {
141
				throw new Fio\ServiceUnavailableException($xmlResponse->getError(), $xmlResponse->getErrorCode());
142
			}
143
		}
144
	}
145
146
	private static function sleep($filename)
147
	{
148
		$criticalTime = time() - filemtime($filename);
149
		if ($criticalTime < self::WAIT_TIME) {
150
			sleep(self::WAIT_TIME - $criticalTime);
151
		}
152
	}
153
154
	/**
155
	 * @param string $token
156
	 * @return string
157
	 */
158
	private function loadFileName($token)
159
	{
160
		$key = substr($token, 10, -10);
161
		if (!isset(self::$tokens[$key])) {
162
			self::$tokens[$key] = $this->tempDir . DIRECTORY_SEPARATOR . md5($key);
163
		}
164
165
		return self::$tokens[$key];
166
	}
167
168
	private static function safeProtocol($filename)
169
	{
170
		return Utils\SafeStream::PROTOCOL . '://' . $filename;
171
	}
172
173
	/**
174
	 * @param $response
175
	 * @return Pay\XMLResponse
176
	 */
177
	private static function createXmlResponse($response)
178
	{
179
		return new Pay\XMLResponse($response->getContents());
180
	}
181
182
}
183