diff --git a/app/Http/Controllers/Api/Client/Servers/WebsocketController.php b/app/Http/Controllers/Api/Client/Servers/WebsocketController.php index 5aaf28afd..f81bb227f 100644 --- a/app/Http/Controllers/Api/Client/Servers/WebsocketController.php +++ b/app/Http/Controllers/Api/Client/Servers/WebsocketController.php @@ -61,15 +61,18 @@ class WebsocketController extends ClientApiController $permissions = $this->permissionsService->handle($server, $user); $node = null; - - // Check if there is a transfer query param asking to connect to the target node's websocket. - if ($request->query('transfer', 'false') === 'true') { + if ($server->transfer !== null) { // Check if the user has permissions to receive transfer logs. if (! in_array('admin.websocket.transfer', $permissions)) { - throw new HttpException(Response::HTTP_FORBIDDEN, 'You do not have permission to get transfer logs'); + throw new HttpException(Response::HTTP_FORBIDDEN, 'You do not have permission to view transfer logs'); } - $node = $server->transfer->newNode; + // Redirect the websocket request to the new node if the server has been archived. + if ($server->transfer->archived) { + $node = $server->transfer->newNode; + } else { + $node = $server->node; + } } else { $node = $server->node; } diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php index 388a1b5b3..8ee2c242f 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php @@ -112,7 +112,6 @@ class ServerTransferController extends Controller // Unsuspend the server and don't continue the transfer. if (! $request->input('successful')) { - //$this->suspensionService->toggle($server, 'unsuspend'); $server->transfer->forceFill([ 'successful' => false, ])->saveOrFail(); @@ -142,6 +141,12 @@ class ServerTransferController extends Controller ->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. diff --git a/app/Models/ServerTransfer.php b/app/Models/ServerTransfer.php index e7bde02f9..cb95fefc7 100644 --- a/app/Models/ServerTransfer.php +++ b/app/Models/ServerTransfer.php @@ -12,6 +12,7 @@ namespace Pterodactyl\Models; * @property string $old_additional_allocations * @property string $new_additional_allocations * @property bool|null $successful + * @property bool $archived * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at * @@ -55,6 +56,7 @@ class ServerTransfer extends Model 'old_additional_allocations' => 'string', 'new_additional_allocations' => 'string', 'successful' => 'bool', + 'archived' => 'bool', ]; /** diff --git a/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php b/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php new file mode 100644 index 000000000..1162d8a4f --- /dev/null +++ b/database/migrations/2020_12_17_014330_add_archived_field_to_server_transfers_table.php @@ -0,0 +1,38 @@ +boolean('archived')->default(0)->after('new_additional_allocations'); + }); + + // Update archived to all be true on existing transfers. + Schema::table('server_transfers', function (Blueprint $table) { + DB::statement('UPDATE `server_transfers` SET `archived` = 1 WHERE `successful` = 1'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('server_transfers', function (Blueprint $table) { + $table->dropColumn('archived'); + }); + } +} diff --git a/resources/scripts/api/server/getWebsocketToken.ts b/resources/scripts/api/server/getWebsocketToken.ts index d1e1f24a9..da78dfd05 100644 --- a/resources/scripts/api/server/getWebsocketToken.ts +++ b/resources/scripts/api/server/getWebsocketToken.ts @@ -5,13 +5,9 @@ interface Response { socket: string; } -export default (server: string, transfer: boolean): Promise => { +export default (server: string): Promise => { return new Promise((resolve, reject) => { - http.get(`/api/client/servers/${server}/websocket`, { - params: { - transfer, - }, - }) + http.get(`/api/client/servers/${server}/websocket`) .then(({ data }) => resolve({ token: data.data.token, socket: data.data.socket, diff --git a/resources/scripts/components/server/WebsocketHandler.tsx b/resources/scripts/components/server/WebsocketHandler.tsx index 085cd40f3..d519da4f5 100644 --- a/resources/scripts/components/server/WebsocketHandler.tsx +++ b/resources/scripts/components/server/WebsocketHandler.tsx @@ -15,15 +15,12 @@ const reconnectErrors = [ export default () => { let updatingToken = false; const [ error, setError ] = useState<'connecting' | string>(''); - const [ transfer, setTransfer ] = useState(false); const { connected, instance } = ServerContext.useStoreState(state => state.socket); const uuid = ServerContext.useStoreState(state => state.server.data?.uuid); const setServerStatus = ServerContext.useStoreActions(actions => actions.status.setServerStatus); const { setInstance, setConnectionState } = ServerContext.useStoreActions(actions => actions.socket); - const connect = (uuid: string, transfer = false) => { - setTransfer(transfer); - + const connect = (uuid: string) => { const socket = new Websocket(); socket.on('auth success', () => setConnectionState(true)); @@ -52,21 +49,12 @@ export default () => { }); socket.on('transfer status', (status: string) => { - if (status === 'success') { - setTransfer(false); + if (status === 'starting' || status === 'success') { return; } - if (status === 'starting') { - return; - } - - // This doesn't use the `setTransfer` hook as it doesn't want to work properly in this context, - // and causes all kinds of fuckery with the websocket. - let transfer = false; - if (status === 'archived') { - transfer = true; - } + // Force a reconnection to the websocket which will connect us + // to the target node instead of the source node. // Close the current websocket connection. socket.close(); @@ -75,10 +63,10 @@ export default () => { setConnectionState(false); setInstance(null); - connect(uuid, transfer); + connect(uuid); }); - getWebsocketToken(uuid, transfer) + getWebsocketToken(uuid) .then(data => { // Connect and then set the authentication token. socket.setToken(data.token).connect(data.socket); @@ -93,7 +81,7 @@ export default () => { if (updatingToken) return; updatingToken = true; - getWebsocketToken(uuid, transfer) + getWebsocketToken(uuid) .then(data => socket.setToken(data.token, true)) .catch(error => console.error(error)) .then(() => {