optimizations
This commit is contained in:
149
app/Console/Commands/TestObjectStorageUploadCommand.php
Normal file
149
app/Console/Commands/TestObjectStorageUploadCommand.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Throwable;
|
||||
|
||||
final class TestObjectStorageUploadCommand extends Command
|
||||
{
|
||||
protected $signature = 'storage:test-upload
|
||||
{--disk=s3 : Filesystem disk to test}
|
||||
{--file= : Optional absolute or relative path to an existing local file to upload}
|
||||
{--path= : Optional remote object key to use}
|
||||
{--keep : Keep the uploaded test object instead of deleting it afterwards}';
|
||||
|
||||
protected $description = 'Upload a probe file to the configured object storage disk and verify that it was stored.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$diskName = (string) $this->option('disk');
|
||||
$diskConfig = config("filesystems.disks.{$diskName}");
|
||||
|
||||
if (! is_array($diskConfig)) {
|
||||
$this->error("Filesystem disk [{$diskName}] is not configured.");
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$this->line('Testing object storage upload.');
|
||||
$this->line('Disk: '.$diskName);
|
||||
$this->line('Driver: '.(string) ($diskConfig['driver'] ?? 'unknown'));
|
||||
$this->line('Bucket: '.(string) ($diskConfig['bucket'] ?? 'n/a'));
|
||||
$this->line('Region: '.(string) ($diskConfig['region'] ?? 'n/a'));
|
||||
$this->line('Endpoint: '.((string) ($diskConfig['endpoint'] ?? '') !== '' ? (string) $diskConfig['endpoint'] : '[not set]'));
|
||||
$this->line('Path style: '.((bool) ($diskConfig['use_path_style_endpoint'] ?? false) ? 'true' : 'false'));
|
||||
|
||||
if ((string) ($diskConfig['endpoint'] ?? '') === '') {
|
||||
$this->warn('No endpoint is configured for this S3 disk. Many S3-compatible providers, including Contabo object storage, require AWS_ENDPOINT to be set.');
|
||||
}
|
||||
|
||||
$remotePath = $this->resolveRemotePath();
|
||||
$keepObject = (bool) $this->option('keep');
|
||||
$sourceFile = $this->option('file');
|
||||
$filesystem = Storage::disk($diskName);
|
||||
|
||||
try {
|
||||
if (is_string($sourceFile) && trim($sourceFile) !== '') {
|
||||
$localPath = $this->resolveLocalPath($sourceFile);
|
||||
if ($localPath === null) {
|
||||
$this->error('The file passed to --file does not exist.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$stream = fopen($localPath, 'rb');
|
||||
if ($stream === false) {
|
||||
$this->error('Unable to open the local file for reading.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$written = $filesystem->put($remotePath, $stream);
|
||||
} finally {
|
||||
fclose($stream);
|
||||
}
|
||||
|
||||
$sourceLabel = $localPath;
|
||||
} else {
|
||||
$contents = $this->buildProbeContents($diskName);
|
||||
$written = $filesystem->put($remotePath, $contents);
|
||||
$sourceLabel = '[generated probe payload]';
|
||||
}
|
||||
|
||||
if ($written !== true) {
|
||||
$this->error('Upload did not complete successfully. The storage driver returned a failure status.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$exists = $filesystem->exists($remotePath);
|
||||
$size = $exists ? $filesystem->size($remotePath) : null;
|
||||
|
||||
$this->info('Upload succeeded.');
|
||||
$this->line('Source: '.$sourceLabel);
|
||||
$this->line('Object key: '.$remotePath);
|
||||
$this->line('Exists after upload: '.($exists ? 'yes' : 'no'));
|
||||
if ($size !== null) {
|
||||
$this->line('Stored size: '.number_format((int) $size).' bytes');
|
||||
}
|
||||
|
||||
if (! $keepObject && $exists) {
|
||||
$filesystem->delete($remotePath);
|
||||
$this->line('Cleanup: deleted uploaded test object');
|
||||
} elseif ($keepObject) {
|
||||
$this->warn('Cleanup skipped because --keep was used.');
|
||||
}
|
||||
|
||||
return $exists ? self::SUCCESS : self::FAILURE;
|
||||
} catch (Throwable $exception) {
|
||||
$this->error('Object storage test failed.');
|
||||
$this->line($exception->getMessage());
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveRemotePath(): string
|
||||
{
|
||||
$provided = trim((string) $this->option('path'));
|
||||
if ($provided !== '') {
|
||||
return ltrim(str_replace('\\', '/', $provided), '/');
|
||||
}
|
||||
|
||||
return 'tests/object-storage/'.now()->format('Ymd-His').'-'.Str::random(10).'.txt';
|
||||
}
|
||||
|
||||
private function resolveLocalPath(string $path): ?string
|
||||
{
|
||||
$trimmed = trim($path);
|
||||
if ($trimmed === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_file($trimmed)) {
|
||||
return $trimmed;
|
||||
}
|
||||
|
||||
$relative = base_path($trimmed);
|
||||
|
||||
return is_file($relative) ? $relative : null;
|
||||
}
|
||||
|
||||
private function buildProbeContents(string $diskName): string
|
||||
{
|
||||
return implode("\n", [
|
||||
'Skinbase object storage upload test',
|
||||
'disk='.$diskName,
|
||||
'timestamp='.now()->toIso8601String(),
|
||||
'app_url='.(string) config('app.url'),
|
||||
'random='.Str::uuid()->toString(),
|
||||
'',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user