From 3b11ba9fcaa7913135115cc9f592110b647f59b4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 18 Jan 2020 15:26:15 -0800 Subject: [PATCH] Basic support for installation process --- .../Client/Servers/WebsocketController.php | 2 +- .../Servers/ServerInstallController.php | 47 +++++++++++++++++++ app/Models/Pack.php | 16 +++++++ app/Models/Server.php | 4 +- .../scripts/components/server/Console.tsx | 13 +++-- routes/api-remote.php | 5 +- 6 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php diff --git a/app/Http/Controllers/Api/Client/Servers/WebsocketController.php b/app/Http/Controllers/Api/Client/Servers/WebsocketController.php index dd12ce8ce..4468aa733 100644 --- a/app/Http/Controllers/Api/Client/Servers/WebsocketController.php +++ b/app/Http/Controllers/Api/Client/Servers/WebsocketController.php @@ -67,7 +67,7 @@ class WebsocketController extends ClientApiController 'connect', 'send-command', 'send-power', - ], $request->user()->root_admin ? ['receive-errors'] : [])) + ], $request->user()->root_admin ? ['receive-errors', 'receive-install'] : [])) ->getToken($signer, new Key($server->node->daemonSecret)); $socket = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $server->node->getConnectionAddress()); diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php b/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php new file mode 100644 index 000000000..0dfc1dd64 --- /dev/null +++ b/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php @@ -0,0 +1,47 @@ +repository = $repository; + } + + /** + * Returns installation information for a server. + * + * @param \Illuminate\Http\Request $request + * @param string $uuid + * @return \Illuminate\Http\JsonResponse + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function __invoke(Request $request, string $uuid) + { + $server = $this->repository->getByUuid($uuid); + $egg = $server->egg; + + return JsonResponse::create([ + 'container_image' => $egg->copy_script_container, + 'entrypoint' => $egg->copy_script_entry, + 'script' => $egg->copy_script_install, + ]); + } +} diff --git a/app/Models/Pack.php b/app/Models/Pack.php index 4eddf797b..092f1cbf2 100644 --- a/app/Models/Pack.php +++ b/app/Models/Pack.php @@ -4,6 +4,22 @@ namespace Pterodactyl\Models; use Pterodactyl\Models\Traits\Searchable; +/** + * @property int $id + * @property int $egg_id + * @property string $uuid + * @property string $name + * @property string $version + * @property string $description + * @property bool $selectable + * @property bool $visible + * @property bool $locked + * @property \Carbon\Carbon $created_at + * @property \Carbon\Carbon $updated_at + * + * @property \Pterodactyl\Models\Egg|null $egg + * @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers + */ class Pack extends Validable { use Searchable; diff --git a/app/Models/Server.php b/app/Models/Server.php index 995b07ca5..9bdb19ff1 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -253,11 +253,11 @@ class Server extends Validable /** * Gets information for the egg associated with this server. * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + * @return \Illuminate\Database\Eloquent\Relations\HasOne */ public function egg() { - return $this->belongsTo(Egg::class); + return $this->hasOne(Egg::class, 'id', 'egg_id'); } /** diff --git a/resources/scripts/components/server/Console.tsx b/resources/scripts/components/server/Console.tsx index abcf60558..5f659be88 100644 --- a/resources/scripts/components/server/Console.tsx +++ b/resources/scripts/components/server/Console.tsx @@ -47,21 +47,22 @@ const TerminalDiv = styled.div` `; export default () => { + const TERMINAL_PRELUDE = '\u001b[1m\u001b[33mcontainer@pterodactyl~ \u001b[0m'; const [ terminalElement, setTerminalElement ] = useState(null); const useRef = useCallback(node => setTerminalElement(node), []); const terminal = useMemo(() => new Terminal({ ...terminalProps }), []); const { connected, instance } = ServerContext.useStoreState(state => state.socket); - const handleConsoleOutput = (line: string) => terminal.writeln( - line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m', + const handleConsoleOutput = (line: string, prelude = false) => terminal.writeln( + (prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m', ); const handleDaemonErrorOutput = (line: string) => terminal.writeln( - '\u001b[1m\u001b[41m[Internal] ' + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m', + TERMINAL_PRELUDE + '\u001b[1m\u001b[41m' + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m', ); const handlePowerChangeEvent = (state: string) => terminal.writeln( - '\u001b[1m\u001b[33m[Status Change] Server marked as ' + state + '...\u001b[0m', + TERMINAL_PRELUDE + 'Server marked as ' + state + '...\u001b[0m', ); const handleCommandKeydown = (e: React.KeyboardEvent) => { @@ -89,12 +90,16 @@ export default () => { instance.addListener('status', handlePowerChangeEvent); instance.addListener('console output', handleConsoleOutput); + instance.addListener('install output', handleConsoleOutput); + instance.addListener('daemon message', line => handleConsoleOutput(line, true)); instance.addListener('daemon error', handleDaemonErrorOutput); instance.send('send logs'); } return () => { instance && instance.removeListener('console output', handleConsoleOutput) + .removeListener('install output', handleConsoleOutput) + .removeListener('daemon message', line => handleConsoleOutput(line, true)) .removeListener('daemon error', handleDaemonErrorOutput) .removeListener('status', handlePowerChangeEvent); }; diff --git a/routes/api-remote.php b/routes/api-remote.php index 476e90512..fa8989ddc 100644 --- a/routes/api-remote.php +++ b/routes/api-remote.php @@ -5,12 +5,9 @@ use Illuminate\Support\Facades\Route; Route::get('/authenticate/{token}', 'ValidateKeyController@index'); Route::post('/download-file', 'FileDownloadController@index'); -Route::group(['prefix' => '/scripts'], function () { - Route::get('/{uuid}', 'EggInstallController@index')->name('api.remote.scripts'); -}); - // Routes for the Wings daemon. Route::post('/sftp/auth', 'SftpAuthenticationController'); Route::group(['prefix' => '/servers/{uuid}'], function () { Route::get('/', 'Servers\ServerDetailsController'); + Route::get('/install', 'Servers\ServerInstallController'); });