From e87c5f66573418768b3dbf7a28af743ad4e4e723 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 1 May 2019 20:12:20 -0700 Subject: [PATCH] Implement basic support for connecting to wings console via websocket rather than socketio --- package.json | 3 +- .../themes/pterodactyl/js/frontend/console.js | 4 +- .../scripts/components/server/Server.vue | 17 +-- .../server/components/PowerButtons.vue | 4 +- .../components/server/subpages/Console.vue | 20 +--- resources/assets/scripts/helpers/statuses.ts | 8 +- resources/assets/scripts/helpers/ziggy.js | 2 +- .../scripts/mixins/socketio/connector.ts | 103 ++++++++++-------- .../assets/scripts/mixins/socketio/index.ts | 7 +- .../assets/scripts/store/modules/socket.ts | 13 +-- resources/assets/scripts/store/types.ts | 2 +- yarn.lock | 56 +++++----- 12 files changed, 122 insertions(+), 117 deletions(-) diff --git a/package.json b/package.json index f30057146..2ffaa9358 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "feather-icons": "^4.10.0", "jquery": "^3.3.1", "lodash": "^4.17.11", - "socket.io-client": "^2.1.1", + "socket.io-client": "^2.2.0", "vee-validate": "^2.1.7", "vue": "^2.6.4", "vue-axios": "^2.1.1", @@ -14,6 +14,7 @@ "vue-router": "^3.0.1", "vuex": "^3.0.1", "vuex-router-sync": "^5.0.0", + "ws-wrapper": "^2.0.0", "xterm": "^3.5.1" }, "devDependencies": { diff --git a/public/themes/pterodactyl/js/frontend/console.js b/public/themes/pterodactyl/js/frontend/console.js index 8943da42a..41a3d716b 100644 --- a/public/themes/pterodactyl/js/frontend/console.js +++ b/public/themes/pterodactyl/js/frontend/console.js @@ -65,7 +65,7 @@ $(document).ready(function () { if (e.which === 13) { saveToHistory($(this).val()); - Socket.emit((ConsoleServerStatus !== 0) ? 'send command' : 'set status', $(this).val()); + Socket.emit((ConsoleServerStatus !== 0) ? 'send command' : 'set state', $(this).val()); $(this).val(''); } @@ -233,7 +233,7 @@ function updateServerPowerControls (data) { $(document).ready(function () { $('[data-attr="power"]').click(function (event) { if (! $(this).hasClass('disabled')) { - Socket.emit('set status', $(this).data('action')); + Socket.emit('set state', $(this).data('action')); } }); diff --git a/resources/assets/scripts/components/server/Server.vue b/resources/assets/scripts/components/server/Server.vue index db78a6bc3..30b66a345 100644 --- a/resources/assets/scripts/components/server/Server.vue +++ b/resources/assets/scripts/components/server/Server.vue @@ -34,6 +34,11 @@ Databases +
  • + + Networking + +
  • @@ -54,7 +59,6 @@ import Vue from 'vue'; import Navigation from '@/components/core/Navigation.vue'; import {mapState} from 'vuex'; - import * as io from 'socket.io-client'; import {Socketio} from "@/mixins/socketio"; import PowerButtons from "@/components/server/components/PowerButtons.vue"; import Flash from "@/components/Flash.vue"; @@ -105,13 +109,12 @@ this.$store.dispatch('server/getCredentials', {server: this.$route.params.id}) ]) .then(() => { - // Configure the socket.io implementation. This is a really ghetto way of handling things - // but all of these plugins assume you have some constant connection, which we don't. - const socket = io(`${this.credentials.node}/v1/ws/${this.server.uuid}`, { - query: `token=${this.credentials.key}`, - }); + // Configure the websocket implementation and assign it to the mixin. + this.$socket().connect( + `ws://192.168.50.3:8080/api/servers/${this.server.uuid}/ws`, + 'CC8kHCuMkXPosgzGO6d37wvhNcksWxG6kTrA', + ); - this.$socket().connect(socket); this.loadingServerData = false; }) .catch(err => { diff --git a/resources/assets/scripts/components/server/components/PowerButtons.vue b/resources/assets/scripts/components/server/components/PowerButtons.vue index 096925d83..131c332e4 100644 --- a/resources/assets/scripts/components/server/components/PowerButtons.vue +++ b/resources/assets/scripts/components/server/components/PowerButtons.vue @@ -3,7 +3,7 @@
    @@ -45,7 +45,7 @@ methods: { sendPowerAction: function (action: string) { - this.$socket().instance().emit('set status', action) + this.$socket().emit('set state', action) }, }, }); diff --git a/resources/assets/scripts/components/server/subpages/Console.vue b/resources/assets/scripts/components/server/subpages/Console.vue index 57c80514b..a833ba927 100644 --- a/resources/assets/scripts/components/server/subpages/Console.vue +++ b/resources/assets/scripts/components/server/subpages/Console.vue @@ -64,20 +64,12 @@ * Listen for specific socket.io emits from the server. */ sockets: { - 'server log': function (data: string) { - data.split(/\n/g).forEach((line: string): void => { - if (this.terminal) { - this.terminal.writeln(line + '\u001b[0m'); - } - }); + 'server log': function (lines: Array) { + lines.forEach(data => data.split(/\n/g).forEach(line => this.terminal && this.terminal.writeln(line + '\u001b[0m'))); }, - 'console': function (data: { line: string }) { - data.line.split(/\n/g).forEach((line: string): void => { - if (this.terminal) { - this.terminal.writeln(line + '\u001b[0m'); - } - }); + 'console output': function (line: string) { + this.terminal && this.terminal.writeln(line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m'); }, }, @@ -114,7 +106,7 @@ this.terminal.fit(); this.terminal.clear(); - this.$socket().instance().emit('send server log'); + this.$socket().emit('send logs'); }, /** @@ -123,7 +115,7 @@ sendCommand: function () { this.commandHistoryIndex = -1; this.commandHistory.unshift(this.command); - this.$socket().instance().emit('send command', this.command); + this.$socket().emit('send command', this.command); this.command = ''; }, diff --git a/resources/assets/scripts/helpers/statuses.ts b/resources/assets/scripts/helpers/statuses.ts index 7ed02f15a..662a3a6fb 100644 --- a/resources/assets/scripts/helpers/statuses.ts +++ b/resources/assets/scripts/helpers/statuses.ts @@ -1,6 +1,6 @@ export default { - STATUS_OFF: 0, - STATUS_ON: 1, - STATUS_STARTING: 2, - STATUS_STOPPING: 3, + STATUS_OFF: 'offline', + STATUS_ON: 'running', + STATUS_STARTING: 'starting', + STATUS_STOPPING: 'stopping', }; diff --git a/resources/assets/scripts/helpers/ziggy.js b/resources/assets/scripts/helpers/ziggy.js index 3c41949c4..8f8d46af2 100644 --- a/resources/assets/scripts/helpers/ziggy.js +++ b/resources/assets/scripts/helpers/ziggy.js @@ -1,5 +1,5 @@ var Ziggy = { - namedRoutes: JSON.parse('{"debugbar.openhandler":{"uri":"_debugbar\/open","methods":["GET","HEAD"],"domain":null},"debugbar.clockwork":{"uri":"_debugbar\/clockwork\/{id}","methods":["GET","HEAD"],"domain":null},"debugbar.assets.css":{"uri":"_debugbar\/assets\/stylesheets","methods":["GET","HEAD"],"domain":null},"debugbar.assets.js":{"uri":"_debugbar\/assets\/javascript","methods":["GET","HEAD"],"domain":null},"debugbar.cache.delete":{"uri":"_debugbar\/cache\/{key}\/{tags?}","methods":["DELETE"],"domain":null},"index":{"uri":"\/","methods":["GET","HEAD"],"domain":null},"account":{"uri":"account","methods":["GET","HEAD"],"domain":null},"account.api":{"uri":"account\/api","methods":["GET","HEAD"],"domain":null},"account.api.new":{"uri":"account\/api\/new","methods":["GET","HEAD"],"domain":null},"account.api.revoke":{"uri":"account\/api\/revoke\/{identifier}","methods":["DELETE"],"domain":null},"account.two_factor":{"uri":"account\/two_factor","methods":["GET","HEAD"],"domain":null},"account.two_factor.enable":{"uri":"account\/two_factor\/totp","methods":["POST"],"domain":null},"account.two_factor.disable":{"uri":"account\/two_factor\/totp\/disable","methods":["POST"],"domain":null},"admin.index":{"uri":"admin","methods":["GET","HEAD"],"domain":null},"admin.statistics":{"uri":"admin\/statistics","methods":["GET","HEAD"],"domain":null},"admin.api.index":{"uri":"admin\/api","methods":["GET","HEAD"],"domain":null},"admin.api.new":{"uri":"admin\/api\/new","methods":["GET","HEAD"],"domain":null},"admin.api.delete":{"uri":"admin\/api\/revoke\/{identifier}","methods":["DELETE"],"domain":null},"admin.locations":{"uri":"admin\/locations","methods":["GET","HEAD"],"domain":null},"admin.locations.view":{"uri":"admin\/locations\/view\/{location}","methods":["GET","HEAD"],"domain":null},"admin.databases":{"uri":"admin\/databases","methods":["GET","HEAD"],"domain":null},"admin.databases.view":{"uri":"admin\/databases\/view\/{host}","methods":["GET","HEAD"],"domain":null},"admin.settings":{"uri":"admin\/settings","methods":["GET","HEAD"],"domain":null},"admin.settings.mail":{"uri":"admin\/settings\/mail","methods":["GET","HEAD"],"domain":null},"admin.settings.mail.test":{"uri":"admin\/settings\/mail\/test","methods":["GET","HEAD"],"domain":null},"admin.settings.advanced":{"uri":"admin\/settings\/advanced","methods":["GET","HEAD"],"domain":null},"admin.users":{"uri":"admin\/users","methods":["GET","HEAD"],"domain":null},"admin.users.json":{"uri":"admin\/users\/accounts.json","methods":["GET","HEAD"],"domain":null},"admin.users.new":{"uri":"admin\/users\/new","methods":["GET","HEAD"],"domain":null},"admin.users.view":{"uri":"admin\/users\/view\/{user}","methods":["GET","HEAD"],"domain":null},"admin.servers":{"uri":"admin\/servers","methods":["GET","HEAD"],"domain":null},"admin.servers.new":{"uri":"admin\/servers\/new","methods":["GET","HEAD"],"domain":null},"admin.servers.view":{"uri":"admin\/servers\/view\/{server}","methods":["GET","HEAD"],"domain":null},"admin.servers.view.details":{"uri":"admin\/servers\/view\/{server}\/details","methods":["GET","HEAD"],"domain":null},"admin.servers.view.build":{"uri":"admin\/servers\/view\/{server}\/build","methods":["GET","HEAD"],"domain":null},"admin.servers.view.startup":{"uri":"admin\/servers\/view\/{server}\/startup","methods":["GET","HEAD"],"domain":null},"admin.servers.view.database":{"uri":"admin\/servers\/view\/{server}\/database","methods":["GET","HEAD"],"domain":null},"admin.servers.view.manage":{"uri":"admin\/servers\/view\/{server}\/manage","methods":["GET","HEAD"],"domain":null},"admin.servers.view.delete":{"uri":"admin\/servers\/view\/{server}\/delete","methods":["GET","HEAD"],"domain":null},"admin.servers.view.manage.toggle":{"uri":"admin\/servers\/view\/{server}\/manage\/toggle","methods":["POST"],"domain":null},"admin.servers.view.manage.rebuild":{"uri":"admin\/servers\/view\/{server}\/manage\/rebuild","methods":["POST"],"domain":null},"admin.servers.view.manage.suspension":{"uri":"admin\/servers\/view\/{server}\/manage\/suspension","methods":["POST"],"domain":null},"admin.servers.view.manage.reinstall":{"uri":"admin\/servers\/view\/{server}\/manage\/reinstall","methods":["POST"],"domain":null},"admin.servers.view.database.delete":{"uri":"admin\/servers\/view\/{server}\/database\/{database}\/delete","methods":["DELETE"],"domain":null},"admin.nodes":{"uri":"admin\/nodes","methods":["GET","HEAD"],"domain":null},"admin.nodes.new":{"uri":"admin\/nodes\/new","methods":["GET","HEAD"],"domain":null},"admin.nodes.view":{"uri":"admin\/nodes\/view\/{node}","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.settings":{"uri":"admin\/nodes\/view\/{node}\/settings","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.configuration":{"uri":"admin\/nodes\/view\/{node}\/configuration","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.allocation":{"uri":"admin\/nodes\/view\/{node}\/allocation","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.servers":{"uri":"admin\/nodes\/view\/{node}\/servers","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.configuration.token":{"uri":"admin\/nodes\/view\/{node}\/settings\/token","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.allocation.removeBlock":{"uri":"admin\/nodes\/view\/{node}\/allocation\/remove","methods":["POST"],"domain":null},"admin.nodes.view.allocation.setAlias":{"uri":"admin\/nodes\/view\/{node}\/allocation\/alias","methods":["POST"],"domain":null},"admin.nodes.view.delete":{"uri":"admin\/nodes\/view\/{node}\/delete","methods":["DELETE"],"domain":null},"admin.nodes.view.allocation.removeSingle":{"uri":"admin\/nodes\/view\/{node}\/allocation\/remove\/{allocation}","methods":["DELETE"],"domain":null},"admin.nodes.view.allocation.removeMultiple":{"uri":"admin\/nodes\/view\/{node}\/allocations","methods":["DELETE"],"domain":null},"admin.nests":{"uri":"admin\/nests","methods":["GET","HEAD"],"domain":null},"admin.nests.new":{"uri":"admin\/nests\/new","methods":["GET","HEAD"],"domain":null},"admin.nests.view":{"uri":"admin\/nests\/view\/{nest}","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.new":{"uri":"admin\/nests\/egg\/new","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.view":{"uri":"admin\/nests\/egg\/{egg}","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.export":{"uri":"admin\/nests\/egg\/{egg}\/export","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.variables":{"uri":"admin\/nests\/egg\/{egg}\/variables","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.scripts":{"uri":"admin\/nests\/egg\/{egg}\/scripts","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.import":{"uri":"admin\/nests\/import","methods":["POST"],"domain":null},"admin.nests.egg.variables.edit":{"uri":"admin\/nests\/egg\/{egg}\/variables\/{variable}","methods":["PATCH"],"domain":null},"admin.packs":{"uri":"admin\/packs","methods":["GET","HEAD"],"domain":null},"admin.packs.new":{"uri":"admin\/packs\/new","methods":["GET","HEAD"],"domain":null},"admin.packs.new.template":{"uri":"admin\/packs\/new\/template","methods":["GET","HEAD"],"domain":null},"admin.packs.view":{"uri":"admin\/packs\/view\/{pack}","methods":["GET","HEAD"],"domain":null},"admin.packs.view.export":{"uri":"admin\/packs\/view\/{pack}\/export\/{files?}","methods":["POST"],"domain":null},"auth.login":{"uri":"auth\/login","methods":["GET","HEAD"],"domain":null},"auth.forgot-password":{"uri":"auth\/password","methods":["GET","HEAD"],"domain":null},"auth.reset":{"uri":"auth\/password\/reset\/{token}","methods":["GET","HEAD"],"domain":null},"auth.login-checkpoint":{"uri":"auth\/login\/checkpoint","methods":["POST"],"domain":null},"auth.reset-password":{"uri":"auth\/password\/reset","methods":["POST"],"domain":null},"auth.logout":{"uri":"auth\/logout","methods":["GET","HEAD"],"domain":null},"server.credentials":{"uri":"api\/server\/{server}\/credentials","methods":["GET","HEAD"],"domain":null},"server.files":{"uri":"api\/server\/{server}\/files\/{directory?}","methods":["GET","HEAD"],"domain":null},"server.index":{"uri":"api\/server\/{server}","methods":["GET","HEAD"],"domain":null},"server.console":{"uri":"api\/server\/{server}\/console","methods":["GET","HEAD"],"domain":null},"api.application.users":{"uri":"api\/application\/users","methods":["GET","HEAD"],"domain":null},"api.application.users.view":{"uri":"api\/application\/users\/{user}","methods":["GET","HEAD"],"domain":null},"api.application.users.external":{"uri":"api\/application\/users\/external\/{external_id}","methods":["GET","HEAD"],"domain":null},"api.application.nodes":{"uri":"api\/application\/nodes","methods":["GET","HEAD"],"domain":null},"api.application.nodes.view":{"uri":"api\/application\/nodes\/{node}","methods":["GET","HEAD"],"domain":null},"api.application.allocations":{"uri":"api\/application\/nodes\/{node}\/allocations","methods":["GET","HEAD"],"domain":null},"api.application.allocations.view":{"uri":"api\/application\/nodes\/{node}\/allocations\/{allocation}","methods":["DELETE"],"domain":null},"api.applications.locations":{"uri":"api\/application\/locations","methods":["GET","HEAD"],"domain":null},"api.application.locations.view":{"uri":"api\/application\/locations\/{location}","methods":["GET","HEAD"],"domain":null},"api.application.servers":{"uri":"api\/application\/servers","methods":["GET","HEAD"],"domain":null},"api.application.servers.view":{"uri":"api\/application\/servers\/{server}","methods":["GET","HEAD"],"domain":null},"api.application.servers.external":{"uri":"api\/application\/servers\/external\/{external_id}","methods":["GET","HEAD"],"domain":null},"api.application.servers.details":{"uri":"api\/application\/servers\/{server}\/details","methods":["PATCH"],"domain":null},"api.application.servers.build":{"uri":"api\/application\/servers\/{server}\/build","methods":["PATCH"],"domain":null},"api.application.servers.startup":{"uri":"api\/application\/servers\/{server}\/startup","methods":["PATCH"],"domain":null},"api.application.servers.suspend":{"uri":"api\/application\/servers\/{server}\/suspend","methods":["POST"],"domain":null},"api.application.servers.unsuspend":{"uri":"api\/application\/servers\/{server}\/unsuspend","methods":["POST"],"domain":null},"api.application.servers.reinstall":{"uri":"api\/application\/servers\/{server}\/reinstall","methods":["POST"],"domain":null},"api.application.servers.rebuild":{"uri":"api\/application\/servers\/{server}\/rebuild","methods":["POST"],"domain":null},"api.application.servers.databases":{"uri":"api\/application\/servers\/{server}\/databases","methods":["GET","HEAD"],"domain":null},"api.application.servers.databases.view":{"uri":"api\/application\/servers\/{server}\/databases\/{database}","methods":["GET","HEAD"],"domain":null},"api.application.nests":{"uri":"api\/application\/nests","methods":["GET","HEAD"],"domain":null},"api.application.nests.view":{"uri":"api\/application\/nests\/{nest}","methods":["GET","HEAD"],"domain":null},"api.application.nests.eggs":{"uri":"api\/application\/nests\/{nest}\/eggs","methods":["GET","HEAD"],"domain":null},"api.application.nests.eggs.view":{"uri":"api\/application\/nests\/{nest}\/eggs\/{egg}","methods":["GET","HEAD"],"domain":null},"api.client.index":{"uri":"api\/client","methods":["GET","HEAD"],"domain":null},"api.client.account":{"uri":"api\/client\/account","methods":["GET","HEAD"],"domain":null},"api.client.account.update-email":{"uri":"api\/client\/account\/email","methods":["PUT"],"domain":null},"api.client.account.update-password":{"uri":"api\/client\/account\/password","methods":["PUT"],"domain":null},"api.client.servers.view":{"uri":"api\/client\/servers\/{server}","methods":["GET","HEAD"],"domain":null},"api.client.servers.resources":{"uri":"api\/client\/servers\/{server}\/utilization","methods":["GET","HEAD"],"domain":null},"api.client.servers.command":{"uri":"api\/client\/servers\/{server}\/command","methods":["POST"],"domain":null},"api.client.servers.power":{"uri":"api\/client\/servers\/{server}\/power","methods":["POST"],"domain":null},"api.client.servers.databases":{"uri":"api\/client\/servers\/{server}\/databases","methods":["GET","HEAD"],"domain":null},"api.client.servers.databases.delete":{"uri":"api\/client\/servers\/{server}\/databases\/{database}","methods":["DELETE"],"domain":null},"api.client.servers.files.download":{"uri":"api\/client\/servers\/{server}\/files\/download\/{file}","methods":["POST"],"domain":null},"api.remote.authenticate":{"uri":"api\/remote\/authenticate\/{token}","methods":["GET","HEAD"],"domain":null},"api.remote.download_file":{"uri":"api\/remote\/download-file","methods":["POST"],"domain":null},"api.remote.eggs":{"uri":"api\/remote\/eggs","methods":["GET","HEAD"],"domain":null},"api.remote.eggs.download":{"uri":"api\/remote\/eggs\/{uuid}","methods":["GET","HEAD"],"domain":null},"api.remote.scripts":{"uri":"api\/remote\/scripts\/{uuid}","methods":["GET","HEAD"],"domain":null},"api.remote.sftp":{"uri":"api\/remote\/sftp","methods":["POST"],"domain":null},"daemon.pack.pull":{"uri":"daemon\/packs\/pull\/{uuid}","methods":["GET","HEAD"],"domain":null},"daemon.pack.hash":{"uri":"daemon\/packs\/pull\/{uuid}\/hash","methods":["GET","HEAD"],"domain":null},"daemon.configuration":{"uri":"daemon\/configure\/{token}","methods":["GET","HEAD"],"domain":null},"daemon.install":{"uri":"daemon\/install","methods":["POST"],"domain":null}}'), + namedRoutes: JSON.parse('{"debugbar.openhandler":{"uri":"_debugbar\/open","methods":["GET","HEAD"],"domain":null},"debugbar.clockwork":{"uri":"_debugbar\/clockwork\/{id}","methods":["GET","HEAD"],"domain":null},"debugbar.assets.css":{"uri":"_debugbar\/assets\/stylesheets","methods":["GET","HEAD"],"domain":null},"debugbar.assets.js":{"uri":"_debugbar\/assets\/javascript","methods":["GET","HEAD"],"domain":null},"debugbar.cache.delete":{"uri":"_debugbar\/cache\/{key}\/{tags?}","methods":["DELETE"],"domain":null},"index":{"uri":"\/","methods":["GET","HEAD"],"domain":null},"account":{"uri":"account","methods":["GET","HEAD"],"domain":null},"account.api":{"uri":"account\/api","methods":["GET","HEAD"],"domain":null},"account.api.new":{"uri":"account\/api\/new","methods":["GET","HEAD"],"domain":null},"account.api.revoke":{"uri":"account\/api\/revoke\/{identifier}","methods":["DELETE"],"domain":null},"account.two_factor":{"uri":"account\/two_factor","methods":["GET","HEAD"],"domain":null},"account.two_factor.enable":{"uri":"account\/two_factor\/totp","methods":["POST"],"domain":null},"account.two_factor.disable":{"uri":"account\/two_factor\/totp\/disable","methods":["POST"],"domain":null},"admin.index":{"uri":"admin","methods":["GET","HEAD"],"domain":null},"admin.statistics":{"uri":"admin\/statistics","methods":["GET","HEAD"],"domain":null},"admin.api.index":{"uri":"admin\/api","methods":["GET","HEAD"],"domain":null},"admin.api.new":{"uri":"admin\/api\/new","methods":["GET","HEAD"],"domain":null},"admin.api.delete":{"uri":"admin\/api\/revoke\/{identifier}","methods":["DELETE"],"domain":null},"admin.locations":{"uri":"admin\/locations","methods":["GET","HEAD"],"domain":null},"admin.locations.view":{"uri":"admin\/locations\/view\/{location}","methods":["GET","HEAD"],"domain":null},"admin.databases":{"uri":"admin\/databases","methods":["GET","HEAD"],"domain":null},"admin.databases.view":{"uri":"admin\/databases\/view\/{host}","methods":["GET","HEAD"],"domain":null},"admin.settings":{"uri":"admin\/settings","methods":["GET","HEAD"],"domain":null},"admin.settings.mail":{"uri":"admin\/settings\/mail","methods":["GET","HEAD"],"domain":null},"admin.settings.mail.test":{"uri":"admin\/settings\/mail\/test","methods":["GET","HEAD"],"domain":null},"admin.settings.advanced":{"uri":"admin\/settings\/advanced","methods":["GET","HEAD"],"domain":null},"admin.users":{"uri":"admin\/users","methods":["GET","HEAD"],"domain":null},"admin.users.json":{"uri":"admin\/users\/accounts.json","methods":["GET","HEAD"],"domain":null},"admin.users.new":{"uri":"admin\/users\/new","methods":["GET","HEAD"],"domain":null},"admin.users.view":{"uri":"admin\/users\/view\/{user}","methods":["GET","HEAD"],"domain":null},"admin.servers":{"uri":"admin\/servers","methods":["GET","HEAD"],"domain":null},"admin.servers.new":{"uri":"admin\/servers\/new","methods":["GET","HEAD"],"domain":null},"admin.servers.view":{"uri":"admin\/servers\/view\/{server}","methods":["GET","HEAD"],"domain":null},"admin.servers.view.details":{"uri":"admin\/servers\/view\/{server}\/details","methods":["GET","HEAD"],"domain":null},"admin.servers.view.build":{"uri":"admin\/servers\/view\/{server}\/build","methods":["GET","HEAD"],"domain":null},"admin.servers.view.startup":{"uri":"admin\/servers\/view\/{server}\/startup","methods":["GET","HEAD"],"domain":null},"admin.servers.view.database":{"uri":"admin\/servers\/view\/{server}\/database","methods":["GET","HEAD"],"domain":null},"admin.servers.view.manage":{"uri":"admin\/servers\/view\/{server}\/manage","methods":["GET","HEAD"],"domain":null},"admin.servers.view.delete":{"uri":"admin\/servers\/view\/{server}\/delete","methods":["GET","HEAD"],"domain":null},"admin.servers.view.manage.toggle":{"uri":"admin\/servers\/view\/{server}\/manage\/toggle","methods":["POST"],"domain":null},"admin.servers.view.manage.rebuild":{"uri":"admin\/servers\/view\/{server}\/manage\/rebuild","methods":["POST"],"domain":null},"admin.servers.view.manage.suspension":{"uri":"admin\/servers\/view\/{server}\/manage\/suspension","methods":["POST"],"domain":null},"admin.servers.view.manage.reinstall":{"uri":"admin\/servers\/view\/{server}\/manage\/reinstall","methods":["POST"],"domain":null},"admin.servers.view.database.delete":{"uri":"admin\/servers\/view\/{server}\/database\/{database}\/delete","methods":["DELETE"],"domain":null},"admin.nodes":{"uri":"admin\/nodes","methods":["GET","HEAD"],"domain":null},"admin.nodes.new":{"uri":"admin\/nodes\/new","methods":["GET","HEAD"],"domain":null},"admin.nodes.view":{"uri":"admin\/nodes\/view\/{node}","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.settings":{"uri":"admin\/nodes\/view\/{node}\/settings","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.configuration":{"uri":"admin\/nodes\/view\/{node}\/configuration","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.allocation":{"uri":"admin\/nodes\/view\/{node}\/allocation","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.servers":{"uri":"admin\/nodes\/view\/{node}\/servers","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.configuration.token":{"uri":"admin\/nodes\/view\/{node}\/settings\/token","methods":["GET","HEAD"],"domain":null},"admin.nodes.view.allocation.removeBlock":{"uri":"admin\/nodes\/view\/{node}\/allocation\/remove","methods":["POST"],"domain":null},"admin.nodes.view.allocation.setAlias":{"uri":"admin\/nodes\/view\/{node}\/allocation\/alias","methods":["POST"],"domain":null},"admin.nodes.view.delete":{"uri":"admin\/nodes\/view\/{node}\/delete","methods":["DELETE"],"domain":null},"admin.nodes.view.allocation.removeSingle":{"uri":"admin\/nodes\/view\/{node}\/allocation\/remove\/{allocation}","methods":["DELETE"],"domain":null},"admin.nodes.view.allocation.removeMultiple":{"uri":"admin\/nodes\/view\/{node}\/allocations","methods":["DELETE"],"domain":null},"admin.nests":{"uri":"admin\/nests","methods":["GET","HEAD"],"domain":null},"admin.nests.new":{"uri":"admin\/nests\/new","methods":["GET","HEAD"],"domain":null},"admin.nests.view":{"uri":"admin\/nests\/view\/{nest}","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.new":{"uri":"admin\/nests\/egg\/new","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.view":{"uri":"admin\/nests\/egg\/{egg}","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.export":{"uri":"admin\/nests\/egg\/{egg}\/export","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.variables":{"uri":"admin\/nests\/egg\/{egg}\/variables","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.scripts":{"uri":"admin\/nests\/egg\/{egg}\/scripts","methods":["GET","HEAD"],"domain":null},"admin.nests.egg.import":{"uri":"admin\/nests\/import","methods":["POST"],"domain":null},"admin.nests.egg.variables.edit":{"uri":"admin\/nests\/egg\/{egg}\/variables\/{variable}","methods":["PATCH"],"domain":null},"admin.packs":{"uri":"admin\/packs","methods":["GET","HEAD"],"domain":null},"admin.packs.new":{"uri":"admin\/packs\/new","methods":["GET","HEAD"],"domain":null},"admin.packs.new.template":{"uri":"admin\/packs\/new\/template","methods":["GET","HEAD"],"domain":null},"admin.packs.view":{"uri":"admin\/packs\/view\/{pack}","methods":["GET","HEAD"],"domain":null},"admin.packs.view.export":{"uri":"admin\/packs\/view\/{pack}\/export\/{files?}","methods":["POST"],"domain":null},"auth.login":{"uri":"auth\/login","methods":["GET","HEAD"],"domain":null},"auth.forgot-password":{"uri":"auth\/password","methods":["GET","HEAD"],"domain":null},"auth.reset":{"uri":"auth\/password\/reset\/{token}","methods":["GET","HEAD"],"domain":null},"auth.login-checkpoint":{"uri":"auth\/login\/checkpoint","methods":["POST"],"domain":null},"auth.reset-password":{"uri":"auth\/password\/reset","methods":["POST"],"domain":null},"auth.logout":{"uri":"auth\/logout","methods":["GET","HEAD"],"domain":null},"server.credentials":{"uri":"api\/server\/{server}\/credentials","methods":["GET","HEAD"],"domain":null},"server.files":{"uri":"api\/server\/{server}\/files\/{directory?}","methods":["GET","HEAD"],"domain":null},"server.index":{"uri":"api\/server\/{server}","methods":["GET","HEAD"],"domain":null},"server.console":{"uri":"api\/server\/{server}\/console","methods":["GET","HEAD"],"domain":null},"api.application.users":{"uri":"api\/application\/users","methods":["GET","HEAD"],"domain":null},"api.application.users.view":{"uri":"api\/application\/users\/{user}","methods":["GET","HEAD"],"domain":null},"api.application.users.external":{"uri":"api\/application\/users\/external\/{external_id}","methods":["GET","HEAD"],"domain":null},"api.application.nodes":{"uri":"api\/application\/nodes","methods":["GET","HEAD"],"domain":null},"api.application.nodes.view":{"uri":"api\/application\/nodes\/{node}","methods":["GET","HEAD"],"domain":null},"api.application.allocations":{"uri":"api\/application\/nodes\/{node}\/allocations","methods":["GET","HEAD"],"domain":null},"api.application.allocations.view":{"uri":"api\/application\/nodes\/{node}\/allocations\/{allocation}","methods":["DELETE"],"domain":null},"api.applications.locations":{"uri":"api\/application\/locations","methods":["GET","HEAD"],"domain":null},"api.application.locations.view":{"uri":"api\/application\/locations\/{location}","methods":["GET","HEAD"],"domain":null},"api.application.servers":{"uri":"api\/application\/servers","methods":["GET","HEAD"],"domain":null},"api.application.servers.view":{"uri":"api\/application\/servers\/{server}","methods":["GET","HEAD"],"domain":null},"api.application.servers.external":{"uri":"api\/application\/servers\/external\/{external_id}","methods":["GET","HEAD"],"domain":null},"api.application.servers.details":{"uri":"api\/application\/servers\/{server}\/details","methods":["PATCH"],"domain":null},"api.application.servers.build":{"uri":"api\/application\/servers\/{server}\/build","methods":["PATCH"],"domain":null},"api.application.servers.startup":{"uri":"api\/application\/servers\/{server}\/startup","methods":["PATCH"],"domain":null},"api.application.servers.suspend":{"uri":"api\/application\/servers\/{server}\/suspend","methods":["POST"],"domain":null},"api.application.servers.unsuspend":{"uri":"api\/application\/servers\/{server}\/unsuspend","methods":["POST"],"domain":null},"api.application.servers.reinstall":{"uri":"api\/application\/servers\/{server}\/reinstall","methods":["POST"],"domain":null},"api.application.servers.rebuild":{"uri":"api\/application\/servers\/{server}\/rebuild","methods":["POST"],"domain":null},"api.application.servers.databases":{"uri":"api\/application\/servers\/{server}\/databases","methods":["GET","HEAD"],"domain":null},"api.application.servers.databases.view":{"uri":"api\/application\/servers\/{server}\/databases\/{database}","methods":["GET","HEAD"],"domain":null},"api.application.nests":{"uri":"api\/application\/nests","methods":["GET","HEAD"],"domain":null},"api.application.nests.view":{"uri":"api\/application\/nests\/{nest}","methods":["GET","HEAD"],"domain":null},"api.application.nests.eggs":{"uri":"api\/application\/nests\/{nest}\/eggs","methods":["GET","HEAD"],"domain":null},"api.application.nests.eggs.view":{"uri":"api\/application\/nests\/{nest}\/eggs\/{egg}","methods":["GET","HEAD"],"domain":null},"api.client.index":{"uri":"api\/client","methods":["GET","HEAD"],"domain":null},"api.client.account":{"uri":"api\/client\/account","methods":["GET","HEAD"],"domain":null},"api.client.account.update-email":{"uri":"api\/client\/account\/email","methods":["PUT"],"domain":null},"api.client.account.update-password":{"uri":"api\/client\/account\/password","methods":["PUT"],"domain":null},"api.client.servers.view":{"uri":"api\/client\/servers\/{server}","methods":["GET","HEAD"],"domain":null},"api.client.servers.resources":{"uri":"api\/client\/servers\/{server}\/utilization","methods":["GET","HEAD"],"domain":null},"api.client.servers.command":{"uri":"api\/client\/servers\/{server}\/command","methods":["POST"],"domain":null},"api.client.servers.power":{"uri":"api\/client\/servers\/{server}\/power","methods":["POST"],"domain":null},"api.client.servers.databases":{"uri":"api\/client\/servers\/{server}\/databases","methods":["GET","HEAD"],"domain":null},"api.client.servers.databases.delete":{"uri":"api\/client\/servers\/{server}\/databases\/{database}","methods":["DELETE"],"domain":null},"api.client.servers.files.download":{"uri":"api\/client\/servers\/{server}\/files\/download\/{file}","methods":["POST"],"domain":null},"api.client.servers.network":{"uri":"api\/client\/servers\/{server}\/network","methods":["GET","HEAD"],"domain":null},"api.remote.authenticate":{"uri":"api\/remote\/authenticate\/{token}","methods":["GET","HEAD"],"domain":null},"api.remote.download_file":{"uri":"api\/remote\/download-file","methods":["POST"],"domain":null},"api.remote.eggs":{"uri":"api\/remote\/eggs","methods":["GET","HEAD"],"domain":null},"api.remote.eggs.download":{"uri":"api\/remote\/eggs\/{uuid}","methods":["GET","HEAD"],"domain":null},"api.remote.scripts":{"uri":"api\/remote\/scripts\/{uuid}","methods":["GET","HEAD"],"domain":null},"api.remote.sftp":{"uri":"api\/remote\/sftp","methods":["POST"],"domain":null},"daemon.pack.pull":{"uri":"daemon\/packs\/pull\/{uuid}","methods":["GET","HEAD"],"domain":null},"daemon.pack.hash":{"uri":"daemon\/packs\/pull\/{uuid}\/hash","methods":["GET","HEAD"],"domain":null},"daemon.configuration":{"uri":"daemon\/configure\/{token}","methods":["GET","HEAD"],"domain":null},"daemon.install":{"uri":"daemon\/install","methods":["POST"],"domain":null}}'), baseUrl: 'http://pterodactyl.test/', baseProtocol: 'http', baseDomain: 'pterodactyl.test', diff --git a/resources/assets/scripts/mixins/socketio/connector.ts b/resources/assets/scripts/mixins/socketio/connector.ts index 97aee0a5f..a46a28151 100644 --- a/resources/assets/scripts/mixins/socketio/connector.ts +++ b/resources/assets/scripts/mixins/socketio/connector.ts @@ -1,29 +1,23 @@ -import * as io from 'socket.io-client'; import {camelCase} from 'lodash'; import SocketEmitter from './emitter'; import {Store} from "vuex"; -const SYSTEM_EVENTS: Array = [ - 'connect', - 'error', - 'disconnect', - 'reconnect', - 'reconnect_attempt', - 'reconnecting', - 'reconnect_error', - 'reconnect_failed', - 'connect_error', - 'connect_timeout', - 'connecting', - 'ping', - 'pong', -]; +const SOCKET_CONNECT = 'connect'; +const SOCKET_ERROR = 'error'; +const SOCKET_DISCONNECT = 'disconnect'; + +// This is defined in the wings daemon code and referenced here so that it is obvious +// where we are pulling these random data objects from. +type WingsWebsocketResponse = { + event: string, + args: Array +} export default class SocketioConnector { /** * The socket instance. */ - socket: null | SocketIOClient.Socket; + socket: null | WebSocket; /** * The vuex store being used to persist data and socket state. @@ -37,21 +31,33 @@ export default class SocketioConnector { /** * Initialize a new Socket connection. - * - * @param {io} socket */ - connect(socket: SocketIOClient.Socket) { - this.socket = socket; + connect(url: string, protocols?: string | string[]): void { + this.socket = new WebSocket(url, protocols); this.registerEventListeners(); } /** * Return the socket instance we are working with. */ - instance(): SocketIOClient.Socket | null { + instance(): WebSocket | null { return this.socket; } + /** + * Sends an event along to the websocket. If there is no active connection, a void + * result is returned. + */ + emit(event: string, payload?: string | Array): void | false { + if (!this.socket) { + return false + } + + this.socket.send(JSON.stringify({ + event, args: typeof payload === 'string' ? [payload] : payload + })); + } + /** * Register the event listeners for this socket including user-defined ones in the store as * well as global system events from Socekt.io. @@ -61,55 +67,66 @@ export default class SocketioConnector { return; } - // @ts-ignore - this.socket['onevent'] = (packet: { data: Array }): void => { - const [event, ...args] = packet.data; - SocketEmitter.emit(event, ...args); - - this.passToStore(event, args); + this.socket.onopen = () => this.emitAndPassToStore(SOCKET_CONNECT); + this.socket.onclose = () => this.emitAndPassToStore(SOCKET_DISCONNECT); + this.socket.onerror = () => { + // @todo reconnect? + if (this.socket && this.socket.readyState !== 1) { + this.emitAndPassToStore(SOCKET_ERROR, ['Failed to connect to websocket.']); + } }; - SYSTEM_EVENTS.forEach((event: string): void => { - if (!this.socket) { - return; + this.socket.onmessage = (wse): void => { + console.log('Socket message:', wse.data); + + try { + let {event, args}: WingsWebsocketResponse = JSON.parse(wse.data); + + this.emitAndPassToStore(event, args); + } catch (ex) { + // do nothing, bad JSON response + console.error(ex); + return } + }; + } - this.socket.on(event, (payload: any) => { - SocketEmitter.emit(event, payload); - - this.passToStore(event, payload); - }); - }); + /** + * Emits the event over the event emitter and also passes it along to the vuex store. + */ + emitAndPassToStore(event: string, payload?: Array) { + payload ? SocketEmitter.emit(event, ...payload) : SocketEmitter.emit(event); + this.passToStore(event, payload); } /** * Pass event calls off to the Vuex store if there is a corresponding function. */ - passToStore(event: string | number, payload: Array) { + passToStore(event: string, payload?: Array) { if (!this.store) { return; } const s: Store = this.store; - const mutation = `SOCKET_${String(event).toUpperCase()}`; - const action = `socket_${camelCase(String(event))}`; + const mutation = `SOCKET_${event.toUpperCase()}`; + const action = `socket_${camelCase(event)}`; // @ts-ignore Object.keys(this.store._mutations).filter((namespaced: string): boolean => { return namespaced.split('/').pop() === mutation; }).forEach((namespaced: string): void => { - s.commit(namespaced, this.unwrap(payload)); + s.commit(namespaced, payload ? this.unwrap(payload) : null); }); // @ts-ignore Object.keys(this.store._actions).filter((namespaced: string): boolean => { return namespaced.split('/').pop() === action; }).forEach((namespaced: string): void => { - s.dispatch(namespaced, this.unwrap(payload)).catch(console.error); + s.dispatch(namespaced, payload ? this.unwrap(payload) : null).catch(console.error); }); } - unwrap(args: Array) { + unwrap(args: Array) { return (args && args.length <= 1) ? args[0] : args; } } diff --git a/resources/assets/scripts/mixins/socketio/index.ts b/resources/assets/scripts/mixins/socketio/index.ts index 3f03d6966..118bccf95 100644 --- a/resources/assets/scripts/mixins/socketio/index.ts +++ b/resources/assets/scripts/mixins/socketio/index.ts @@ -34,10 +34,7 @@ export const Socketio: ComponentOptions = { }, methods: { - /** - * @return {SocketioConnector} - */ - '$socket': function () { + '$socket': function (): SocketioConnector | null { return connector; }, @@ -49,7 +46,7 @@ export const Socketio: ComponentOptions = { return; } - const instance: SocketIOClient.Socket | null = connector.instance(); + const instance = connector.instance(); if (instance) { instance.close(); } diff --git a/resources/assets/scripts/store/modules/socket.ts b/resources/assets/scripts/store/modules/socket.ts index 0d97f4585..ba74296d4 100644 --- a/resources/assets/scripts/store/modules/socket.ts +++ b/resources/assets/scripts/store/modules/socket.ts @@ -19,17 +19,12 @@ export default { state.connectionError = err; }, - SOCKET_CONNECT_ERROR: (state: SocketState, err: Error) => { - state.connected = false; - state.connectionError = err; + 'SOCKET_INITIAL STATUS': (state: SocketState, data: string) => { + state.status = data; }, - 'SOCKET_INITIAL STATUS': (state: SocketState, data: { status: number }) => { - state.status = data.status; - }, - - SOCKET_STATUS: (state: SocketState, data: { status: number }) => { - state.status = data.status; + SOCKET_STATUS: (state: SocketState, data: string) => { + state.status = data; } }, }; diff --git a/resources/assets/scripts/store/types.ts b/resources/assets/scripts/store/types.ts index 01049f60d..f4f5ddfd2 100644 --- a/resources/assets/scripts/store/types.ts +++ b/resources/assets/scripts/store/types.ts @@ -11,7 +11,7 @@ export type ApplicationState = { export type SocketState = { connected: boolean, connectionError: boolean | Error, - status: number, + status: string, } export type ServerApplicationCredentials = { diff --git a/yarn.lock b/yarn.lock index 6f7fb2bb6..f4d342c6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1379,9 +1379,9 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" -blob@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" bluebird@^3.1.1, bluebird@^3.5.3: version "3.5.3" @@ -2607,9 +2607,9 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -engine.io-client@~3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2619,18 +2619,18 @@ engine.io-client@~3.2.0: indexof "0.0.1" parseqs "0.0.5" parseuri "0.0.5" - ws "~3.3.1" + ws "~6.1.0" xmlhttprequest-ssl "~1.5.4" yeast "0.1.2" engine.io-parser@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" base64-arraybuffer "0.1.5" - blob "0.0.4" + blob "0.0.5" has-binary2 "~1.0.2" enhanced-resolve@^3.4.0: @@ -2809,7 +2809,7 @@ event-emitter@~0.3.5: d "1" es5-ext "~0.10.14" -eventemitter3@^3.0.0: +"eventemitter3@>=2 <4", eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -6299,28 +6299,28 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socket.io-client@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" +socket.io-client@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" component-bind "1.0.0" component-emitter "1.2.1" debug "~3.1.0" - engine.io-client "~3.2.0" + engine.io-client "~3.3.1" has-binary2 "~1.0.2" has-cors "1.1.0" indexof "0.0.1" object-component "0.0.3" parseqs "0.0.5" parseuri "0.0.5" - socket.io-parser "~3.2.0" + socket.io-parser "~3.3.0" to-array "0.1.4" -socket.io-parser@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" dependencies: component-emitter "1.2.1" debug "~3.1.0" @@ -6870,10 +6870,6 @@ uglifyjs-webpack-plugin@^2.1.1: webpack-sources "^1.1.0" worker-farm "^1.5.2" -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - unicode-canonical-property-names-ecmascript@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.3.tgz#f6119f417467593c0086357c85546b6ad5abc583" @@ -7445,13 +7441,17 @@ write-file-stdout@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1" -ws@~3.3.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" +ws-wrapper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ws-wrapper/-/ws-wrapper-2.0.0.tgz#598f67a9fdf13d532abaf593d8ce8889f94b5a2a" + dependencies: + eventemitter3 ">=2 <4" + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" dependencies: async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" xmlhttprequest-ssl@~1.5.4: version "1.5.5"