Skip to content

Commit

Permalink
Retry connection with a new header (#4)
Browse files Browse the repository at this point in the history
* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

* Retry connection with a new header

(cherry picked from commit 7028acc)
  • Loading branch information
arsafiso authored and frets1700 committed Jan 7, 2022
1 parent 3fd1979 commit d4cf9cd
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 3 deletions.
47 changes: 47 additions & 0 deletions src/Http/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@
use Symplicity\Outlook\Interfaces\Http\ConnectionInterface;
use Symplicity\Outlook\Interfaces\Http\RequestOptionsInterface;
use Symplicity\Outlook\Utilities\RequestType;
use Symplicity\Outlook\Interfaces\Http\RequestInterface;

class Connection implements ConnectionInterface
{
public const MAX_RETRIES = 3;
public const MAX_UPSERT_RETRIES = 5;
public $requestArgs;

protected $clientOptions;
protected $responses;
protected $logger;

protected static $eventInfo = [];

/** @var RequestInterface $requestHandler */
private $requestHandler;

public function __construct(?LoggerInterface $logger, array $clientOptions = [])
{
$this->logger = $logger;
Expand All @@ -39,6 +44,9 @@ public function __construct(?LoggerInterface $logger, array $clientOptions = [])

public function get(string $url, RequestOptionsInterface $requestOptions, array $args = []) : ResponseInterface
{
$this->requestArgs = $args;
$this->requestArgs['url'] = $url;

$client = $this->createClientWithRetryHandler();
$options = [
'headers' => $requestOptions->getHeaders()
Expand All @@ -50,6 +58,28 @@ public function get(string $url, RequestOptionsInterface $requestOptions, array

try {
return $client->request(RequestType::Get, $url, $options);
} catch (\Exception $e) {
if ($this->logger instanceof LoggerInterface) {
$this->logger->warning('Get Request Failed', [
'error' => $e->getMessage(),
'code' => $e->getCode()
]);
}
$responseCode = $e->getCode();
}

if ($responseCode === 401) {
return $this->retryConnection($client, $url);
}

throw new ConnectionException(sprintf('Unable to GET for URL %s', $url), $e->getCode());
}

public function retryConnection(ClientInterface $client, string $url): ResponseInterface
{
try {
$headers = $this->tryRefreshHeaderToken();
return $client->request(RequestType::Get, $url, ['headers' => $headers]);
} catch (\Exception $e) {
if ($this->logger instanceof LoggerInterface) {
$this->logger->warning('Get Request Failed', [
Expand Down Expand Up @@ -214,4 +244,21 @@ protected function shouldRetry(int $statusCode) : bool
{
return in_array($statusCode, [401, 403, 408, 429]) || $statusCode >= 500;
}

public function tryRefreshHeaderToken(): array
{
if ($this->requestHandler instanceof RequestInterface && isset($this->requestArgs['url'], $this->requestArgs['token'])) {
return $this->requestHandler->getHeadersWithToken($this->requestArgs['url'], [
'token' => $this->requestArgs['token'],
'logger' => $this->logger
]);
}

return [];
}

public function setRequestHandler(RequestInterface $requestHandler) : void
{
$this->requestHandler = $requestHandler;
}
}
43 changes: 41 additions & 2 deletions src/Http/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
use Symplicity\Outlook\Interfaces\Http\ConnectionInterface;
use Symplicity\Outlook\Interfaces\Http\ResponseIteratorInterface;
use Symplicity\Outlook\Utilities\RequestType;
use Symplicity\Outlook\Token;
use Symplicity\Outlook\Interfaces\Http\RequestInterface;

class Request
class Request implements RequestInterface
{
public const OUTLOOK_VERSION = 'v2.0';
public const OUTLOOK_ROOT_URL = 'https://outlook.office.com/api/';
Expand Down Expand Up @@ -88,7 +90,12 @@ public function getEvent(string $url, array $params = []): ResponseInterface
'outlook.timezone="' . $requestOptions->getPreferredTimezone() . '"'
]));

return $this->connection->get($url, $requestOptions, ['skipQueryParams' => $params['skipQueryParams'] ?? true]);
$args = [
'skipQueryParams' => $params['skipQueryParams'] ?? true,
'token' => !empty($params['token']) ? $params['token'] : '',
];
$this->connection->setRequestHandler($this);
return $this->connection->get($url, $requestOptions, $args);
}

public function getEventIterator(string $url, array $params = []): ResponseIteratorInterface
Expand Down Expand Up @@ -213,4 +220,36 @@ public static function getBatchApi()
{
return static::OUTLOOK_ROOT_URL . static::OUTLOOK_VERSION . DIRECTORY_SEPARATOR . self::OUTLOOK_BATCH_ENDPOINT;
}

public function getHeadersWithToken(string $url, array $params = []): array
{
$token = isset($params['token']) ? $params['token'] : [];
if (isset($token['clientID'], $token['clientSecret'], $token['outlookProxyUrl'])) {
$tokenObj = new Token($token['clientID'], $token['clientSecret'], ['logger' => $params['logger']]);
$tokenEntity = $tokenObj->refresh($token['refreshToken'], $token['outlookProxyUrl']);
$accessToken = $tokenEntity->getAccessToken();
if ($accessToken) {
return $this->getHeaders($url, [
'headers' => [],
'timezone' => RequestOptions::DEFAULT_TIMEZONE,
'preferenceHeaders' => [],
'token' => $accessToken
]);
}
}

return [];
}

public function getHeaders(string $url, array $options): array
{
/** @var RequestOptions $requestOptions */
$requestOptions = $this->requestOptions->call($this, $url, RequestType::Get(), $options);
$requestOptions->addDefaultHeaders(true);
$requestOptions->addPreferenceHeaders(array_merge($requestOptions->getDefaultPreferenceHeaders(), [
'outlook.timezone="' . $requestOptions->getPreferredTimezone() . '"'
]));

return $requestOptions->getHeaders();
}
}
6 changes: 6 additions & 0 deletions src/Interfaces/Http/ConnectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use GuzzleHttp\ClientInterface;
use Psr\Http\Message\ResponseInterface;
use Symplicity\Outlook\Exception\ConnectionException;
use Symplicity\Outlook\Interfaces\Http\RequestInterface;

interface ConnectionInterface
{
Expand Down Expand Up @@ -48,4 +49,9 @@ public function upsert(string $url, RequestOptionsInterface $requestOptions) : R
* @return ResponseInterface
*/
public function delete(string $url, RequestOptionsInterface $requestOptions) : ResponseInterface;

/**
* Set Request Handler Obj
*/
public function setRequestHandler(RequestInterface $requestHandler) : void;
}
16 changes: 16 additions & 0 deletions src/Interfaces/Http/RequestInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Symplicity\Outlook\Interfaces\Http;

interface RequestInterface
{
/**
* Get Headers with refreshed token
* @param string $url
* @param array $params
* @return array
*/
public function getHeadersWithToken(string $url, array $params = []) : array;
}
33 changes: 32 additions & 1 deletion tests/Http/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use Psr\Http\Message\ResponseInterface;
use Symplicity\Outlook\Http\Connection;
use Symplicity\Outlook\Http\RequestOptions;
use Symplicity\Outlook\Interfaces\Utils\BatchResponseInterface;
use Symplicity\Outlook\Http\Request as outlookRequest;
use Symplicity\Outlook\Utilities\RequestType;

class ConnectionTest extends TestCase
Expand Down Expand Up @@ -183,4 +183,35 @@ public function getRetryHandlerData(): array
[new Request(RequestType::Delete, 'outlook.com'), new Response(429, ['Content-Length' => 0], stream_for('Client Error')), 11, false]
];
}

public function testTryRefreshHeaderToken()
{
$logger = new Logger('outlook-calendar', [$this->handler]);
$connectionHandler = new Connection($logger);
$this->assertEmpty($connectionHandler->tryRefreshHeaderToken());

$requestObj = new outlookRequest('123', ['connection' => $this->connection, 'requestOptions' => null]);
$connectionHandler->setRequestHandler($requestObj);
$connectionHandler->requestArgs = [
'url' => 'test.com',
'token' => 'test',
];
$this->assertEmpty($connectionHandler->tryRefreshHeaderToken());

$requestObj = $this->createMock(outlookRequest::class);
$requestObj->method('getHeadersWithToken')
->willReturn(['foo']);
$connectionHandler->setRequestHandler($requestObj);
$connectionHandler->requestArgs = [
'url' => 'test.com',
'token' => [
'clientID' => '123',
'clientSecret' => '456',
'refreshToken' => '789',
'outlookProxyUrl' => 'https://test.com/',
],
'logger' => $logger,
];
$this->assertEquals(['foo'], $connectionHandler->tryRefreshHeaderToken());
}
}
48 changes: 48 additions & 0 deletions tests/Http/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,52 @@ public function testGetEvents()
$this->assertInstanceOf(RequestOptionsInterface::class, $requestOptions);
$this->assertEquals(RequestType::Get, $requestOptions->getMethod());
}

public function testGetHeadersWithToken()
{
$connection = $this->getMockBuilder(Connection::class)
->disableOriginalConstructor()
->onlyMethods(['get'])
->getMock();

$constructorArgs = [
'requestOptions' => function () {
return new RequestOptions('test.com', RequestType::Get(), [
'token' => 'foo'
]);
},
'connection' => $connection
];
$request = new Request('foo', $constructorArgs);

$this->assertEmpty($request->getHeadersWithToken('test.com'));
}

public function testGetHeaders()
{
$connection = $this->getMockBuilder(Connection::class)
->disableOriginalConstructor()
->onlyMethods(['get'])
->getMock();

$request = new Request('foo', [
'requestOptions' => function () {
return new RequestOptions('test.com', RequestType::Get(), [
'token' => 'foo'
]);
},
'connection' => $connection
]);

$this->assertNotEmpty($request->getHeaders('test.com', [
'headers' => [],
'timezone' => RequestOptions::DEFAULT_TIMEZONE,
'preferenceHeaders' => [],
'token' => '123'
]));

$this->assertNotEmpty($request->getHeaders('test.com', []));

$this->assertNotEmpty($request->getHeaders('', []));
}
}

0 comments on commit d4cf9cd

Please sign in to comment.