-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eb1aace
commit f88c0a6
Showing
21 changed files
with
1,703 additions
and
861 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Inspirum\Balikobot\Client; | ||
|
||
interface Client | ||
{ | ||
/** | ||
* Call API server, parse and validate response data | ||
* | ||
* @param array<mixed,mixed> $data | ||
* | ||
* @return array<mixed,mixed> | ||
* | ||
* @throws \Inspirum\Balikobot\Exception\Exception | ||
*/ | ||
public function call( | ||
string $version, | ||
?string $carrier, | ||
string $request, | ||
array $data = [], | ||
string $path = '', | ||
bool $shouldHaveStatus = true, | ||
bool $gzip = false, | ||
): array; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Inspirum\Balikobot\Client; | ||
|
||
use GuzzleHttp\Psr7\Response; | ||
use Psr\Http\Message\ResponseInterface; | ||
use RuntimeException; | ||
use function base64_encode; | ||
use function count; | ||
use function curl_close; | ||
use function curl_errno; | ||
use function curl_error; | ||
use function curl_exec; | ||
use function curl_getinfo; | ||
use function curl_init; | ||
use function curl_setopt; | ||
use function json_encode; | ||
use function sprintf; | ||
use const CURLINFO_HTTP_CODE; | ||
use const CURLOPT_HEADER; | ||
use const CURLOPT_HTTPHEADER; | ||
use const CURLOPT_POST; | ||
use const CURLOPT_POSTFIELDS; | ||
use const CURLOPT_RETURNTRANSFER; | ||
use const CURLOPT_SSL_VERIFYHOST; | ||
use const CURLOPT_SSL_VERIFYPEER; | ||
use const CURLOPT_URL; | ||
|
||
final class CurlRequester implements Requester | ||
{ | ||
public function __construct( | ||
private string $apiUser, | ||
private string $apiKey, | ||
private bool $sslVerify = true, | ||
) { | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function request(string $url, array $data = []): ResponseInterface | ||
{ | ||
// init curl | ||
$ch = curl_init(); | ||
|
||
// set headers | ||
curl_setopt($ch, CURLOPT_URL, $url); | ||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
curl_setopt($ch, CURLOPT_HEADER, false); | ||
|
||
// disable SSL verification | ||
if ($this->sslVerify === false) { | ||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); | ||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | ||
} | ||
|
||
// set data | ||
if (count($data) > 0) { | ||
curl_setopt($ch, CURLOPT_POST, true); | ||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); | ||
} | ||
|
||
// set auth | ||
curl_setopt($ch, CURLOPT_HTTPHEADER, [ | ||
sprintf('Authorization: Basic %s', base64_encode(sprintf('%s:%s', $this->apiUser, $this->apiKey))), | ||
'Content-Type: application/json', | ||
]); | ||
|
||
// execute curl | ||
$response = curl_exec($ch); | ||
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | ||
|
||
// check for errors. | ||
if ($response === false) { | ||
throw new RuntimeException(curl_error($ch), curl_errno($ch)); | ||
} | ||
|
||
// close curl | ||
curl_close($ch); | ||
|
||
return new Response((int) $statusCode, [], (string) $response); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Inspirum\Balikobot\Client; | ||
|
||
use GuzzleHttp\Psr7\InflateStream; | ||
use Inspirum\Balikobot\Exception\BadRequestException; | ||
use Inspirum\Balikobot\Response\Validator; | ||
use JsonException; | ||
use Psr\Http\Message\StreamInterface; | ||
use Throwable; | ||
use function json_decode; | ||
use function sprintf; | ||
use function str_replace; | ||
use function trim; | ||
use const JSON_THROW_ON_ERROR; | ||
|
||
final class DefaultClient implements Client | ||
{ | ||
public function __construct( | ||
private Requester $requester, | ||
private Validator $validator, | ||
) { | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function call( | ||
string $version, | ||
?string $carrier, | ||
string $request, | ||
array $data = [], | ||
string $path = '', | ||
bool $shouldHaveStatus = true, | ||
bool $gzip = false, | ||
): array { | ||
$url = $this->resolveUrl($version, $carrier, $request, $path, $gzip); | ||
|
||
$response = $this->requester->request($url, $data); | ||
|
||
$statusCode = $response->getStatusCode(); | ||
$contents = $this->getContents($response->getBody(), $gzip); | ||
$parsedContent = $this->parseContents($contents, $statusCode < 300); | ||
|
||
$this->validateResponse($statusCode, $parsedContent, $shouldHaveStatus); | ||
|
||
return $parsedContent; | ||
} | ||
|
||
private function resolveUrl(string $version, ?string $carrier, string $request, string $path, bool $gzip): string | ||
{ | ||
$url = sprintf('%s/%s/%s', $carrier, $request, $path); | ||
$url = trim(str_replace('//', '/', $url), '/'); | ||
|
||
if ($gzip) { | ||
$url = sprintf('%s?gzip=1', $path); | ||
} | ||
|
||
return sprintf('%s/%s', $version, $url); | ||
} | ||
|
||
/** | ||
* @return array<mixed,mixed> | ||
* | ||
* @throws \Inspirum\Balikobot\Exception\Exception | ||
*/ | ||
private function parseContents(string $content, bool $throwOnError): array | ||
{ | ||
try { | ||
return json_decode($content, true, flags: JSON_THROW_ON_ERROR); | ||
} catch (JsonException $exception) { | ||
if ($throwOnError) { | ||
throw new BadRequestException([], 400, $exception, 'Cannot parse response data'); | ||
} | ||
|
||
return []; | ||
} | ||
} | ||
|
||
private function getContents(StreamInterface $stream, bool $gzip): string | ||
{ | ||
if ($gzip === false) { | ||
return $stream->getContents(); | ||
} | ||
|
||
try { | ||
$inflateStream = new InflateStream($stream); | ||
|
||
return $inflateStream->getContents(); | ||
} catch (Throwable) { | ||
$stream->rewind(); | ||
|
||
return $stream->getContents(); | ||
} | ||
} | ||
|
||
/** | ||
* @param array<mixed,mixed> $response | ||
* | ||
* @throws \Inspirum\Balikobot\Exception\Exception | ||
*/ | ||
private function validateResponse(int $statusCode, array $response, bool $shouldHaveStatus): void | ||
{ | ||
$this->validator->validateStatus($statusCode, $response); | ||
|
||
$this->validator->validateResponseStatus($response, null, $shouldHaveStatus); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Inspirum\Balikobot\Client; | ||
|
||
use Psr\Http\Message\ResponseInterface; | ||
|
||
interface Requester | ||
{ | ||
/** | ||
* @param array<mixed,mixed> $data | ||
*/ | ||
public function request(string $url, array $data = []): ResponseInterface; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.