Skip to content

Commit f28fa30

Browse files
authored
add fias status checker (#30)
1 parent 272a353 commit f28fa30

File tree

5 files changed

+279
-0
lines changed

5 files changed

+279
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\Exception;
6+
7+
/**
8+
* Исключение, которое выбрасывается, если не удается определить статус ФИАС.
9+
*/
10+
class StatusCheckerException extends Exception
11+
{
12+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\FiasStatusChecker;
6+
7+
use Liquetsoft\Fias\Component\Exception\StatusCheckerException;
8+
use Liquetsoft\Fias\Component\FiasInformer\FiasInformer;
9+
use Throwable;
10+
11+
/**
12+
* Объект, который проверяет статус сервисов ФИАС с помощью запросов через curl.
13+
*/
14+
class CurlStatusChecker implements FiasStatusChecker
15+
{
16+
/**
17+
* @var string
18+
*/
19+
private $wsdlUrl;
20+
21+
/**
22+
* @var FiasInformer
23+
*/
24+
private $informer;
25+
26+
public function __construct(string $wsdlUrl, FiasInformer $informer)
27+
{
28+
$this->wsdlUrl = $wsdlUrl;
29+
$this->informer = $informer;
30+
}
31+
32+
/**
33+
* @inheritDoc
34+
*/
35+
public function check(): StatusCheckerResult
36+
{
37+
if (!$this->sendHeadRequest($this->wsdlUrl)) {
38+
return new StatusCheckerResult(
39+
FiasStatusChecker::STATUS_NOT_AVAILABLE,
40+
[
41+
[
42+
'service' => FiasStatusChecker::SERVICE_INFORMER,
43+
'status' => FiasStatusChecker::STATUS_NOT_AVAILABLE,
44+
'reason' => 'WSDL file is unavailable',
45+
],
46+
[
47+
'service' => FiasStatusChecker::SERVICE_FILE_SERVER,
48+
'status' => FiasStatusChecker::STATUS_UNKNOWN,
49+
'reason' => 'Informer is unavailable',
50+
],
51+
]
52+
);
53+
}
54+
55+
try {
56+
$info = $this->informer->getCompleteInfo();
57+
} catch (Throwable $e) {
58+
return new StatusCheckerResult(
59+
FiasStatusChecker::STATUS_NOT_AVAILABLE,
60+
[
61+
[
62+
'service' => FiasStatusChecker::SERVICE_INFORMER,
63+
'status' => FiasStatusChecker::STATUS_NOT_AVAILABLE,
64+
'reason' => $e->getMessage(),
65+
],
66+
[
67+
'service' => FiasStatusChecker::SERVICE_FILE_SERVER,
68+
'status' => FiasStatusChecker::STATUS_UNKNOWN,
69+
'reason' => 'Informer is unavailable',
70+
],
71+
]
72+
);
73+
}
74+
75+
if (!$this->sendHeadRequest($info->getUrl())) {
76+
return new StatusCheckerResult(
77+
FiasStatusChecker::STATUS_NOT_AVAILABLE,
78+
[
79+
[
80+
'service' => FiasStatusChecker::SERVICE_INFORMER,
81+
'status' => FiasStatusChecker::STATUS_AVAILABLE,
82+
'reason' => '',
83+
],
84+
[
85+
'service' => FiasStatusChecker::SERVICE_FILE_SERVER,
86+
'status' => FiasStatusChecker::STATUS_NOT_AVAILABLE,
87+
'reason' => 'File to download in unaviable',
88+
],
89+
]
90+
);
91+
}
92+
93+
return new StatusCheckerResult(
94+
FiasStatusChecker::STATUS_AVAILABLE,
95+
[
96+
[
97+
'service' => FiasStatusChecker::SERVICE_INFORMER,
98+
'status' => FiasStatusChecker::STATUS_AVAILABLE,
99+
'reason' => '',
100+
],
101+
[
102+
'service' => FiasStatusChecker::SERVICE_FILE_SERVER,
103+
'status' => FiasStatusChecker::STATUS_AVAILABLE,
104+
'reason' => '',
105+
],
106+
]
107+
);
108+
}
109+
110+
/**
111+
* Отправляет HEAD запрос на указанный url и проверяет, что в ответ пришел статус 200.
112+
*
113+
* @param string $url
114+
*
115+
* @return bool
116+
*/
117+
private function sendHeadRequest(string $url): bool
118+
{
119+
$ch = curl_init();
120+
if (!is_resource($ch)) {
121+
throw new StatusCheckerException("Can't init curl resource.");
122+
}
123+
124+
curl_setopt_array(
125+
$ch,
126+
[
127+
CURLOPT_URL => $url,
128+
CURLOPT_FOLLOWLOCATION => true,
129+
CURLOPT_NOBODY => true,
130+
]
131+
);
132+
133+
$res = curl_exec($ch);
134+
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
135+
$error = curl_error($ch);
136+
curl_close($ch);
137+
138+
return empty($error) && $httpCode === 200;
139+
}
140+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\FiasStatusChecker;
6+
7+
/**
8+
* Сервис, который проверяет доступность всех компонентов ФИАС (сервиса информирования, файла для загрузки и т.д.).
9+
*/
10+
interface FiasStatusChecker
11+
{
12+
public const STATUS_AVAILABLE = 'available';
13+
public const STATUS_NOT_AVAILABLE = 'not available';
14+
public const STATUS_UNKNOWN = 'unknown';
15+
16+
public const SERVICE_INFORMER = 'informer';
17+
public const SERVICE_FILE_SERVER = 'file server';
18+
19+
/**
20+
* Проверяет статусы всех компонентов ФИАС.
21+
*
22+
* @return StatusCheckerResult
23+
*/
24+
public function check(): StatusCheckerResult;
25+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\FiasStatusChecker;
6+
7+
/**
8+
* Объект, который содержит информацию о проверке статуса.
9+
*/
10+
class StatusCheckerResult
11+
{
12+
/**
13+
* @var string
14+
*/
15+
private $resultStatus;
16+
17+
/**
18+
* @var array<int, array>
19+
*/
20+
private $perServiceStatuses;
21+
22+
/**
23+
* @param string $resultStatus
24+
* @param array<int, array> $perServiceStatuses
25+
*/
26+
public function __construct(string $resultStatus, array $perServiceStatuses)
27+
{
28+
$this->resultStatus = $resultStatus;
29+
$this->perServiceStatuses = $perServiceStatuses;
30+
}
31+
32+
/**
33+
* Возвращает сттатус общего сосотояния ФИАС.
34+
*
35+
* @return string
36+
*/
37+
public function getResultStatus(): string
38+
{
39+
return $this->resultStatus;
40+
}
41+
42+
/**
43+
* Возвращает массив со статусами по каждому сервису.
44+
*
45+
* @return array<int, array>
46+
*/
47+
public function getPerServiceStatuses(): array
48+
{
49+
return $this->perServiceStatuses;
50+
}
51+
}

src/Pipeline/Task/CheckStatusTask.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Liquetsoft\Fias\Component\Pipeline\Task;
6+
7+
use Liquetsoft\Fias\Component\Exception\StatusCheckerException;
8+
use Liquetsoft\Fias\Component\FiasStatusChecker\FiasStatusChecker;
9+
use Liquetsoft\Fias\Component\Pipeline\State\State;
10+
use Psr\Log\LogLevel;
11+
12+
/**
13+
* Задача, которая проверяет статус ФИАС.
14+
*/
15+
class CheckStatusTask implements Task, LoggableTask
16+
{
17+
use LoggableTaskTrait;
18+
19+
/**
20+
* @var FiasStatusChecker
21+
*/
22+
protected $checker;
23+
24+
/**
25+
* @param FiasStatusChecker $checker
26+
*/
27+
public function __construct(FiasStatusChecker $checker)
28+
{
29+
$this->checker = $checker;
30+
}
31+
32+
/**
33+
* @inheritDoc
34+
*/
35+
public function run(State $state): void
36+
{
37+
$status = $this->checker->check();
38+
39+
if ($status->getResultStatus() !== FiasStatusChecker::STATUS_AVAILABLE) {
40+
$message = 'FIAS is unavailable.';
41+
$this->log(
42+
LogLevel::ERROR,
43+
$message,
44+
[
45+
'services_statuses' => $status->getPerServiceStatuses(),
46+
]
47+
);
48+
throw new StatusCheckerException($message);
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)