diff --git a/app/Http/Controllers/Server/CredentialsController.php b/app/Http/Controllers/Server/CredentialsController.php new file mode 100644 index 000000000..36e6489ee --- /dev/null +++ b/app/Http/Controllers/Server/CredentialsController.php @@ -0,0 +1,48 @@ +keyProviderService = $keyProviderService; + } + + /** + * Return a set of credentials that the currently authenticated user can use to access + * a given server with. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function index(Request $request): JsonResponse + { + /** @var \Pterodactyl\Models\Server $server */ + $server = $request->attributes->get('server'); + $server->loadMissing('node'); + + return JsonResponse::create([ + 'node' => $server->getRelation('node')->getConnectionAddress(), + 'key' => $this->keyProviderService->handle($server, $request->user()), + ]); + } +} diff --git a/app/Models/Node.php b/app/Models/Node.php index 2643d062a..4d6348e4c 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -131,6 +131,16 @@ class Node extends Model implements CleansAttributes, ValidableContract 'maintenance_mode' => false, ]; + /** + * Get the connection address to use when making calls to this node. + * + * @return string + */ + public function getConnectionAddress(): string + { + return sprintf('%s://%s:%s', $this->scheme, $this->fqdn, $this->daemonListen); + } + /** * Returns the configuration in JSON format. * diff --git a/package.json b/package.json index aba89a6de..f7ea216e8 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "pterodactyl-panel", "dependencies": { "date-fns": "^1.29.0", + "socket.io-client": "^2.1.1", "vee-validate": "^2.1.0-beta.2", "vue": "^2.5.7", "vue-axios": "^2.1.1", diff --git a/resources/assets/scripts/components/server/Server.vue b/resources/assets/scripts/components/server/Server.vue index 75d93e587..4039967be 100644 --- a/resources/assets/scripts/components/server/Server.vue +++ b/resources/assets/scripts/components/server/Server.vue @@ -69,6 +69,8 @@ import {mapState} from 'vuex'; import { ConsolePage } from './subpages/ConsolePage'; + import io from 'socket.io-client'; + export default { components: { ProgressBar, Navigation, ConsolePage, TerminalIcon, FolderIcon, UsersIcon, @@ -76,7 +78,7 @@ }, computed: { - ...mapState('server', ['server']), + ...mapState('server', ['server', 'credentials']), }, mounted: function () { @@ -85,20 +87,70 @@ data: function () { return { + socket: null, loadingServerData: true, }; }, methods: { + /** + * Load the core server information needed for these pages to be functional. + */ loadServer: function () { - this.$store.dispatch('server/getServer', {server: this.$route.params.id}) + Promise.all([ + this.$store.dispatch('server/getServer', {server: this.$route.params.id}), + this.$store.dispatch('server/getCredentials', {server: this.$route.params.id}) + ]) .then(() => { this.loadingServerData = false; + this.initalizeWebsocket(); }) - .catch(err => { - console.error(err); - }); + .catch(console.error); }, - } + + initalizeWebsocket: function () { + this.$store.commit('server/CONSOLE_DATA', 'Connecting to ' + this.credentials.node + '...'); + this.socket = io(this.credentials.node + '/v1/ws/' + this.server.uuid, { + query: 'token=' + this.credentials.key, + }); + + this.socket.on('error', this._socket_error); + this.socket.on('connect', this._socket_connect); + this.socket.on('status', this._socket_status); + this.socket.on('initial status', this._socket_status); + this.socket.on('server log', this._socket_serverLog); + this.socket.on('console', this._socket_consoleLine); + }, + + _socket_error: function (err) { + this.$store.commit('server/CONSOLE_DATA', 'There was a socket error: ' + err); + console.error('there was a socket error:', err); + }, + + _socket_connect: function () { + this.$store.commit('server/CONSOLE_DATA', 'Connected to socket.'); + this.socket.emit('send server log'); + console.log('connected'); + }, + + _socket_status: function (data) { + this.$store.commit('server/CONSOLE_DATA', 'Server state has changed.'); + console.warn(data); + }, + + _socket_serverLog: function (data) { + data.split(/\n/g).forEach(item => { + this.$store.commit('server/CONSOLE_DATA', item); + }); + }, + + _socket_consoleLine: function (data) { + if(data.line) { + data.line.split(/\n/g).forEach((item) => { + this.$store.commit('server/CONSOLE_DATA', item); + }); + } + } + }, } diff --git a/resources/assets/scripts/components/server/subpages/ConsolePage.vue b/resources/assets/scripts/components/server/subpages/ConsolePage.vue index 5db738959..e9787f38a 100644 --- a/resources/assets/scripts/components/server/subpages/ConsolePage.vue +++ b/resources/assets/scripts/components/server/subpages/ConsolePage.vue @@ -1,8 +1,8 @@