support S3 compatible storage providers (#401)

This commit is contained in:
Saeed Vaziry
2024-12-22 23:06:36 +01:00
committed by GitHub
parent db81583884
commit ea3d64607a
20 changed files with 127 additions and 576 deletions

View File

@ -3,46 +3,89 @@
namespace App\StorageProviders;
use App\Models\Server;
use App\Models\StorageProvider;
use App\SSH\Storage\S3 as S3Storage;
use App\SSH\Storage\Storage;
use Aws\S3\Exception\S3Exception;
use Aws\S3\S3Client;
use Illuminate\Support\Facades\Log;
class S3 extends S3AbstractStorageProvider
class S3 extends AbstractStorageProvider
{
protected StorageProvider $storageProvider;
protected ?S3Client $client = null;
protected array $clientConfig = [];
public function getApiUrl(): string
{
if (isset($this->storageProvider->credentials['api_url']) && $this->storageProvider->credentials['api_url']) {
return $this->storageProvider->credentials['api_url'];
}
$region = $this->storageProvider->credentials['region'];
return "https://s3.{$region}.amazonaws.com";
}
public function getClient(): S3Client
{
return new S3Client($this->clientConfig);
}
/**
* Build the configuration array for the S3 client.
* This method can be overridden by child classes to modify the configuration.
*/
public function buildClientConfig(): array
{
$this->clientConfig = [
'credentials' => [
'key' => $this->storageProvider->credentials['key'],
'secret' => $this->storageProvider->credentials['secret'],
],
'region' => $this->storageProvider->credentials['region'],
'version' => 'latest',
'endpoint' => $this->getApiUrl(),
];
return $this->clientConfig;
}
public function validationRules(): array
{
return [
'api_url' => 'nullable',
'key' => 'required',
'secret' => 'required',
'region' => 'required',
'bucket' => 'required',
'path' => 'required',
'path' => 'nullable',
];
}
public function credentialData(array $input): array
{
return [
'api_url' => $input['api_url'] ?? '',
'key' => $input['key'],
'secret' => $input['secret'],
'region' => $input['region'],
'bucket' => $input['bucket'],
'path' => $input['path'],
'path' => $input['path'] ?? '',
];
}
public function connect(): bool
{
try {
$this->setBucketRegion($this->storageProvider->credentials['region']);
$this->setApiUrl();
$this->buildClientConfig();
$this->getClient()->listBuckets();
return true;
} catch (S3Exception $e) {
Log::error('Failed to connect to S3', ['exception' => $e]);
Log::error('Failed to connect to the provider', ['exception' => $e]);
return false;
}

View File

@ -1,74 +0,0 @@
<?php
namespace App\StorageProviders;
use App\Models\StorageProvider;
use Aws\S3\S3Client;
abstract class S3AbstractStorageProvider extends AbstractStorageProvider implements S3ClientInterface, S3StorageInterface
{
protected ?string $apiUrl = null;
protected ?string $bucketRegion = null;
protected ?S3Client $client = null;
protected StorageProvider $storageProvider;
protected array $clientConfig = [];
public function getApiUrl(): string
{
return $this->apiUrl;
}
public function setApiUrl(?string $region = null): void
{
$this->bucketRegion = $region ?? $this->bucketRegion;
$this->apiUrl = "https://s3.{$this->bucketRegion}.amazonaws.com";
}
public function getBucketRegion(): string
{
return $this->bucketRegion;
}
public function setBucketRegion(string $region): void
{
$this->bucketRegion = $region;
}
public function getClient(): S3Client
{
return new S3Client($this->clientConfig);
}
/**
* Build the configuration array for the S3 client.
* This method can be overridden by child classes to modify the configuration.
*/
public function buildClientConfig(): array
{
$this->clientConfig = [
'credentials' => [
'key' => $this->storageProvider->credentials['key'],
'secret' => $this->storageProvider->credentials['secret'],
],
'region' => $this->getBucketRegion(),
'version' => 'latest',
'endpoint' => $this->getApiUrl(),
];
return $this->clientConfig;
}
/**
* Set or update a configuration parameter for the S3 client.
*/
public function setConfigParam(array $param): void
{
foreach ($param as $key => $value) {
$this->clientConfig[$key] = $value;
}
}
}

View File

@ -1,10 +0,0 @@
<?php
namespace App\StorageProviders;
use Aws\S3\S3Client;
interface S3ClientInterface
{
public function getClient(): S3Client;
}

View File

@ -1,14 +0,0 @@
<?php
namespace App\StorageProviders;
interface S3StorageInterface
{
public function getApiUrl(): string;
public function setApiUrl(?string $region = null): void;
public function getBucketRegion(): string;
public function setBucketRegion(string $region): void;
}

View File

@ -1,85 +0,0 @@
<?php
namespace App\StorageProviders;
use App\Models\Server;
use App\SSH\Storage\Storage;
use App\SSH\Storage\Wasabi as WasabiStorage;
use Aws\S3\Exception\S3Exception;
use Illuminate\Support\Facades\Log;
class Wasabi extends S3AbstractStorageProvider
{
private const DEFAULT_REGION = 'us-east-1';
public function validationRules(): array
{
return [
'key' => 'required',
'secret' => 'required',
'region' => 'required',
'bucket' => 'required',
'path' => 'required',
];
}
public function credentialData(array $input): array
{
return [
'key' => $input['key'],
'secret' => $input['secret'],
'region' => $input['region'],
'bucket' => $input['bucket'],
'path' => $input['path'],
];
}
public function connect(): bool
{
try {
$this->setBucketRegion(self::DEFAULT_REGION);
$this->setApiUrl();
$this->buildClientConfig();
$this->getClient()->listBuckets();
return true;
} catch (S3Exception $e) {
Log::error('Failed to connect to S3', ['exception' => $e]);
return false;
}
}
/**
* Build the configuration array for the S3 client.
* This method can be overridden by child classes to modify the configuration.
*/
public function buildClientConfig(): array
{
$this->clientConfig = [
'credentials' => [
'key' => $this->storageProvider->credentials['key'],
'secret' => $this->storageProvider->credentials['secret'],
],
'region' => $this->getBucketRegion(),
'version' => 'latest',
'endpoint' => $this->getApiUrl(),
'use_path_style_endpoint' => true,
];
return $this->clientConfig;
}
public function ssh(Server $server): Storage
{
return new WasabiStorage($server, $this->storageProvider);
}
public function setApiUrl(?string $region = null): void
{
$this->bucketRegion = $region ?? $this->bucketRegion;
$this->apiUrl = "https://s3.{$this->bucketRegion}.wasabisys.com";
}
public function delete(array $paths): void {}
}