From 60f6e86b8bc951150f0c2d3387bd80ddeba50fb0 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 11 Apr 2020 15:35:32 -0700 Subject: [PATCH] Remove all of the old references to unused interfaces outside the test code --- .php_cs | 1 + .../Server/BulkPowerActionCommand.php | 13 +-- .../Server/BulkReinstallActionCommand.php | 24 ++-- .../Daemon/BaseRepositoryInterface.php | 68 ----------- .../Daemon/CommandRepositoryInterface.php | 19 --- .../ConfigurationRepositoryInterface.php | 19 --- .../Daemon/FileRepositoryInterface.php | 86 -------------- .../Daemon/PowerRepositoryInterface.php | 26 ----- .../Daemon/ServerRepositoryInterface.php | 83 ------------- .../Api/Remote/ValidateKeyController.php | 100 ---------------- app/Jobs/Schedule/RunTaskJob.php | 72 ++++-------- app/Providers/RepositoryServiceProvider.php | 17 --- .../SetDefaultAllocationService.php | 110 ------------------ .../RevokeMultipleDaemonKeysService.php | 89 -------------- 14 files changed, 44 insertions(+), 683 deletions(-) delete mode 100644 app/Contracts/Repository/Daemon/BaseRepositoryInterface.php delete mode 100644 app/Contracts/Repository/Daemon/CommandRepositoryInterface.php delete mode 100644 app/Contracts/Repository/Daemon/ConfigurationRepositoryInterface.php delete mode 100644 app/Contracts/Repository/Daemon/FileRepositoryInterface.php delete mode 100644 app/Contracts/Repository/Daemon/PowerRepositoryInterface.php delete mode 100644 app/Contracts/Repository/Daemon/ServerRepositoryInterface.php delete mode 100644 app/Http/Controllers/Api/Remote/ValidateKeyController.php delete mode 100644 app/Services/Allocations/SetDefaultAllocationService.php delete mode 100644 app/Services/DaemonKeys/RevokeMultipleDaemonKeysService.php diff --git a/.php_cs b/.php_cs index 8a52ffee6..e72e8e70a 100644 --- a/.php_cs +++ b/.php_cs @@ -47,6 +47,7 @@ return PhpCsFixer\Config::create() 'psr4' => true, 'random_api_migration' => true, 'single_line_throw' => false, + 'single_trait_insert_per_statement' => false, 'standardize_not_equals' => true, 'ternary_to_null_coalescing' => true, 'yoda_style' => [ diff --git a/app/Console/Commands/Server/BulkPowerActionCommand.php b/app/Console/Commands/Server/BulkPowerActionCommand.php index 5e728a037..383879902 100644 --- a/app/Console/Commands/Server/BulkPowerActionCommand.php +++ b/app/Console/Commands/Server/BulkPowerActionCommand.php @@ -5,14 +5,14 @@ namespace Pterodactyl\Console\Commands\Server; use Illuminate\Console\Command; use GuzzleHttp\Exception\RequestException; use Illuminate\Validation\ValidationException; -use Pterodactyl\Repositories\Daemon\PowerRepository; use Illuminate\Validation\Factory as ValidatorFactory; +use Pterodactyl\Repositories\Wings\DaemonPowerRepository; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; class BulkPowerActionCommand extends Command { /** - * @var \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface + * @var \Pterodactyl\Repositories\Wings\DaemonPowerRepository */ private $powerRepository; @@ -42,27 +42,26 @@ class BulkPowerActionCommand extends Command /** * BulkPowerActionCommand constructor. * - * @param \Pterodactyl\Repositories\Daemon\PowerRepository $powerRepository + * @param \Pterodactyl\Repositories\Wings\DaemonPowerRepository $powerRepository * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository * @param \Illuminate\Validation\Factory $validator */ public function __construct( - PowerRepository $powerRepository, + DaemonPowerRepository $powerRepository, ServerRepositoryInterface $repository, ValidatorFactory $validator ) { parent::__construct(); - $this->powerRepository = $powerRepository; $this->repository = $repository; $this->validator = $validator; + $this->powerRepository = $powerRepository; } /** * Handle the bulk power request. * * @throws \Illuminate\Validation\ValidationException - * @throws \Pterodactyl\Exceptions\Repository\Daemon\InvalidPowerSignalException */ public function handle() { @@ -105,7 +104,7 @@ class BulkPowerActionCommand extends Command $this->powerRepository ->setNode($server->node) ->setServer($server) - ->sendSignal($action); + ->send($action); } catch (RequestException $exception) { $this->output->error(trans('command/messages.server.power.action_failed', [ 'name' => $server->name, diff --git a/app/Console/Commands/Server/BulkReinstallActionCommand.php b/app/Console/Commands/Server/BulkReinstallActionCommand.php index b15fbfaa1..a56cefc79 100644 --- a/app/Console/Commands/Server/BulkReinstallActionCommand.php +++ b/app/Console/Commands/Server/BulkReinstallActionCommand.php @@ -12,8 +12,8 @@ namespace Pterodactyl\Console\Commands\Server; use Webmozart\Assert\Assert; use Illuminate\Console\Command; use GuzzleHttp\Exception\RequestException; +use Pterodactyl\Repositories\Eloquent\ServerRepository; use Pterodactyl\Repositories\Wings\DaemonServerRepository; -use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Services\Servers\ServerConfigurationStructureService; class BulkReinstallActionCommand extends Command @@ -21,23 +21,23 @@ class BulkReinstallActionCommand extends Command /** * @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService */ - protected $configurationStructureService; + private $configurationStructureService; /** - * @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface + * @var \Pterodactyl\Repositories\Wings\DaemonServerRepository */ - protected $daemonRepository; + private $daemonRepository; + + /** + * @var \Pterodactyl\Repositories\Eloquent\ServerRepository + */ + private $repository; /** * @var string */ protected $description = 'Reinstall a single server, all servers on a node, or all servers on the panel.'; - /** - * @var \Pterodactyl\Repositories\Wings\DaemonServerRepository - */ - protected $repository; - /** * @var string */ @@ -50,12 +50,12 @@ class BulkReinstallActionCommand extends Command * * @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonRepository * @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $configurationStructureService - * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository + * @param \Pterodactyl\Repositories\Eloquent\ServerRepository $repository */ public function __construct( DaemonServerRepository $daemonRepository, ServerConfigurationStructureService $configurationStructureService, - ServerRepositoryInterface $repository + ServerRepository $repository ) { parent::__construct(); @@ -101,7 +101,7 @@ class BulkReinstallActionCommand extends Command /** * Return the servers to be reinstalled. * - * @return \Illuminate\Database\Eloquent\Collection + * @return \Illuminate\Support\Collection */ private function getServersToProcess() { diff --git a/app/Contracts/Repository/Daemon/BaseRepositoryInterface.php b/app/Contracts/Repository/Daemon/BaseRepositoryInterface.php deleted file mode 100644 index 791dcc819..000000000 --- a/app/Contracts/Repository/Daemon/BaseRepositoryInterface.php +++ /dev/null @@ -1,68 +0,0 @@ -. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -namespace Pterodactyl\Http\Controllers\Api\Remote; - -use Spatie\Fractal\Fractal; -use Illuminate\Http\Response; -use Pterodactyl\Http\Controllers\Controller; -use Illuminate\Contracts\Foundation\Application; -use Illuminate\Foundation\Testing\HttpException; -use League\Fractal\Serializer\JsonApiSerializer; -use Pterodactyl\Transformers\Daemon\ApiKeyTransformer; -use Pterodactyl\Exceptions\Repository\RecordNotFoundException; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface; - -class ValidateKeyController extends Controller -{ - /** - * @var \Illuminate\Contracts\Foundation\Application - */ - protected $app; - - /** - * @var \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface - */ - protected $daemonKeyRepository; - - /** - * @var \Spatie\Fractal\Fractal - */ - protected $fractal; - - /** - * ValidateKeyController constructor. - * - * @param \Illuminate\Contracts\Foundation\Application $app - * @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $daemonKeyRepository - * @param \Spatie\Fractal\Fractal $fractal - */ - public function __construct( - Application $app, - DaemonKeyRepositoryInterface $daemonKeyRepository, - Fractal $fractal - ) { - $this->app = $app; - $this->daemonKeyRepository = $daemonKeyRepository; - $this->fractal = $fractal; - } - - /** - * Return the server(s) and permissions associated with an API key. - * - * @param string $token - * @return array - * - * @throws \Illuminate\Foundation\Testing\HttpException - */ - public function index($token) - { - if (! starts_with($token, DaemonKeyRepositoryInterface::INTERNAL_KEY_IDENTIFIER)) { - throw new HttpException(Response::HTTP_NOT_IMPLEMENTED); - } - - try { - $key = $this->daemonKeyRepository->getKeyWithServer($token); - } catch (RecordNotFoundException $exception) { - throw new NotFoundHttpException; - } - - if ($key->getRelation('server')->suspended || $key->getRelation('server')->installed !== 1) { - throw new NotFoundHttpException; - } - - return $this->fractal->item($key, $this->app->make(ApiKeyTransformer::class), 'server') - ->serializeWith(JsonApiSerializer::class) - ->toArray(); - } -} diff --git a/app/Jobs/Schedule/RunTaskJob.php b/app/Jobs/Schedule/RunTaskJob.php index 0b09102a1..bab5b9f68 100644 --- a/app/Jobs/Schedule/RunTaskJob.php +++ b/app/Jobs/Schedule/RunTaskJob.php @@ -3,33 +3,25 @@ namespace Pterodactyl\Jobs\Schedule; use Exception; -use Cake\Chronos\Chronos; +use Carbon\Carbon; use Pterodactyl\Jobs\Job; use InvalidArgumentException; +use Illuminate\Container\Container; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\DispatchesJobs; +use Pterodactyl\Repositories\Eloquent\TaskRepository; +use Pterodactyl\Repositories\Wings\DaemonPowerRepository; +use Pterodactyl\Repositories\Wings\DaemonCommandRepository; use Pterodactyl\Contracts\Repository\TaskRepositoryInterface; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface; -use Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface; -use Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface; class RunTaskJob extends Job implements ShouldQueue { use DispatchesJobs, InteractsWithQueue, SerializesModels; - /** - * @var \Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface - */ - protected $commandRepository; - - /** - * @var \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface - */ - protected $powerRepository; - /** * @var int */ @@ -41,7 +33,7 @@ class RunTaskJob extends Job implements ShouldQueue public $task; /** - * @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface + * @var \Pterodactyl\Repositories\Eloquent\TaskRepository */ protected $taskRepository; @@ -61,28 +53,24 @@ class RunTaskJob extends Job implements ShouldQueue /** * Run the job and send actions to the daemon running the server. * - * @param \Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface $commandRepository + * @param \Pterodactyl\Repositories\Wings\DaemonCommandRepository $commandRepository * @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService - * @param \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface $powerRepository - * @param \Pterodactyl\Contracts\Repository\TaskRepositoryInterface $taskRepository + * @param \Pterodactyl\Repositories\Wings\DaemonPowerRepository $powerRepository + * @param \Pterodactyl\Repositories\Eloquent\TaskRepository $taskRepository * * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\Daemon\InvalidPowerSignalException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function handle( - CommandRepositoryInterface $commandRepository, + DaemonCommandRepository $commandRepository, DaemonKeyProviderService $keyProviderService, - PowerRepositoryInterface $powerRepository, - TaskRepositoryInterface $taskRepository + DaemonPowerRepository $powerRepository, + TaskRepository $taskRepository ) { - $this->commandRepository = $commandRepository; - $this->powerRepository = $powerRepository; $this->taskRepository = $taskRepository; $task = $this->taskRepository->getTaskForJobProcess($this->task); $server = $task->getRelation('server'); - $user = $server->getRelation('user'); // Do not process a task that is not set to active. if (! $task->getRelation('schedule')->is_active) { @@ -95,14 +83,10 @@ class RunTaskJob extends Job implements ShouldQueue // Perform the provided task against the daemon. switch ($task->action) { case 'power': - $this->powerRepository->setServer($server) - ->setToken($keyProviderService->handle($server, $user)) - ->sendSignal($task->payload); + $powerRepository->setServer($server)->send($task->payload); break; case 'command': - $this->commandRepository->setServer($server) - ->setToken($keyProviderService->handle($server, $user)) - ->send($task->payload); + $commandRepository->setServer($server)->send($task->payload); break; default: throw new InvalidArgumentException('Cannot run a task that points to a non-existent action.'); @@ -115,10 +99,7 @@ class RunTaskJob extends Job implements ShouldQueue /** * Handle a failure while sending the action to the daemon or otherwise processing the job. * - * @param null|\Exception $exception - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * @param \Exception|null $exception */ public function failed(Exception $exception = null) { @@ -149,28 +130,25 @@ class RunTaskJob extends Job implements ShouldQueue /** * Marks the parent schedule as being complete. - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ private function markScheduleComplete() { - $repository = app()->make(ScheduleRepositoryInterface::class); - $repository->withoutFreshModel()->update($this->schedule, [ - 'is_processing' => false, - 'last_run_at' => Chronos::now()->toDateTimeString(), - ]); + Container::getInstance() + ->make(ScheduleRepositoryInterface::class) + ->withoutFreshModel() + ->update($this->schedule, [ + 'is_processing' => false, + 'last_run_at' => Carbon::now()->toDateTimeString(), + ]); } /** * Mark a specific task as no longer being queued. - * - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ private function markTaskNotQueued() { - $repository = app()->make(TaskRepositoryInterface::class); - $repository->update($this->task, ['is_queued' => false]); + Container::getInstance() + ->make(TaskRepositoryInterface::class) + ->update($this->task, ['is_queued' => false]); } } diff --git a/app/Providers/RepositoryServiceProvider.php b/app/Providers/RepositoryServiceProvider.php index 6ee5a8d5c..ef8e6cb0a 100644 --- a/app/Providers/RepositoryServiceProvider.php +++ b/app/Providers/RepositoryServiceProvider.php @@ -13,15 +13,12 @@ use Pterodactyl\Repositories\Eloquent\ApiKeyRepository; use Pterodactyl\Repositories\Eloquent\ServerRepository; use Pterodactyl\Repositories\Eloquent\SessionRepository; use Pterodactyl\Repositories\Eloquent\SubuserRepository; -use Pterodactyl\Repositories\Wings\DaemonFileRepository; use Pterodactyl\Repositories\Eloquent\DatabaseRepository; use Pterodactyl\Repositories\Eloquent\LocationRepository; use Pterodactyl\Repositories\Eloquent\ScheduleRepository; use Pterodactyl\Repositories\Eloquent\SettingsRepository; -use Pterodactyl\Repositories\Wings\DaemonPowerRepository; use Pterodactyl\Repositories\Eloquent\DaemonKeyRepository; use Pterodactyl\Repositories\Eloquent\AllocationRepository; -use Pterodactyl\Repositories\Wings\DaemonCommandRepository; use Pterodactyl\Contracts\Repository\EggRepositoryInterface; use Pterodactyl\Repositories\Eloquent\EggVariableRepository; use Pterodactyl\Contracts\Repository\NestRepositoryInterface; @@ -39,18 +36,11 @@ use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface; use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface; -use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository; use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface; use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; -use Pterodactyl\Contracts\Repository\Daemon\FileRepositoryInterface; use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface; -use Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; -use Pterodactyl\Contracts\Repository\Daemon\CommandRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface; -use Pterodactyl\Contracts\Repository\Daemon\ConfigurationRepositoryInterface; -use Pterodactyl\Repositories\Wings\DaemonServerRepository as DaemonServerRepository; -use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface; class RepositoryServiceProvider extends ServiceProvider { @@ -79,12 +69,5 @@ class RepositoryServiceProvider extends ServiceProvider $this->app->bind(SubuserRepositoryInterface::class, SubuserRepository::class); $this->app->bind(TaskRepositoryInterface::class, TaskRepository::class); $this->app->bind(UserRepositoryInterface::class, UserRepository::class); - - // Daemon Repositories - $this->app->bind(ConfigurationRepositoryInterface::class, DaemonConfigurationRepository::class); - $this->app->bind(CommandRepositoryInterface::class, DaemonCommandRepository::class); - $this->app->bind(DaemonServerRepositoryInterface::class, DaemonServerRepository::class); - $this->app->bind(FileRepositoryInterface::class, DaemonFileRepository::class); - $this->app->bind(PowerRepositoryInterface::class, DaemonPowerRepository::class); } } diff --git a/app/Services/Allocations/SetDefaultAllocationService.php b/app/Services/Allocations/SetDefaultAllocationService.php deleted file mode 100644 index b05b1c48f..000000000 --- a/app/Services/Allocations/SetDefaultAllocationService.php +++ /dev/null @@ -1,110 +0,0 @@ -connection = $connection; - $this->daemonRepository = $daemonRepository; - $this->repository = $repository; - $this->serverRepository = $serverRepository; - } - - /** - * Update the default allocation for a server only if that allocation is currently - * assigned to the specified server. - * - * @param int|\Pterodactyl\Models\Server $server - * @param int $allocation - * @return \Pterodactyl\Models\Allocation - * - * @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException - * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - * @throws \Pterodactyl\Exceptions\Service\Allocation\AllocationDoesNotBelongToServerException - */ - public function handle($server, int $allocation): Allocation - { - if (! $server instanceof Server) { - $server = $this->serverRepository->find($server); - } - - $allocations = $this->repository->findWhere([['server_id', '=', $server->id]]); - $model = $allocations->filter(function ($model) use ($allocation) { - return $model->id === $allocation; - })->first(); - - if (! $model instanceof Allocation) { - throw new AllocationDoesNotBelongToServerException; - } - - $this->connection->beginTransaction(); - $this->serverRepository->withoutFreshModel()->update($server->id, ['allocation_id' => $model->id]); - - // Update on the daemon. - try { - $this->daemonRepository->setServer($server)->update([ - 'build' => [ - 'default' => [ - 'ip' => $model->ip, - 'port' => $model->port, - ], - 'ports|overwrite' => $allocations->groupBy('ip')->map(function ($item) { - return $item->pluck('port'); - })->toArray(), - ], - ]); - - $this->connection->commit(); - } catch (RequestException $exception) { - $this->connection->rollBack(); - throw new DaemonConnectionException($exception); - } - - return $model; - } -} diff --git a/app/Services/DaemonKeys/RevokeMultipleDaemonKeysService.php b/app/Services/DaemonKeys/RevokeMultipleDaemonKeysService.php deleted file mode 100644 index 84237f94d..000000000 --- a/app/Services/DaemonKeys/RevokeMultipleDaemonKeysService.php +++ /dev/null @@ -1,89 +0,0 @@ -daemonRepository = $daemonRepository; - $this->repository = $repository; - } - - /** - * Grab all of the keys that exist for a single user and delete them from all - * daemon's that they are assigned to. If connection fails, this function will - * return an error. - * - * @param \Pterodactyl\Models\User $user - * @param bool $ignoreConnectionErrors - */ - public function handle(User $user, bool $ignoreConnectionErrors = false) - { - $keys = $this->repository->getKeysForRevocation($user); - - $keys->groupBy('node.id')->each(function ($group, $nodeId) use ($ignoreConnectionErrors) { - try { - $this->daemonRepository->setNode(collect($group)->first()->getRelation('node'))->revokeAccessKey(collect($group)->pluck('secret')->toArray()); - } catch (RequestException $exception) { - if (! $ignoreConnectionErrors) { - throw new DaemonConnectionException($exception); - } - - $this->setConnectionException($nodeId, $exception); - } - - $this->repository->deleteKeys(collect($group)->pluck('id')->toArray()); - }); - } - - /** - * Returns an array of exceptions that were returned by the handle function. - * - * @return RequestException[] - */ - public function getExceptions() - { - return $this->exceptions; - } - - /** - * Add an exception for a node to the array. - * - * @param int $node - * @param \GuzzleHttp\Exception\RequestException $exception - */ - protected function setConnectionException(int $node, RequestException $exception) - { - $this->exceptions[$node] = $exception; - } -}