From d9eb942e8cd39882ca991a55128d5df2cc32bc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 4 Mar 2025 13:43:13 +0100 Subject: [PATCH] Merge deployment download endpoints --- .../Http/Deployments/Download/Get.php | 32 ++++- .../Modules/Functions/Services/Http.php | 2 - .../Http/Deployments/Builds/Download/Get.php | 133 ------------------ .../Sites/Http/Deployments/Download/Get.php | 36 +++-- .../Platform/Modules/Sites/Services/Http.php | 2 - src/Appwrite/Specification/Format.php | 16 +++ 6 files changed, 68 insertions(+), 153 deletions(-) delete mode 100644 src/Appwrite/Platform/Modules/Sites/Http/Deployments/Builds/Download/Get.php diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php index 1a1ff9b938..c84d255f23 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php @@ -15,6 +15,7 @@ use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Storage\Device; use Utopia\Swoole\Request; +use Utopia\Validator\WhiteList; class Get extends Action { @@ -52,14 +53,16 @@ class Get extends Action )) ->param('functionId', '', new UID(), 'Function ID.') ->param('deploymentId', '', new UID(), 'Deployment ID.') + ->param('type', '', new WhiteList(['source', 'output']), 'Deployment file to download. Can be: "source", "output".') ->inject('response') ->inject('request') ->inject('dbForProject') ->inject('deviceForFunctions') + ->inject('deviceForBuilds') ->callback([$this, 'action']); } - public function action(string $functionId, string $deploymentId, Response $response, Request $request, Database $dbForProject, Device $deviceForFunctions) + public function action(string $functionId, string $deploymentId, string $type, Response $response, Request $request, Database $dbForProject, Device $deviceForFunctions, Device $deviceForBuilds) { $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -75,8 +78,23 @@ class Get extends Action throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); } - $path = $deployment->getAttribute('path', ''); - if (!$deviceForFunctions->exists($path)) { + switch ($type) { + case 'output': + $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId')); + if ($build->isEmpty()) { + throw new Exception(Exception::BUILD_NOT_FOUND); + } + + $path = $build->getAttribute('path', ''); + $device = $deviceForBuilds; + break; + case 'source': + $path = $deployment->getAttribute('path', ''); + $device = $deviceForFunctions; + break; + } + + if (!$device->exists($path)) { throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); } @@ -86,7 +104,7 @@ class Get extends Action ->addHeader('X-Peak', \memory_get_peak_usage()) ->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"'); - $size = $deviceForFunctions->getFileSize($path); + $size = $device->getFileSize($path); $rangeHeader = $request->getHeader('range'); if (!empty($rangeHeader)) { @@ -108,13 +126,13 @@ class Get extends Action ->addHeader('Content-Length', $end - $start + 1) ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); - $response->send($deviceForFunctions->read($path, $start, ($end - $start + 1))); + $response->send($device->read($path, $start, ($end - $start + 1))); } if ($size > APP_STORAGE_READ_BUFFER) { for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) { $response->chunk( - $deviceForFunctions->read( + $device->read( $path, ($i * MAX_OUTPUT_CHUNK_SIZE), min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE)) @@ -123,7 +141,7 @@ class Get extends Action ); } } else { - $response->send($deviceForFunctions->read($path)); + $response->send($device->read($path)); } } } diff --git a/src/Appwrite/Platform/Modules/Functions/Services/Http.php b/src/Appwrite/Platform/Modules/Functions/Services/Http.php index a17c80865e..5ae77c5d6b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Functions/Services/Http.php @@ -3,7 +3,6 @@ namespace Appwrite\Platform\Modules\Functions\Services; use Appwrite\Platform\Modules\Functions\Http\Deployments\Builds\Create as CreateBuild; -use Appwrite\Platform\Modules\Functions\Http\Deployments\Builds\Download\Get as DownloadBuild; use Appwrite\Platform\Modules\Functions\Http\Deployments\Builds\Update as UpdateBuild; use Appwrite\Platform\Modules\Functions\Http\Deployments\Create as CreateDeployment; use Appwrite\Platform\Modules\Functions\Http\Deployments\Delete as DeleteDeployment; @@ -65,7 +64,6 @@ class Http extends Service $this->addAction(DownloadDeployment::getName(), new DownloadDeployment()); $this->addAction(CreateBuild::getName(), new CreateBuild()); $this->addAction(UpdateBuild::getName(), new UpdateBuild()); - $this->addAction(DownloadBuild::getName(), new DownloadBuild()); // Executions $this->addAction(CreateExecution::getName(), new CreateExecution()); diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Builds/Download/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Builds/Download/Get.php deleted file mode 100644 index f86fa591c1..0000000000 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Builds/Download/Get.php +++ /dev/null @@ -1,133 +0,0 @@ -setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) - ->setHttpPath('/v1/sites/:siteId/deployments/:deploymentId/build/download') - ->desc('Download build') - ->groups(['api', 'sites']) - ->label('scope', 'sites.read') - ->label('sdk', new Method( - namespace: 'sites', - name: 'getDeploymentBuildDownload', - description: <<param('siteId', '', new UID(), 'Site ID.') - ->param('deploymentId', '', new UID(), 'Deployment ID.') - ->inject('response') - ->inject('request') - ->inject('dbForProject') - ->inject('deviceForBuilds') - ->callback([$this, 'action']); - } - - public function action(string $siteId, string $deploymentId, Response $response, Request $request, Database $dbForProject, Device $deviceForBuilds) - { - $site = $dbForProject->getDocument('sites', $siteId); - if ($site->isEmpty()) { - throw new Exception(Exception::SITE_NOT_FOUND); - } - - $deployment = $dbForProject->getDocument('deployments', $deploymentId); - if ($deployment->isEmpty()) { - throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); - } - - if ($deployment->getAttribute('resourceId') !== $site->getId()) { - throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); - } - - $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId')); - if ($build->isEmpty()) { - throw new Exception(Exception::BUILD_NOT_FOUND); - } - - $path = $build->getAttribute('path', ''); - if (!$deviceForBuilds->exists($path)) { - throw new Exception(Exception::BUILD_NOT_FOUND); - } - - $response - ->setContentType('application/gzip') - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache - ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"'); - - $size = $deviceForBuilds->getFileSize($path); - $rangeHeader = $request->getHeader('range'); - - if (!empty($rangeHeader)) { - $start = $request->getRangeStart(); - $end = $request->getRangeEnd(); - $unit = $request->getRangeUnit(); - - if ($end === null) { - $end = min(($start + MAX_OUTPUT_CHUNK_SIZE - 1), ($size - 1)); - } - - if ($unit !== 'bytes' || $start >= $end || $end >= $size) { - throw new Exception(Exception::STORAGE_INVALID_RANGE); - } - - $response - ->addHeader('Accept-Ranges', 'bytes') - ->addHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $size) - ->addHeader('Content-Length', $end - $start + 1) - ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); - - $response->send($deviceForBuilds->read($path, $start, ($end - $start + 1))); - } - - if ($size > APP_STORAGE_READ_BUFFER) { - for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) { - $response->chunk( - $deviceForBuilds->read( - $path, - ($i * MAX_OUTPUT_CHUNK_SIZE), - min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE)) - ), - (($i + 1) * MAX_OUTPUT_CHUNK_SIZE) >= $size - ); - } - } else { - $response->send($deviceForBuilds->read($path)); - } - } -} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php index 2d38e619a6..2897c6914e 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php @@ -15,6 +15,7 @@ use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; use Utopia\Storage\Device; use Utopia\Swoole\Request; +use Utopia\Validator\WhiteList; class Get extends Action { @@ -51,14 +52,16 @@ class Get extends Action )) ->param('siteId', '', new UID(), 'Site ID.') ->param('deploymentId', '', new UID(), 'Deployment ID.') + ->param('type', '', new WhiteList(['source', 'output']), 'Deployment file to download. Can be: "source", "output".') ->inject('response') ->inject('request') ->inject('dbForProject') ->inject('deviceForSites') + ->inject('deviceForBuilds') ->callback([$this, 'action']); } - public function action(string $siteId, string $deploymentId, Response $response, Request $request, Database $dbForProject, Device $deviceForSites) + public function action(string $siteId, string $deploymentId, string $type, Response $response, Request $request, Database $dbForProject, Device $deviceForSites, Device $deviceForBuilds) { $site = $dbForProject->getDocument('sites', $siteId); if ($site->isEmpty()) { @@ -74,18 +77,33 @@ class Get extends Action throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); } - $path = $deployment->getAttribute('path', ''); - if (!$deviceForSites->exists($path)) { - throw new Exception(Exception::DEPLOYMENT_NOT_FOUND); + switch ($type) { + case 'output': + $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId')); + if ($build->isEmpty()) { + throw new Exception(Exception::BUILD_NOT_FOUND); + } + + $path = $build->getAttribute('path', ''); + $device = $deviceForBuilds; + break; + case 'source': + $path = $deployment->getAttribute('path', ''); + $device = $deviceForSites; + break; + } + + if (!$device->exists($path)) { + throw new Exception(Exception::BUILD_NOT_FOUND); } $response ->setContentType('application/gzip') ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"'); + ->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '-' . $type . '.tar.gz"'); - $size = $deviceForSites->getFileSize($path); + $size = $device->getFileSize($path); $rangeHeader = $request->getHeader('range'); if (!empty($rangeHeader)) { @@ -107,13 +125,13 @@ class Get extends Action ->addHeader('Content-Length', $end - $start + 1) ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); - $response->send($deviceForSites->read($path, $start, ($end - $start + 1))); + $response->send($device->read($path, $start, ($end - $start + 1))); } if ($size > APP_STORAGE_READ_BUFFER) { for ($i = 0; $i < ceil($size / MAX_OUTPUT_CHUNK_SIZE); $i++) { $response->chunk( - $deviceForSites->read( + $device->read( $path, ($i * MAX_OUTPUT_CHUNK_SIZE), min(MAX_OUTPUT_CHUNK_SIZE, $size - ($i * MAX_OUTPUT_CHUNK_SIZE)) @@ -122,7 +140,7 @@ class Get extends Action ); } } else { - $response->send($deviceForSites->read($path)); + $response->send($device->read($path)); } } } diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index 9df4329b01..7b322900d1 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -3,7 +3,6 @@ namespace Appwrite\Platform\Modules\Sites\Services; use Appwrite\Platform\Modules\Sites\Http\Deployments\Builds\Create as CreateBuild; -use Appwrite\Platform\Modules\Sites\Http\Deployments\Builds\Download\Get as DownloadBuild; use Appwrite\Platform\Modules\Sites\Http\Deployments\Builds\Update as UpdateBuild; use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; @@ -58,7 +57,6 @@ class Http extends Service $this->addAction(UpdateDeployment::getName(), new UpdateDeployment()); $this->addAction(DeleteDeployment::getName(), new DeleteDeployment()); $this->addAction(DownloadDeployment::getName(), new DownloadDeployment()); - $this->addAction(DownloadBuild::getName(), new DownloadBuild()); $this->addAction(CreateBuild::getName(), new CreateBuild()); $this->addAction(UpdateBuild::getName(), new UpdateBuild()); diff --git a/src/Appwrite/Specification/Format.php b/src/Appwrite/Specification/Format.php index f4bec326e7..7e7dd988df 100644 --- a/src/Appwrite/Specification/Format.php +++ b/src/Appwrite/Specification/Format.php @@ -210,8 +210,24 @@ abstract class Format break; } break; + case 'functions': + switch ($method) { + case 'getDeploymentDownload': + switch ($param) { + case 'type': + return 'DeploymentDownloadType'; + } + break; + } + break; case 'sites': switch ($method) { + case 'getDeploymentDownload': + switch ($param) { + case 'type': + return 'Deployment'; + } + break; case 'getUsage': case 'listUsage': switch ($param) {