Files
SkinbaseNova/app/Services/Uploads/UploadCancelService.php
2026-02-14 15:14:12 +01:00

85 lines
2.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Uploads;
use App\Repositories\Uploads\UploadSessionRepository;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use RuntimeException;
final class UploadCancelService
{
public function __construct(
private readonly UploadSessionRepository $sessions,
private readonly UploadStorageService $storage,
private readonly UploadAuditService $audit
) {
}
public function cancel(string $sessionId, int $userId, string $ip): array
{
$session = $this->sessions->getOrFail($sessionId);
$lockSeconds = (int) config('uploads.chunk.lock_seconds', 10);
$lockWait = (int) config('uploads.chunk.lock_wait_seconds', 5);
$lock = Cache::lock('uploads:cancel:' . $sessionId, $lockSeconds);
try {
$lock->block($lockWait);
} catch (\Throwable $e) {
$this->audit->log($userId, 'upload_cancel_locked', $ip, [
'session_id' => $sessionId,
]);
throw new RuntimeException('Upload is busy. Please retry.');
}
try {
if (in_array($session->status, [UploadSessionStatus::CANCELLED, UploadSessionStatus::PROCESSED, UploadSessionStatus::QUARANTINED], true)) {
$this->audit->log($userId, 'upload_cancel_noop', $ip, [
'session_id' => $sessionId,
'status' => $session->status,
]);
return [
'session_id' => $sessionId,
'status' => $session->status,
];
}
$this->safeDeleteTmp($session->tempPath);
$this->sessions->updateStatus($sessionId, UploadSessionStatus::CANCELLED);
$this->sessions->updateProgress($sessionId, 0);
$this->sessions->updateFailureReason($sessionId, 'cancelled');
$this->audit->log($userId, 'upload_cancelled', $ip, [
'session_id' => $sessionId,
]);
return [
'session_id' => $sessionId,
'status' => UploadSessionStatus::CANCELLED,
];
} finally {
optional($lock)->release();
}
}
private function safeDeleteTmp(string $path): void
{
$tmpRoot = $this->storage->sectionPath('tmp');
$realRoot = realpath($tmpRoot);
$realPath = realpath($path);
if (! $realRoot || ! $realPath || strpos($realPath, $realRoot) !== 0) {
return;
}
if (File::exists($realPath)) {
File::delete($realPath);
}
}
}