Skip to content

Commit df2402b

Browse files
authored
Streaming Transfers (pterodactyl#4548)
1 parent 032e4f2 commit df2402b

File tree

6 files changed

+38
-106
lines changed

6 files changed

+38
-106
lines changed

app/Http/Controllers/Admin/Servers/ServerTransferController.php

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22

33
namespace Pterodactyl\Http\Controllers\Admin\Servers;
44

5+
use Carbon\CarbonImmutable;
56
use Illuminate\Http\Request;
67
use Pterodactyl\Models\Server;
78
use Illuminate\Http\RedirectResponse;
89
use Prologue\Alerts\AlertsMessageBag;
910
use Pterodactyl\Models\ServerTransfer;
11+
use Illuminate\Database\ConnectionInterface;
1012
use Pterodactyl\Http\Controllers\Controller;
11-
use Pterodactyl\Services\Servers\TransferService;
13+
use Pterodactyl\Services\Nodes\NodeJWTService;
1214
use Pterodactyl\Repositories\Eloquent\NodeRepository;
13-
use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository;
15+
use Pterodactyl\Repositories\Wings\DaemonTransferRepository;
1416
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
1517

1618
class ServerTransferController extends Controller
@@ -21,9 +23,10 @@ class ServerTransferController extends Controller
2123
public function __construct(
2224
private AlertsMessageBag $alert,
2325
private AllocationRepositoryInterface $allocationRepository,
24-
private NodeRepository $nodeRepository,
25-
private TransferService $transferService,
26-
private DaemonConfigurationRepository $daemonConfigurationRepository
26+
private ConnectionInterface $connection,
27+
private DaemonTransferRepository $daemonTransferRepository,
28+
private NodeJWTService $nodeJWTService,
29+
private NodeRepository $nodeRepository
2730
) {
2831
}
2932

@@ -46,12 +49,15 @@ public function transfer(Request $request, Server $server): RedirectResponse
4649

4750
// Check if the node is viable for the transfer.
4851
$node = $this->nodeRepository->getNodeWithResourceUsage($node_id);
49-
if ($node->isViable($server->memory, $server->disk)) {
50-
// Check if the selected daemon is online.
51-
$this->daemonConfigurationRepository->setNode($node)->getSystemInformation();
52+
if (!$node->isViable($server->memory, $server->disk)) {
53+
$this->alert->danger(trans('admin/server.alerts.transfer_not_viable'))->flash();
54+
55+
return redirect()->route('admin.servers.view.manage', $server->id);
56+
}
5257

53-
$server->validateTransferState();
58+
$server->validateTransferState();
5459

60+
$this->connection->transaction(function () use ($server, $node_id, $allocation_id, $additional_allocations) {
5561
// Create a new ServerTransfer entry.
5662
$transfer = new ServerTransfer();
5763

@@ -68,13 +74,19 @@ public function transfer(Request $request, Server $server): RedirectResponse
6874
// Add the allocations to the server, so they cannot be automatically assigned while the transfer is in progress.
6975
$this->assignAllocationsToServer($server, $node_id, $allocation_id, $additional_allocations);
7076

71-
// Request an archive from the server's current daemon. (this also checks if the daemon is online)
72-
$this->transferService->requestArchive($server);
77+
// Generate a token for the destination node that the source node can use to authenticate with.
78+
$token = $this->nodeJWTService
79+
->setExpiresAt(CarbonImmutable::now()->addMinutes(15))
80+
->setSubject($server->uuid)
81+
->handle($transfer->newNode, $server->uuid, 'sha256');
7382

74-
$this->alert->success(trans('admin/server.alerts.transfer_started'))->flash();
75-
} else {
76-
$this->alert->danger(trans('admin/server.alerts.transfer_not_viable'))->flash();
77-
}
83+
// Notify the source node of the pending outgoing transfer.
84+
$this->daemonTransferRepository->setServer($server)->notify($transfer->newNode, $token);
85+
86+
return $transfer;
87+
});
88+
89+
$this->alert->success(trans('admin/server.alerts.transfer_started'))->flash();
7890

7991
return redirect()->route('admin.servers.view.manage', $server->id);
8092
}

app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@
22

33
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
44

5-
use Carbon\CarbonImmutable;
6-
use Illuminate\Http\Request;
75
use Illuminate\Http\Response;
86
use Illuminate\Http\JsonResponse;
97
use Pterodactyl\Models\Allocation;
108
use Illuminate\Support\Facades\Log;
119
use Pterodactyl\Models\ServerTransfer;
1210
use Illuminate\Database\ConnectionInterface;
1311
use Pterodactyl\Http\Controllers\Controller;
14-
use Pterodactyl\Services\Nodes\NodeJWTService;
1512
use Pterodactyl\Repositories\Eloquent\ServerRepository;
1613
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
17-
use Pterodactyl\Repositories\Wings\DaemonTransferRepository;
1814
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
1915

2016
class ServerTransferController extends Controller
@@ -25,52 +21,10 @@ class ServerTransferController extends Controller
2521
public function __construct(
2622
private ConnectionInterface $connection,
2723
private ServerRepository $repository,
28-
private DaemonServerRepository $daemonServerRepository,
29-
private DaemonTransferRepository $daemonTransferRepository,
30-
private NodeJWTService $jwtService
24+
private DaemonServerRepository $daemonServerRepository
3125
) {
3226
}
3327

34-
/**
35-
* The daemon notifies us about the archive status.
36-
*
37-
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
38-
* @throws \Throwable
39-
*/
40-
public function archive(Request $request, string $uuid): JsonResponse
41-
{
42-
$server = $this->repository->getByUuid($uuid);
43-
44-
// Unsuspend the server and don't continue the transfer.
45-
if (!$request->input('successful')) {
46-
return $this->processFailedTransfer($server->transfer);
47-
}
48-
49-
$this->connection->transaction(function () use ($server) {
50-
// This token is used by the new node the server is being transferred to. It allows
51-
// that node to communicate with the old node during the process to initiate the
52-
// actual file transfer.
53-
$token = $this->jwtService
54-
->setExpiresAt(CarbonImmutable::now()->addMinutes(15))
55-
->setSubject($server->uuid)
56-
->handle($server->node, $server->uuid, 'sha256');
57-
58-
// Update the archived field on the transfer to make clients connect to the websocket
59-
// on the new node to be able to receive transfer logs.
60-
$server->transfer->forceFill(['archived' => true])->saveOrFail();
61-
62-
// On the daemon transfer repository, make sure to set the node after the server
63-
// because setServer() tells the repository to use the server's node and not the one
64-
// we want to specify.
65-
$this->daemonTransferRepository
66-
->setServer($server)
67-
->setNode($server->transfer->newNode)
68-
->notify($server, $token);
69-
});
70-
71-
return new JsonResponse([], Response::HTTP_NO_CONTENT);
72-
}
73-
7428
/**
7529
* The daemon notifies us about a transfer failure.
7630
*

app/Repositories/Wings/DaemonTransferRepository.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
namespace Pterodactyl\Repositories\Wings;
44

5+
use Pterodactyl\Models\Node;
56
use Lcobucci\JWT\Token\Plain;
6-
use Pterodactyl\Models\Server;
77
use GuzzleHttp\Exception\GuzzleException;
88
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
99

@@ -12,16 +12,16 @@ class DaemonTransferRepository extends DaemonRepository
1212
/**
1313
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
1414
*/
15-
public function notify(Server $server, Plain $token): void
15+
public function notify(Node $targetNode, Plain $token): void
1616
{
1717
try {
18-
$this->getHttpClient()->post('/api/transfer', [
18+
$this->getHttpClient()->post(sprintf('/api/servers/%s/transfer', $this->server->uuid), [
1919
'json' => [
20-
'server_id' => $server->uuid,
21-
'url' => $server->node->getConnectionAddress() . sprintf('/api/servers/%s/archive', $server->uuid),
20+
'server_id' => $this->server->uuid,
21+
'url' => $targetNode->getConnectionAddress() . '/api/transfers',
2222
'token' => 'Bearer ' . $token->toString(),
2323
'server' => [
24-
'uuid' => $server->uuid,
24+
'uuid' => $this->server->uuid,
2525
'start_on_completion' => false,
2626
],
2727
],

app/Services/Servers/TransferService.php

Lines changed: 0 additions & 27 deletions
This file was deleted.

resources/scripts/components/server/TransferListener.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ const TransferListener = () => {
77
const getServer = ServerContext.useStoreActions((actions) => actions.server.getServer);
88
const setServerFromState = ServerContext.useStoreActions((actions) => actions.server.setServerFromState);
99

10-
// Listen for the transfer status event so we can update the state of the server.
10+
// Listen for the transfer status event, so we can update the state of the server.
1111
useWebsocketEvent(SocketEvent.TRANSFER_STATUS, (status: string) => {
12-
if (status === 'starting') {
12+
if (status === 'pending' || status === 'processing') {
1313
setServerFromState((s) => ({ ...s, isTransferring: true }));
1414
return;
1515
}
1616

17-
if (status === 'failure') {
17+
if (status === 'failed') {
1818
setServerFromState((s) => ({ ...s, isTransferring: false }));
1919
return;
2020
}
2121

22-
if (status !== 'success') {
22+
if (status !== 'completed') {
2323
return;
2424
}
2525

resources/scripts/components/server/console/Console.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,6 @@ export default () => {
7676
case 'failure':
7777
terminal.writeln(TERMINAL_PRELUDE + 'Transfer has failed.\u001b[0m');
7878
return;
79-
80-
// Sent by the source node whenever the server was archived successfully.
81-
case 'archive':
82-
terminal.writeln(
83-
TERMINAL_PRELUDE +
84-
'Server has been archived successfully, attempting connection to target node..\u001b[0m'
85-
);
8679
}
8780
};
8881

0 commit comments

Comments
 (0)