44
55use Carbon \CarbonImmutable ;
66use Illuminate \Http \Request ;
7+ use Pterodactyl \Models \Backup ;
78use Illuminate \Http \JsonResponse ;
89use League \Flysystem \AwsS3v3 \AwsS3Adapter ;
910use Pterodactyl \Http \Controllers \Controller ;
1011use Pterodactyl \Extensions \Backups \BackupManager ;
1112use Pterodactyl \Repositories \Eloquent \BackupRepository ;
13+ use Symfony \Component \HttpKernel \Exception \BadRequestHttpException ;
1214
1315class BackupRemoteUploadController extends Controller
1416{
@@ -37,25 +39,26 @@ public function __construct(BackupRepository $repository, BackupManager $backupM
3739 }
3840
3941 /**
40- * ?
42+ * Returns the required presigned urls to upload a backup to S3 cloud storage.
4143 *
4244 * @param \Illuminate\Http\Request $request
4345 * @param string $backup
4446 *
4547 * @return \Illuminate\Http\JsonResponse
4648 *
47- * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
4849 * @throws \Exception
50+ * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
4951 */
5052 public function __invoke (Request $ request , string $ backup )
5153 {
54+ // Get the size query parameter.
5255 $ size = $ request ->query ('size ' , null );
53- if ($ size === null ) {
54- return new JsonResponse ([], JsonResponse:: HTTP_BAD_REQUEST );
56+ if (is_null ( $ size) ) {
57+ throw new BadRequestHttpException ( ' Missing size query parameter. ' );
5558 }
5659
5760 /** @var \Pterodactyl\Models\Backup $model */
58- $ model = $ this -> repository -> findFirstWhere ([[ 'uuid ' , '= ' , $ backup ]]);
61+ $ model = Backup:: query ()-> where ([[ 'uuid ' , '= ' , $ backup ]])-> firstOrFail ( );
5962
6063 // Prevent backups that have already been completed from trying to
6164 // be uploaded again.
@@ -66,63 +69,76 @@ public function __invoke(Request $request, string $backup)
6669 // Ensure we are using the S3 adapter.
6770 $ adapter = $ this ->backupManager ->adapter ();
6871 if (! $ adapter instanceof AwsS3Adapter) {
69- return new JsonResponse ([], JsonResponse:: HTTP );
72+ throw new BadRequestHttpException ( ' Backups are not using the s3 storage driver ' );
7073 }
7174
75+ // The path where backup will be uploaded to
7276 $ path = sprintf ('%s/%s.tar.gz ' , $ model ->server ->uuid , $ model ->uuid );
7377
78+ // Get the S3 client
7479 $ client = $ adapter ->getClient ();
7580
76- $ result = $ client ->execute ($ client ->getCommand ('CreateMultipartUpload ' , [
81+ // Params for generating the presigned urls
82+ $ params = [
7783 'Bucket ' => $ adapter ->getBucket (),
7884 'Key ' => $ path ,
7985 'ContentType ' => 'application/x-gzip ' ,
80- ]));
86+ ];
87+
88+ // Execute the CreateMultipartUpload request
89+ $ result = $ client ->execute ($ client ->getCommand ('CreateMultipartUpload ' , $ params ));
90+
91+ // Get the UploadId from the CreateMultipartUpload request,
92+ // this is needed to create the other presigned urls
8193 $ uploadId = $ result ->get ('UploadId ' );
8294
95+ // Create a CompleteMultipartUpload presigned url
8396 $ completeMultipartUpload = $ client ->createPresignedRequest (
84- $ client ->getCommand (' CompleteMultipartUpload ' , [
85- 'Bucket ' => $ adapter -> getBucket () ,
86- ' Key ' => $ path ,
87- ' ContentType ' => ' application/x-gzip ' ,
88- ' UploadId ' => $ uploadId ,
89- ] ),
97+ $ client ->getCommand (
98+ 'CompleteMultipartUpload ' ,
99+ array_merge ( $ params , [
100+ ' UploadId ' => $ uploadId ,
101+ ])
102+ ),
90103 CarbonImmutable::now ()->addMinutes (30 )
91104 );
92105
106+ // Create a AbortMultipartUpload presigned url
93107 $ abortMultipartUpload = $ client ->createPresignedRequest (
94- $ client ->getCommand (' AbortMultipartUpload ' , [
95- 'Bucket ' => $ adapter -> getBucket () ,
96- ' Key ' => $ path ,
97- ' ContentType ' => ' application/x-gzip ' ,
98- ' UploadId ' => $ uploadId ,
99- ] ),
108+ $ client ->getCommand (
109+ 'AbortMultipartUpload ' ,
110+ array_merge ( $ params , [
111+ ' UploadId ' => $ uploadId ,
112+ ])
113+ ),
100114 CarbonImmutable::now ()->addMinutes (45 )
101115 );
102116
117+ // Calculate the number of parts needed to upload the backup
103118 $ partCount = (int ) $ size / (self ::PART_SIZE );
104119
120+ // Create as many UploadPart presigned urls as needed
105121 $ parts = [];
106122 for ($ i = 0 ; $ i < $ partCount ; $ i ++) {
107123 $ part = $ client ->createPresignedRequest (
108- $ client ->getCommand (' UploadPart ' , [
109- 'Bucket ' => $ adapter -> getBucket () ,
110- ' Key ' => $ path ,
111- ' ContentType ' => ' application/x-gzip ' ,
112- ' UploadId ' => $ uploadId ,
113- ' PartNumber ' => $ i + 1 ,
114- ] ),
124+ $ client ->getCommand (
125+ 'UploadPart ' ,
126+ array_merge ( $ params , [
127+ ' UploadId ' => $ uploadId ,
128+ ' PartNumber ' => $ i + 1 ,
129+ ])
130+ ),
115131 CarbonImmutable::now ()->addMinutes (30 )
116132 );
117133
118134 array_push ($ parts , $ part ->getUri ()->__toString ());
119135 }
120136
121137 return new JsonResponse ([
122- 'CompleteMultipartUpload ' => $ completeMultipartUpload ->getUri ()->__toString (),
123- 'AbortMultipartUpload ' => $ abortMultipartUpload ->getUri ()->__toString (),
124- 'Parts ' => $ parts ,
125- 'PartSize ' => self ::PART_SIZE ,
126- ], JsonResponse:: HTTP_OK );
138+ 'complete_multipart_upload ' => $ completeMultipartUpload ->getUri ()->__toString (),
139+ 'abort_multipart_upload ' => $ abortMultipartUpload ->getUri ()->__toString (),
140+ 'parts ' => $ parts ,
141+ 'part_size ' => self ::PART_SIZE ,
142+ ]);
127143 }
128144}
0 commit comments