Skip to content

Commit

Permalink
Reorganize authorization logic, fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zaxbux committed Jul 6, 2021
1 parent edeea80 commit 614eb5b
Show file tree
Hide file tree
Showing 19 changed files with 619 additions and 620 deletions.
111 changes: 29 additions & 82 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,124 +5,71 @@
namespace Zaxbux\BackblazeB2;

use GuzzleHttp\ClientInterface;
use Zaxbux\BackblazeB2\Http\ClientFactory;
use Zaxbux\BackblazeB2\Config;
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 */
class Client
{
use FileServiceHelpersTrait;
use BucketServiceHelpersTrait;
use AuthorizationHeaderTrait;

use FileService;
use BucketService;
use ApplicationKeyService;
use FileServiceHelpersTrait {
FileServiceHelpersTrait::deleteAllFileVersions as deleteAllFileVersions;
}

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';

/** @var ApplicationKeyServiceInstance */
//public $key;

/** @var FileServiceInstance */
//public $file;

/** @var BucketServiceInstance */
//public $bucket;

/** @var ClientInterface */
public $guzzle;

/** @var string */
protected $applicationKeyId;

/** @var string */
protected $applicationKey;

/** @var AccountAuthorization */
protected $accountAuthorization;

/** @var AuthorizationCacheInterface */
protected $authorizationCache;

/**
* Client constructor.
*
* @param string $applicationKeyId The identifier for the key. The account ID can also be used.
* @param string $applicationKey The secret part of the key. The master application key can also be used.
* Create a new instance of the B2 API client for PHP.
*
* @param AuthorizationCacheInterface $authorizationCache [optional] An object implementing an authorization cache.
* @param ClientInterface $client [optional] A client compatible with `GuzzleHttp\ClientInterface`.
* @param array|Config $config One of three possible values:
* 1. An array with application keys: `["application_key_id", "application_key"]`
* 2. An associative array of config options
* 3. An instance of a configuration object (@see \Zaxbux\BackblazeB2\Config)
*/
public function __construct(
string $applicationKeyId,
string $applicationKey,
?AuthorizationCacheInterface $authorizationCache = null,
?array $options = []
) {
$this->applicationKeyId = $applicationKeyId;
$this->applicationKey = $applicationKey;
$this->authorizationCache = $authorizationCache;

$config = new Config($this->getAccountAuthorization());

$this->guzzle = $options['client'] ?? ClientFactory::create($config, $options['handler'] ?? null);
$this->authorize();
}

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

public function getApplicationKey(): string
public function __construct($config)
{
return $this->applicationKey;
$this->config = Config::fromArray($config);
}

public function getAccountAuthorization(): ?AccountAuthorization
public function guzzle(): ClientInterface
{
if (!$this->accountAuthorization) {
$this->accountAuthorization = new AccountAuthorization($this->applicationKeyId, $this->applicationKey);
}

return $this->accountAuthorization;
return $this->config->client();
}

/*public function setAccountAuthorization(AccountAuthorization $accountAuthorization): void
{
//$this->accountAuthorization = $accountAuthorization;
}*/

/**
* Authorize the B2 account in order to get an auth token and API/download URLs.
* 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
*/
public function authorize()
{
// Try to fetch existing authorization token from cache.
if ($this->authorizationCache instanceof AuthorizationCacheInterface) {
$this->accountAuthorization = $this->authorizationCache->get($this->applicationKeyId);
}

// Fetch a new authorization token from the API.
if (!$this->accountAuthorization) {
$this->accountAuthorization = $this->getAccountAuthorization();
} //else {
$this->accountAuthorization->refresh($this->guzzle);
//}

// Cache the new authorization token.
if ($this->authorizationCache instanceof AuthorizationCacheInterface && $this->accountAuthorization) {
$this->authorizationCache->put($this->applicationKeyId, $this->accountAuthorization);
}
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', [
'headers' => [
'Authorization' => static::getBasicAuthorization($applicationKeyId, $applicationKey),
],
]);

return AccountAuthorization::fromResponse($response);
}
}
162 changes: 157 additions & 5 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,43 @@

namespace Zaxbux\BackblazeB2;

use Exception;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\HandlerStack;
use Zaxbux\BackblazeB2\Http\ClientFactory;
use Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface;
use Zaxbux\BackblazeB2\Object\AccountAuthorization;

class Config {

public $auth;
/**
* The identifier for the key. The account ID can also be used.
* @var string
*/
private $applicationKeyId;

/**
* The secret part of the key. The master application key can also be used.
* @var string
*/
private $applicationKey;

/**
* Custom Guzzle handler or handler stack.
* @var callable|\GuzzleHttp\HandlerStack
*/
private $handler;

/** @var array */
/**
* Custom Guzzle client instance.
* @var \GuzzleHttp\ClientInterface
*/
private $client;

/**
* Optional middleware to add to the GuzzleHttp handler stack.
* @var array
*/
public $middleware = [];

/** @var bool */
Expand All @@ -18,7 +48,16 @@ class Config {
* Number of times to retry an API call before throwing an exception.
* @var int
*/
public $maxRetries = 3;
public $maxRetries = 4;

/**
* Maximum amount of time, in seconds, to wait before retrying a failed request.
* Ignored for HTTP status codes: 429, 503.
* Should be a power of 3.
*
* @var int
*/
public $maxRetryDelay = 64;

/**
* Download files with Server-Side Encryption headers instead of using query parameters.
Expand All @@ -44,8 +83,121 @@ class Config {
*/
public $largeFileUploadCustomMinimum = null; //200 * 1024 * 1024;

public function __construct(AccountAuthorization $auth = null)
/**
* An object that implements `AuthorizationCacheInterface` for caching
* account authorization between instances.
*
* @var \Zaxbux\BackblazeB2\Interfaces\AuthorizationCacheInterface
*/
private $authorizationCache;

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

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

public function applicationKey(): string
{
$this->auth = $auth;
return $this->applicationKey;
}

public function __construct(
string $applicationKeyId,
string $applicationKey,
?array $options = null
) {
$this->applicationKeyId = $applicationKeyId;
$this->applicationKey = $applicationKey;
$this->setOptions($options ?? []);
}

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

return $this->client;
}

public function handler(): HandlerStack
{
if (!$this->handler) {
$this->handler = new HandlerStack();
}

if (is_callable($this->handler) && !$this->handler instanceof HandlerStack) {
$this->handler = new HandlerStack(($this->handler));
}

return $this->handler;
}

public function maxRetries(): int
{
return $this->maxRetries;
}

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
* @return Config
*/
public static function fromArray($data): Config
{
// Return existing instance
if ($data instanceof Config) return $data;

return new static(
$data['applicationKeyId'] ?? $data[0],
$data['applicationKey'] ?? $data[1],
$data
);
}

private function setOptions(array $options) {
$this->handler = $options['handler'] ?? null;
}
}
4 changes: 2 additions & 2 deletions src/Helpers/LargeFileUpload.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,12 @@ public function getFile() {

private function minimumPartSize(): int
{
return $this->client->getAccountAuthorization()->getAbsoluteMinimumPartSize();
return $this->config->accountAuthorization()->getAbsoluteMinimumPartSize();
}

private function recommendedPartSize(): int
{
return $this->client->getAccountAuthorization()->getRecommendedPartSize();
return $this->config->accountAuthorization()->getRecommendedPartSize();
}

private function remainingBytes(): int
Expand Down
Loading

0 comments on commit 614eb5b

Please sign in to comment.