optimizations
This commit is contained in:
107
app/Services/NovaCards/NovaCardExportService.php
Normal file
107
app/Services/NovaCards/NovaCardExportService.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\NovaCards;
|
||||
|
||||
use App\Jobs\NovaCards\GenerateNovaCardExportJob;
|
||||
use App\Models\NovaCard;
|
||||
use App\Models\NovaCardExport;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Handles export request creation, status checking, and file resolution.
|
||||
* Actual rendering is delegated to GenerateNovaCardExportJob (queued).
|
||||
*/
|
||||
class NovaCardExportService
|
||||
{
|
||||
/** How long (in minutes) a generated export file is available. */
|
||||
private const EXPORT_TTL_MINUTES = 60;
|
||||
|
||||
/** Allowed export types and their canvas dimensions. */
|
||||
public const EXPORT_SPECS = [
|
||||
NovaCardExport::TYPE_PREVIEW => ['width' => 1080, 'height' => 1080, 'format' => 'webp'],
|
||||
NovaCardExport::TYPE_HIRES => ['width' => 2160, 'height' => 2160, 'format' => 'webp'],
|
||||
NovaCardExport::TYPE_SQUARE => ['width' => 1080, 'height' => 1080, 'format' => 'webp'],
|
||||
NovaCardExport::TYPE_STORY => ['width' => 1080, 'height' => 1920, 'format' => 'webp'],
|
||||
NovaCardExport::TYPE_WALLPAPER => ['width' => 2560, 'height' => 1440, 'format' => 'webp'],
|
||||
NovaCardExport::TYPE_OG => ['width' => 1200, 'height' => 630, 'format' => 'jpg'],
|
||||
];
|
||||
|
||||
public function requestExport(User $user, NovaCard $card, string $exportType, array $options = []): NovaCardExport
|
||||
{
|
||||
if (! $card->allow_export && ! $card->isOwnedBy($user)) {
|
||||
abort(403, 'This card does not allow exports.');
|
||||
}
|
||||
|
||||
$spec = self::EXPORT_SPECS[$exportType] ?? self::EXPORT_SPECS[NovaCardExport::TYPE_PREVIEW];
|
||||
|
||||
// Reuse a recent pending/ready non-expired export for the same type.
|
||||
$existing = NovaCardExport::query()
|
||||
->where('card_id', $card->id)
|
||||
->where('user_id', $user->id)
|
||||
->where('export_type', $exportType)
|
||||
->whereIn('status', [NovaCardExport::STATUS_READY, NovaCardExport::STATUS_PENDING, NovaCardExport::STATUS_PROCESSING])
|
||||
->where('expires_at', '>', now())
|
||||
->orderByDesc('created_at')
|
||||
->first();
|
||||
|
||||
if ($existing !== null) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
$export = NovaCardExport::query()->create([
|
||||
'card_id' => $card->id,
|
||||
'user_id' => $user->id,
|
||||
'export_type' => $exportType,
|
||||
'status' => NovaCardExport::STATUS_PENDING,
|
||||
'width' => $spec['width'],
|
||||
'height' => $spec['height'],
|
||||
'format' => $spec['format'],
|
||||
'options_json' => $options,
|
||||
'expires_at' => now()->addMinutes(self::EXPORT_TTL_MINUTES),
|
||||
]);
|
||||
|
||||
GenerateNovaCardExportJob::dispatch($export->id)
|
||||
->onQueue((string) config('nova_cards.render.queue', 'default'));
|
||||
|
||||
return $export->refresh();
|
||||
}
|
||||
|
||||
public function getStatus(NovaCardExport $export): array
|
||||
{
|
||||
return [
|
||||
'id' => (int) $export->id,
|
||||
'export_type' => (string) $export->export_type,
|
||||
'status' => (string) $export->status,
|
||||
'output_url' => $export->isReady() && ! $export->isExpired() ? $export->outputUrl() : null,
|
||||
'width' => $export->width,
|
||||
'height' => $export->height,
|
||||
'format' => (string) $export->format,
|
||||
'ready_at' => optional($export->ready_at)?->toISOString(),
|
||||
'expires_at' => optional($export->expires_at)?->toISOString(),
|
||||
];
|
||||
}
|
||||
|
||||
public function cleanupExpired(): int
|
||||
{
|
||||
$exports = NovaCardExport::query()
|
||||
->where('expires_at', '<', now())
|
||||
->whereNotNull('output_path')
|
||||
->get();
|
||||
|
||||
$count = 0;
|
||||
foreach ($exports as $export) {
|
||||
$disk = Storage::disk((string) config('nova_cards.storage.public_disk', 'public'));
|
||||
if ($export->output_path && $disk->exists($export->output_path)) {
|
||||
$disk->delete($export->output_path);
|
||||
}
|
||||
$export->delete();
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user