Skip to content

Commit

Permalink
Refactor, split tests into smaller files, fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
zaxbux committed Jul 6, 2021
1 parent 614eb5b commit 47d7752
Show file tree
Hide file tree
Showing 50 changed files with 1,651 additions and 1,488 deletions.
3 changes: 3 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
TODO:
☐ Implement all API exceptions
Guzzle:

Tests:
☐ Test all auxillary objects
Objects:
Expand Down
2 changes: 1 addition & 1 deletion src/Classes/AbstractObjectInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/**
* @link https://www.backblaze.com/b2/docs/files.html#fileInfo
*
* @package Zaxbux\BackblazeB2\Object
*/
abstract class AbstractObjectInfo
{
Expand Down
29 changes: 29 additions & 0 deletions src/Classes/BuiltinAuthorizationCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Zaxbux\BackblazeB2\Classes;

use Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;

/**
* A builtin authorization cache.
*
* @package Zaxbux\BackblazeB2\Classes
*/
class BuiltinAuthorizationCache implements AuthorizationCacheInterface
{
/** @var array */
private $storage;

public function put($key, AccountAuthorization $authorization): void
{
$this->storage[(string) $key] = $authorization;
}

public function get($key): ?AccountAuthorization
{
return $this->storage[(string) $key] ?? null;
}
}
2 changes: 1 addition & 1 deletion src/Classes/FilePathInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use function pathinfo;

/** @package Zaxbux\BackblazeB2 */

final class FilePathInfo
{

Expand Down
152 changes: 119 additions & 33 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,68 @@

namespace Zaxbux\BackblazeB2;

use Exception;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\ClientInterface;
use Zaxbux\BackblazeB2\Config;
use Zaxbux\BackblazeB2\Http\Middleware\ApplyAuthorizationMiddleware;
use Zaxbux\BackblazeB2\Http\Middleware\ExceptionMiddleware;
use Zaxbux\BackblazeB2\Http\Middleware\RetryMiddleware;
use Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;
use Zaxbux\BackblazeB2\Service\ApplicationKeyService;
use Zaxbux\BackblazeB2\Service\BucketService;
use Zaxbux\BackblazeB2\Service\FileService;
use Zaxbux\BackblazeB2\Traits\AuthorizationHeaderTrait;
use Zaxbux\BackblazeB2\Traits\BucketServiceHelpersTrait;
use Zaxbux\BackblazeB2\Traits\DeleteAllFilesTrait;
use Zaxbux\BackblazeB2\Traits\FileServiceHelpersTrait;

/** @package Zaxbux\BackblazeB2 */
use Zaxbux\BackblazeB2\Operations\ApplicationKeyOperationsTrait;
use Zaxbux\BackblazeB2\Operations\BucketOperationsTrait;
use Zaxbux\BackblazeB2\Operations\FileOperationsTrait;

/**
* API Client for Backblaze B2.
*
* @package Zaxbux\BackblazeB2
*/
class Client
{
use FileServiceHelpersTrait;
use BucketServiceHelpersTrait;
use AuthorizationHeaderTrait;
public const VERSION = '2.0.0';
public const USER_AGENT_PREFIX = 'backblaze-b2-php/';
public const BASE_URI = 'https://api.backblazeb2.com';
public const B2_API_VERSION = '/b2api/v2';

use FileOperationsTrait;
use BucketOperationsTrait;
use ApplicationKeyOperationsTrait;

/** @var \Zaxbux\BackblazeB2\Config */
protected $config;

/** @var \GuzzleHttp\ClientInterface */
protected $http;

/** @var \Zaxbux\BackblazeB2\Object\AccountAuthorization */
private $accountAuthorization;

use FileService;
use BucketService;
use ApplicationKeyService;
/**
* Get the configuration object for this instance.
*/
public function getConfig(): Config
{
return $this->config;
}

public const B2_API_CLIENT_VERSION = '2.0.0';
public const B2_API_BASE_URL = 'https://api.backblazeb2.com';
public const B2_API_V2 = '/b2api/v2';
/**
* Get the HTTP client for this instance.
*/
public function getHttpClient(): ClientInterface
{
if (!$this->http) {
$this->http = $this->createDefaultHttpClient();
}

/** @var ClientInterface */
public $guzzle;
return $this->http;
}

/** @var AccountAuthorization */
protected $accountAuthorization;
public function accountAuthorization(): ?AccountAuthorization
{
return $this->accountAuthorization;
}

/**
* Create a new instance of the B2 API client for PHP.
Expand All @@ -47,29 +78,84 @@ class Client
public function __construct($config)
{
$this->config = Config::fromArray($config);
}

public function guzzle(): ClientInterface
{
return $this->config->client();
$this->getHttpClient();
}

/**
* Authorize the B2 account in order to get an authorization token and API URLs.
*
* @link https://www.backblaze.com/b2/docs/b2_authorize_account.html
*
* @param string $applicationKeyId
* @param string $applicationKey
* @param ClientInterface $client
*/
public static function authorizeAccount(
string $applicationKeyId,
string $applicationKey,
ClientInterface $client
): AccountAuthorization {
$response = $client->request('GET', static::B2_API_BASE_URL . static::B2_API_V2 . '/b2_authorize_account', [
public function authorizeAccount(): AccountAuthorization {
$response = $this->http->request('GET', Client::BASE_URI . Client::B2_API_VERSION . '/b2_authorize_account', [
'headers' => [
'Authorization' => static::getBasicAuthorization($applicationKeyId, $applicationKey),
'Authorization' => Utils::basicAuthorization($this->config->applicationKeyId(), $this->config->applicationKey()),
],
]);

return AccountAuthorization::fromResponse($response);
}

public function refreshAccountAuthorization() {
// Check cache for account authorization if account is not already authorized.
if (!$this->accountAuthorization && $this->config->authorizationCache() instanceof AuthorizationCacheInterface) {
$this->accountAuthorization = $this->config->authorizationCache()->get($this->config->applicationKeyId());
}

// Refresh the token if it wasn't cached, or if it has expired.
if (!$this->accountAuthorization || $this->accountAuthorization->expired()) {
$this->accountAuthorization = $this->authorizeAccount();

// Cache the new key
if ($this->config->authorizationCache() instanceof AuthorizationCacheInterface) {
$this->config->authorizationCache()->put($this->config->applicationKeyId(), $this->accountAuthorization);
}
}

// If account authorization still doesn't exist, there is an issue.
if (!$this->accountAuthorization) {
throw new Exception('Failed to refresh account authorization.');
}
}

/**
* Creates a new instance of a GuzzleHttp client.
*/
protected function createDefaultHttpClient(): ClientInterface {
$stack = $this->config->handler();

/*foreach ($this->config->middleware() as $name => $middleware) {
$stack->push($middleware, $name ?? '');
}*/

$stack->push(new ExceptionMiddleware(), 'exception_handler');
$stack->push(new ApplyAuthorizationMiddleware($this), 'b2_auth');
$stack->push(new RetryMiddleware($this->config), 'retry');

$client = new GuzzleClient([
'base_uri' => Client::B2_API_VERSION,
'http_errors' => $this->config->useHttpErrors ?? false,
'allow_redirects' => false,
'handler' => $stack,
'headers' => [
//'Accept' => 'application/json, */*;q=0.8',
'User-Agent' => Utils::getUserAgent($this->config->applicationName()),
],
]);

return $client;
}

/**
* @see __construct()
*/
public static function instance($config): Client
{
return new static($config);
}
}
74 changes: 30 additions & 44 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@
use Exception;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\HandlerStack;
use Zaxbux\BackblazeB2\Classes\BuiltinAuthorizationCache;
use Zaxbux\BackblazeB2\Http\ClientFactory;
use Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;

class Config {
/**
* The main configuration object for the client.
*
* @package Zaxbux\BackblazeB2
*/
class Config
{

/**
* The identifier for the key. The account ID can also be used.
Expand All @@ -23,6 +30,12 @@ class Config {
*/
private $applicationKey;

/**
* Application name, included in the User-Agent HTTP header.
* @var string
*/
private $applicationName = '';

/**
* Custom Guzzle handler or handler stack.
* @var callable|\GuzzleHttp\HandlerStack
Expand All @@ -33,7 +46,7 @@ class Config {
* Custom Guzzle client instance.
* @var \GuzzleHttp\ClientInterface
*/
private $client;
//private $http;

/**
* Optional middleware to add to the GuzzleHttp handler stack.
Expand Down Expand Up @@ -83,7 +96,7 @@ class Config {
*/
public $largeFileUploadCustomMinimum = null; //200 * 1024 * 1024;

/**
/**
* An object that implements `AuthorizationCacheInterface` for caching
* account authorization between instances.
*
Expand All @@ -92,7 +105,7 @@ class Config {
private $authorizationCache;

/** @var \Zaxbux\BackblazeB2\Object\AccountAuthorization */
private $accountAuthorization;
//private $accountAuthorization;

public function applicationKeyId(): string
{
Expand All @@ -104,6 +117,16 @@ public function applicationKey(): string
return $this->applicationKey;
}

public function applicationName(): string
{
return $this->applicationName;
}

public function authorizationCache(): AuthorizationCacheInterface
{
return $this->authorizationCache;
}

public function __construct(
string $applicationKeyId,
string $applicationKey,
Expand All @@ -114,13 +137,9 @@ public function __construct(
$this->setOptions($options ?? []);
}

public function client(): ClientInterface
public function middleware(): array
{
if (!$this->client) {
$this->client = ClientFactory::create($this);
}

return $this->client;
return $this->middleware ?? [];
}

public function handler(): HandlerStack
Expand All @@ -146,40 +165,6 @@ public function maxRetryDelay(): int
return $this->maxRetryDelay();
}

/**
*
* @return AccountAuthorization
* @throws Exception
*/
public function accountAuthorization(): AccountAuthorization
{
// Check cache for account authorization if account is not already authorized.
if (!$this->accountAuthorization && $this->authorizationCache instanceof AuthorizationCacheInterface) {
$this->accountAuthorization = $this->authorizationCache->get($this->applicationKeyId);
}

// Refresh the token if it wasn't cached, or if it has expired.
if (!$this->accountAuthorization || $this->accountAuthorization->expired()) {
$this->accountAuthorization = Client::authorizeAccount(
$this->applicationKeyId,
$this->applicationKey,
$this->client()
);

// Cache the new key
if ($this->authorizationCache instanceof AuthorizationCacheInterface) {
$this->authorizationCache->put($this->applicationKeyId, $this->accountAuthorization);
}
}

// If account authorization still doesn't exist, there is an issue.
if (!$this->accountAuthorization) {
throw new Exception('Failed to get account authorization.');
}

return $this->accountAuthorization;
}

/**
*
* @param mixed $data
Expand All @@ -199,5 +184,6 @@ public static function fromArray($data): Config

private function setOptions(array $options) {
$this->handler = $options['handler'] ?? null;
$this->authorizationCache = $options['authorizationCache'] ?? new BuiltinAuthorizationCache();
}
}
Loading

0 comments on commit 47d7752

Please sign in to comment.