connection = $connection; $this->repository = $repository; $this->allocationRepository = $allocationRepository; $this->nodeRepository = $nodeRepository; $this->daemonServerRepository = $daemonServerRepository; $this->daemonTransferRepository = $daemonTransferRepository; $this->configurationStructureService = $configurationStructureService; $this->writer = $writer; } /** * The daemon notifies us about the archive status. * * @param \Illuminate\Http\Request $request * @param string $uuid * @return \Illuminate\Http\JsonResponse * * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Throwable */ public function archive(Request $request, string $uuid) { $server = $this->repository->getByUuid($uuid); // Unsuspend the server and don't continue the transfer. if (! $request->input('successful')) { $transfer = $server->transfer; $transfer->forceFill([ 'successful' => false, ])->saveOrFail(); $allocationIds = json_decode($transfer->new_additional_allocations); array_push($allocationIds, $transfer->new_allocation); // Release the reserved allocations. $this->allocationRepository->updateWhereIn('id', $allocationIds, ['server_id' => null]); return new JsonResponse([], Response::HTTP_NO_CONTENT); } $server->node_id = $server->transfer->new_node; $data = $this->configurationStructureService->handle($server); $data['suspended'] = false; $data['service']['skip_scripts'] = true; $allocations = $server->getAllocationMappings(); $data['allocations']['default']['ip'] = array_key_first($allocations); $data['allocations']['default']['port'] = $allocations[$data['allocations']['default']['ip']][0]; $now = Chronos::now(); $signer = new Sha256; $token = (new Builder)->issuedBy(config('app.url')) ->permittedFor($server->node->getConnectionAddress()) ->identifiedBy(hash('sha256', $server->uuid), true) ->issuedAt($now->getTimestamp()) ->canOnlyBeUsedAfter($now->getTimestamp()) ->expiresAt($now->addMinutes(15)->getTimestamp()) ->relatedTo($server->uuid, true) ->getToken($signer, new Key($server->node->getDecryptedKey())); // Update the archived field on the transfer to make clients connect to the websocket // on the new node to be able to receive transfer logs. $server->transfer->forceFill([ 'archived' => true, ])->saveOrFail(); // On the daemon transfer repository, make sure to set the node after the server // because setServer() tells the repository to use the server's node and not the one // we want to specify. try { /** @var \Pterodactyl\Models\Node $newNode */ $newNode = $this->nodeRepository->find($server->transfer->new_node); $this->daemonTransferRepository ->setServer($server) ->setNode($newNode) ->notify($server, $data, $server->node, $token->__toString()); } catch (DaemonConnectionException $exception) { throw $exception; } return new JsonResponse([], Response::HTTP_NO_CONTENT); } /** * The daemon notifies us about a transfer failure. * * @param string $uuid * @return \Illuminate\Http\JsonResponse * * @throws \Throwable */ public function failure(string $uuid) { $server = $this->repository->getByUuid($uuid); $transfer = $server->transfer; $allocationIds = json_decode($transfer->new_additional_allocations); array_push($allocationIds, $transfer->new_allocation); // Remove the new allocations. $this->allocationRepository->updateWhereIn('id', $allocationIds, ['server_id' => null]); return new JsonResponse([], Response::HTTP_NO_CONTENT); } /** * The daemon notifies us about a transfer success. * * @param string $uuid * @return \Illuminate\Http\JsonResponse * * @throws \Throwable */ public function success(string $uuid) { $server = $this->repository->getByUuid($uuid); $transfer = $server->transfer; $allocationIds = json_decode($transfer->old_additional_allocations); array_push($allocationIds, $transfer->old_allocation); // Begin a transaction. $this->connection->beginTransaction(); // Remove the old allocations. $this->allocationRepository->updateWhereIn('id', $allocationIds, ['server_id' => null]); // Update the server's allocation_id and node_id. $server->allocation_id = $transfer->new_allocation; $server->node_id = $transfer->new_node; $server->saveOrFail(); // Mark the transfer as successful. $transfer->successful = true; $transfer->saveOrFail(); // Commit the transaction. $this->connection->commit(); // Delete the server from the old node try { $this->daemonServerRepository->setServer($server)->delete(); } catch (DaemonConnectionException $exception) { $this->writer->warning($exception); } // Unsuspend the server $server->load('node'); return new JsonResponse([], Response::HTTP_NO_CONTENT); } }