diff --git a/app/Repositories/Wings/DaemonConfigurationRepository.php b/app/Repositories/Wings/DaemonConfigurationRepository.php index 90b504772..f1b83cacb 100644 --- a/app/Repositories/Wings/DaemonConfigurationRepository.php +++ b/app/Repositories/Wings/DaemonConfigurationRepository.php @@ -2,6 +2,7 @@ namespace Pterodactyl\Repositories\Wings; +use Pterodactyl\Models\Node; use GuzzleHttp\Exception\TransferException; use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; @@ -25,17 +26,19 @@ class DaemonConfigurationRepository extends DaemonRepository } /** - * Updates the configuration information for a daemon. + * Updates the configuration information for a daemon. Updates the information for + * this instance using a passed-in model. This allows us to change plenty of information + * in the model, and still use the old, pre-update model to actually make the HTTP request. * - * @param array $attributes + * @param \Pterodactyl\Models\Node $node * @return \Psr\Http\Message\ResponseInterface * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException */ - public function update(array $attributes = []) + public function update(?Node $node) { try { return $this->getHttpClient()->post( - '/api/update', array_merge($this->node->getConfiguration(), $attributes) + '/api/update', ['json' => $node->getConfiguration()] ); } catch (TransferException $exception) { throw new DaemonConnectionException($exception); diff --git a/app/Services/Nodes/NodeUpdateService.php b/app/Services/Nodes/NodeUpdateService.php index 8ce610df9..9582c4e18 100644 --- a/app/Services/Nodes/NodeUpdateService.php +++ b/app/Services/Nodes/NodeUpdateService.php @@ -5,11 +5,10 @@ namespace Pterodactyl\Services\Nodes; use Illuminate\Support\Str; use Pterodactyl\Models\Node; use GuzzleHttp\Exception\ConnectException; -use GuzzleHttp\Exception\RequestException; use Illuminate\Database\ConnectionInterface; use Illuminate\Contracts\Encryption\Encrypter; +use Pterodactyl\Repositories\Eloquent\NodeRepository; use Pterodactyl\Repositories\Daemon\ConfigurationRepository; -use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository; use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; use Pterodactyl\Exceptions\Service\Node\ConfigurationNotPersistedException; @@ -21,11 +20,6 @@ class NodeUpdateService */ private $connection; - /** - * @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface - */ - private $repository; - /** * @var \Pterodactyl\Repositories\Wings\DaemonConfigurationRepository */ @@ -36,24 +30,29 @@ class NodeUpdateService */ private $encrypter; + /** + * @var \Pterodactyl\Repositories\Eloquent\NodeRepository + */ + private $repository; + /** * UpdateService constructor. * * @param \Illuminate\Database\ConnectionInterface $connection * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter * @param \Pterodactyl\Repositories\Wings\DaemonConfigurationRepository $configurationRepository - * @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository + * @param \Pterodactyl\Repositories\Eloquent\NodeRepository $repository */ public function __construct( ConnectionInterface $connection, Encrypter $encrypter, DaemonConfigurationRepository $configurationRepository, - NodeRepositoryInterface $repository + NodeRepository $repository ) { $this->connection = $connection; - $this->repository = $repository; $this->configurationRepository = $configurationRepository; $this->encrypter = $encrypter; + $this->repository = $repository; } /** @@ -64,55 +63,36 @@ class NodeUpdateService * @param bool $resetToken * * @return \Pterodactyl\Models\Node - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException - * @throws \Pterodactyl\Exceptions\Service\Node\ConfigurationNotPersistedException + * @throws \Throwable */ public function handle(Node $node, array $data, bool $resetToken = false) { if ($resetToken) { - $data['daemon_token'] = Str::random(Node::DAEMON_TOKEN_LENGTH); - $data['daemon_token_id'] = $this->encrypter->encrypt( - Str::random(Node::DAEMON_TOKEN_ID_LENGTH) - ); + $data['daemon_token'] = $this->encrypter->encrypt(Str::random(Node::DAEMON_TOKEN_LENGTH)); + $data['daemon_token_id'] = Str::random(Node::DAEMON_TOKEN_ID_LENGTH); } - $this->connection->beginTransaction(); + [$updated, $exception] = $this->connection->transaction(function () use ($data, $node) { + /** @var \Pterodactyl\Models\Node $updated */ + $updated = $this->repository->withFreshModel()->update($node->id, $data, true, true); - /** @var \Pterodactyl\Models\Node $updatedModel */ - $updatedModel = $this->repository->update($node->id, $data); + try { + $this->configurationRepository->setNode($node)->update($updated); + } catch (DaemonConnectionException $exception) { + if (! is_null($exception->getPrevious()) && $exception->getPrevious() instanceof ConnectException) { + return [$updated, true]; + } - try { - if ($resetToken) { - // We need to clone the new model and set it's authentication token to be the - // old one so we can connect. Then we will pass the new token through as an - // override on the call. - $cloned = $updatedModel->replicate(['daemon_token']); - $cloned->setAttribute('daemon_token', $node->getAttribute('daemon_token')); - - $this->configurationRepository->setNode($cloned)->update([ - 'daemon_token_id' => $updatedModel->daemon_token_id, - 'daemon_token' => $updatedModel->getDecryptedKey(), - ]); - } else { - $this->configurationRepository->setNode($updatedModel)->update(); + throw $exception; } - $this->connection->commit(); - } catch (RequestException $exception) { - // Failed to connect to the Daemon. Let's go ahead and save the configuration - // and let the user know they'll need to manually update. - if ($exception instanceof ConnectException) { - $this->connection->commit(); + return [$updated, false]; + }); - throw new ConfigurationNotPersistedException(trans('exceptions.node.daemon_off_config_updated')); - } - - throw new DaemonConnectionException($exception); + if ($exception) { + throw new ConfigurationNotPersistedException(trans('exceptions.node.daemon_off_config_updated')); } - return $updatedModel; + return $updated; } }