фикс загрузки больших файлов с s3
This commit is contained in:
@@ -6,7 +6,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use OpenApi\Attributes as OA;
|
use OpenApi\Attributes as OA;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
|
|
||||||
class LauncherController extends Controller
|
class LauncherController extends Controller
|
||||||
{
|
{
|
||||||
@@ -72,8 +72,8 @@ class LauncherController extends Controller
|
|||||||
|
|
||||||
#[OA\Get(
|
#[OA\Get(
|
||||||
path: '/api/launcher/download/{path}',
|
path: '/api/launcher/download/{path}',
|
||||||
summary: 'Скачать файл клиента',
|
summary: 'Получить ссылку на скачивание файла',
|
||||||
description: 'Стримит файл из S3 по относительному пути из манифеста. Путь может содержать вложенные директории (например `Data/ruRU/patch-ruRU-3.MPQ`).',
|
description: 'Возвращает временную presigned-ссылку на файл в S3. Лаунчер скачивает файл напрямую из хранилища по этой ссылке. Путь может содержать вложенные директории (например `Data/ruRU/patch-ruRU-3.MPQ`).',
|
||||||
tags: ['Launcher'],
|
tags: ['Launcher'],
|
||||||
security: [['bearerAuth' => []]],
|
security: [['bearerAuth' => []]],
|
||||||
parameters: [
|
parameters: [
|
||||||
@@ -89,10 +89,12 @@ class LauncherController extends Controller
|
|||||||
responses: [
|
responses: [
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
response: 200,
|
response: 200,
|
||||||
description: 'Бинарное содержимое файла',
|
description: 'Временная ссылка на скачивание',
|
||||||
content: new OA\MediaType(
|
content: new OA\JsonContent(
|
||||||
mediaType: 'application/octet-stream',
|
properties: [
|
||||||
schema: new OA\Schema(type: 'string', format: 'binary'),
|
new OA\Property(property: 'url', type: 'string', format: 'uri', description: 'Presigned URL для скачивания'),
|
||||||
|
new OA\Property(property: 'expires_in', type: 'integer', description: 'Время жизни ссылки в секундах', example: 3600),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
new OA\Response(
|
new OA\Response(
|
||||||
@@ -115,7 +117,7 @@ class LauncherController extends Controller
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)]
|
)]
|
||||||
public function download(string $path): StreamedResponse|JsonResponse
|
public function download(string $path): JsonResponse
|
||||||
{
|
{
|
||||||
$disk = Storage::disk($this->disk());
|
$disk = Storage::disk($this->disk());
|
||||||
$fullPath = $this->basePath().'/'.$path;
|
$fullPath = $this->basePath().'/'.$path;
|
||||||
@@ -124,7 +126,13 @@ class LauncherController extends Controller
|
|||||||
return response()->json(['message' => 'Файл не найден.'], 404);
|
return response()->json(['message' => 'Файл не найден.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $disk->download($fullPath);
|
$ttlMinutes = config('moonwell.launcher.download_ttl', 60);
|
||||||
|
$url = $disk->temporaryUrl($fullPath, now()->addMinutes($ttlMinutes));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'url' => $url,
|
||||||
|
'expires_in' => $ttlMinutes * 60,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function disk(): string
|
private function disk(): string
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ return [
|
|||||||
'disk' => env('MOONWELL_LAUNCHER_DISK', 's3'),
|
'disk' => env('MOONWELL_LAUNCHER_DISK', 's3'),
|
||||||
'base_path' => env('MOONWELL_LAUNCHER_BASE_PATH', 'World of Warcraft'),
|
'base_path' => env('MOONWELL_LAUNCHER_BASE_PATH', 'World of Warcraft'),
|
||||||
'manifest_key' => env('MOONWELL_LAUNCHER_MANIFEST_KEY', 'manifest.json'),
|
'manifest_key' => env('MOONWELL_LAUNCHER_MANIFEST_KEY', 'manifest.json'),
|
||||||
|
'download_ttl' => (int) env('MOONWELL_LAUNCHER_DOWNLOAD_TTL', 60),
|
||||||
],
|
],
|
||||||
|
|
||||||
'realm' => [
|
'realm' => [
|
||||||
|
|||||||
Reference in New Issue
Block a user