Path: blob/1.0-develop/app/Services/Backups/InitiateBackupService.php
10260 views
<?php12namespace Pterodactyl\Services\Backups;34use Ramsey\Uuid\Uuid;5use Carbon\CarbonImmutable;6use Webmozart\Assert\Assert;7use Pterodactyl\Models\Backup;8use Pterodactyl\Models\Server;9use Illuminate\Database\ConnectionInterface;10use Pterodactyl\Extensions\Backups\BackupManager;11use Pterodactyl\Repositories\Eloquent\BackupRepository;12use Pterodactyl\Repositories\Wings\DaemonBackupRepository;13use Pterodactyl\Exceptions\Service\Backup\TooManyBackupsException;14use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;1516class InitiateBackupService17{18private array $ignoredFiles = [];1920private bool $isLocked = false;2122/**23* InitiateBackupService constructor.24*/25public function __construct(26private BackupRepository $repository,27private ConnectionInterface $connection,28private DaemonBackupRepository $daemonBackupRepository,29private DeleteBackupService $deleteBackupService,30private BackupManager $backupManager,31) {32}3334/**35* Set if the backup should be locked once it is created which will prevent36* its deletion by users or automated system processes.37*/38public function setIsLocked(bool $isLocked): self39{40$this->isLocked = $isLocked;4142return $this;43}4445/**46* Sets the files to be ignored by this backup.47*48* @param string[]|null $ignored49*/50public function setIgnoredFiles(?array $ignored): self51{52if (is_array($ignored)) {53foreach ($ignored as $value) {54Assert::string($value); // @phpstan-ignore staticMethod.alreadyNarrowedType55}56}5758// Set the ignored files to be any values that are not empty in the array. Don't use59// the PHP empty function here incase anything that is "empty" by default (0, false, etc.)60// were passed as a file or folder name.61$this->ignoredFiles = is_null($ignored) ? [] : array_filter($ignored, function ($value) {62return strlen($value) > 0;63});6465return $this;66}6768/**69* Initiates the backup process for a server on Wings.70*71* @throws \Throwable72* @throws TooManyBackupsException73* @throws TooManyRequestsHttpException74*/75public function handle(Server $server, ?string $name = null, bool $override = false): Backup76{77$limit = config('backups.throttles.limit');78$period = config('backups.throttles.period');79if ($period > 0) {80$previous = $this->repository->getBackupsGeneratedDuringTimespan($server->id, $period);81if ($previous->count() >= $limit) {82$message = sprintf('Only %d backups may be generated within a %d second span of time.', $limit, $period);8384throw new TooManyRequestsHttpException((int) CarbonImmutable::now()->diffInSeconds($previous->last()->created_at->addSeconds($period)), $message);85}86}8788// Check if the server has reached or exceeded its backup limit.89// completed_at == null will cover any ongoing backups, while is_successful == true will cover any completed backups.90$successful = $this->repository->getNonFailedBackups($server);91if (!$server->backup_limit || $successful->count() >= $server->backup_limit) {92// Do not allow the user to continue if this server is already at its limit and can't override.93if (!$override || $server->backup_limit <= 0) {94throw new TooManyBackupsException($server->backup_limit);95}9697// Get the oldest backup the server has that is not "locked" (indicating a backup that should98// never be automatically purged). If we find a backup we will delete it and then continue with99// this process. If no backup is found that can be used an exception is thrown.100$oldest = $successful->where('is_locked', false)->orderBy('created_at')->first();101if (!$oldest) {102throw new TooManyBackupsException($server->backup_limit);103}104105$this->deleteBackupService->handle($oldest);106}107108return $this->connection->transaction(function () use ($server, $name) {109/** @var Backup $backup */110$backup = $this->repository->create([111'server_id' => $server->id,112'uuid' => Uuid::uuid4()->toString(),113'name' => trim($name) ?: sprintf('Backup at %s', CarbonImmutable::now()->toDateTimeString()),114'ignored_files' => array_values($this->ignoredFiles),115'disk' => $this->backupManager->getDefaultAdapter(),116'is_locked' => $this->isLocked,117], true, true);118119$this->daemonBackupRepository->setServer($server)120->setBackupAdapter($this->backupManager->getDefaultAdapter())121->backup($backup);122123return $backup;124});125}126}127128129