Skip to content

Commit 38d7985

Browse files
committed
More socket and console improvements for server
1 parent f866ad5 commit 38d7985

File tree

7 files changed

+169
-76
lines changed

7 files changed

+169
-76
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"vue": "^2.5.7",
99
"vue-axios": "^2.1.1",
1010
"vue-router": "^3.0.1",
11+
"vue-socket.io-extended": "^3.1.0",
1112
"vuex": "^3.0.1",
1213
"vuex-i18n": "^1.10.5",
1314
"vuex-router-sync": "^5.0.0",

resources/assets/scripts/components/server/Server.vue

Lines changed: 15 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -67,34 +67,30 @@
6767
import Navigation from '../core/Navigation';
6868
import ProgressBar from './components/ProgressBar';
6969
import {mapState} from 'vuex';
70-
70+
import { mapState } from 'vuex';
71+
import VueSocketio from 'vue-socket.io-extended';
7172
import io from 'socket.io-client';
73+
import Vue from 'vue';
74+
75+
import PowerButtons from './components/PowerButtons';
7276
7377
export default {
7478
components: {
75-
ProgressBar, Navigation, TerminalIcon, FolderIcon, UsersIcon,
76-
CalendarIcon, DatabaseIcon, GlobeIcon, SettingsIcon
79+
PowerButtons, ProgressBar, Navigation,
80+
TerminalIcon, FolderIcon, UsersIcon, CalendarIcon, DatabaseIcon, GlobeIcon, SettingsIcon
7781
},
7882
7983
computed: {
8084
...mapState('server', ['server', 'credentials']),
85+
...mapState('socket', ['connected', 'connectionError']),
8186
},
8287
8388
mounted: function () {
8489
this.loadServer();
85-
86-
this.$on('send-command', data => {
87-
this.socket.emit('send command', data);
88-
});
89-
90-
this.$on('send-initial-log', () => {
91-
this.socket.emit('send server log');
92-
})
9390
},
9491
9592
data: function () {
9693
return {
97-
socket: null,
9894
loadingServerData: true,
9995
};
10096
},
@@ -109,50 +105,17 @@
109105
this.$store.dispatch('server/getCredentials', {server: this.$route.params.id})
110106
])
111107
.then(() => {
108+
// Configure the socket.io implementation. This is a really ghetto way of handling things
109+
// but all of these plugins assume you have some constant connection, which we don't.
110+
const socket = io(`${this.credentials.node}/v1/ws/${this.server.uuid}`, {
111+
query: `token=${this.credentials.key}`,
112+
});
113+
114+
Vue.use(VueSocketio, socket, { store: this.$store });
112115
this.loadingServerData = false;
113-
this.initalizeWebsocket();
114116
})
115117
.catch(console.error);
116118
},
117-
118-
initalizeWebsocket: function () {
119-
this.socket = io(this.credentials.node + '/v1/ws/' + this.server.uuid, {
120-
query: 'token=' + this.credentials.key,
121-
});
122-
123-
this.socket.on('error', this._socket_error);
124-
this.socket.on('connect', this._socket_connect);
125-
this.socket.on('status', this._socket_status);
126-
this.socket.on('initial status', this._socket_status);
127-
this.socket.on('server log', this._socket_serverLog);
128-
this.socket.on('console', this._socket_consoleLine);
129-
},
130-
131-
_socket_error: function (err) {
132-
this.$emit('socket::error', {err});
133-
},
134-
135-
_socket_connect: function () {
136-
this.$emit('socket::connected');
137-
},
138-
139-
_socket_status: function (data) {
140-
this.$emit('socket::status', {data});
141-
},
142-
143-
_socket_serverLog: function (data) {
144-
data.split(/\n/g).forEach(item => {
145-
this.$emit('console', item);
146-
});
147-
},
148-
149-
_socket_consoleLine: function (data) {
150-
if(data.line) {
151-
data.line.split(/\n/g).forEach(item => {
152-
this.$emit('console', item);
153-
});
154-
}
155-
},
156119
},
157120
}
158121
</script>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<template>
2+
<div>
3+
<div v-if="connected">
4+
<transition name="slide-fade" mode="out-in">
5+
<button class="btn btn-green uppercase text-xs px-4 py-2"
6+
v-if="status === statuses.STATUS_OFF"
7+
v-on:click.prevent="sendPowerAction('start')"
8+
>Start</button>
9+
<div v-else>
10+
<button class="btn btn-red uppercase text-xs px-4 py-2" v-on:click.prevent="sendPowerAction('stop')">Stop</button>
11+
<button class="btn btn-secondary uppercase text-xs px-4 py-2" v-on:click.prevent="sendPowerAction('restart')">Restart</button>
12+
<button class="btn btn-secondary uppercase text-xs px-4 py-2" v-on:click.prevent="sendPowerAction('kill')">Kill</button>
13+
</div>
14+
</transition>
15+
</div>
16+
<div v-else>
17+
<div class="text-center">
18+
<div class="spinner"></div>
19+
<div class="pt-2 text-xs text-grey-light">Connecting to node</div>
20+
</div>
21+
</div>
22+
</div>
23+
</template>
24+
25+
<script>
26+
import Status from './../../../helpers/statuses';
27+
import { mapState } from 'vuex';
28+
29+
export default {
30+
name: 'power-buttons',
31+
32+
computed: {
33+
...mapState('socket', ['connected', 'status']),
34+
},
35+
36+
data: function () {
37+
return {
38+
statuses: Status,
39+
};
40+
},
41+
42+
methods: {
43+
sendPowerAction: function (action) {
44+
this.$socket.emit('set status', action)
45+
},
46+
},
47+
};
48+
</script>
49+
50+
<style scoped>
51+
.slide-fade-enter-active {
52+
transition: all 250ms ease;
53+
}
54+
.slide-fade-leave-active {
55+
transition: all 250ms cubic-bezier(1.0, 0.5, 0.8, 1.0);
56+
}
57+
.slide-fade-enter, .slide-fade-leave-to {
58+
transform: translateX(10px);
59+
opacity: 0;
60+
}
61+
</style>

resources/assets/scripts/components/server/subpages/ConsolePage.vue

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div>
33
<div class="text-xs font-mono">
44
<div class="rounded-t p-2 bg-black overflow-scroll w-full" style="min-height: 16rem;max-height:64rem;">
5-
<div v-if="loadingConsole">
5+
<div v-if="!connected">
66
<div class="spinner spinner-xl mt-24"></div>
77
</div>
88
<div class="mb-2 text-grey-light" ref="terminal"></div>
@@ -27,36 +27,59 @@
2727
<script>
2828
import { Terminal } from 'xterm';
2929
import * as TerminalFit from 'xterm/lib/addons/fit/fit';
30-
import Status from './../../../helpers/statuses';
30+
import {mapState} from 'vuex';
3131
3232
Terminal.applyAddon(TerminalFit);
3333
3434
export default {
3535
name: 'console-page',
36+
computed: {
37+
...mapState('socket', ['connected']),
38+
},
39+
40+
watch: {
41+
/**
42+
* Watch the connected variable and when it becomes true request the server logs.
43+
*
44+
* @param {Boolean} state
45+
*/
46+
connected: function (state) {
47+
if (state) {
48+
this.$socket.emit('send server log');
49+
}
50+
}
51+
},
3652
3753
/**
38-
* Mount the component and setup all of the terminal actions. Also fetches the initial
39-
* logs from the server to populate into the terminal.
54+
* Listen for specific socket.io emits from the server.
4055
*/
41-
mounted: function () {
42-
this.$parent.$on('socket::connected', () => {
43-
this.terminal.open(this.$refs.terminal);
44-
this.terminal.fit();
45-
this.terminal.clear();
56+
sockets: {
57+
'server log': function (data) {
58+
data.split(/\n/g).forEach(line => {
59+
this.terminal.writeln(line);
60+
});
61+
},
4662
47-
this.$parent.$emit('send-initial-log');
48-
});
63+
'console': function (data) {
64+
data.line.split(/\n/g).forEach(line => {
65+
this.terminal.writeln(line);
66+
});
67+
}
68+
},
4969
50-
this.$parent.$on('console', data => {
51-
this.loadingConsole = false;
52-
this.terminal.writeln(data);
53-
});
70+
/**
71+
* Mount the component and setup all of the terminal actions. Also fetches the initial
72+
* logs from the server to populate into the terminal if the socket is connected. If the
73+
* socket is not connected this will occur automatically when it connects.
74+
*/
75+
mounted: function () {
76+
this.terminal.open(this.$refs.terminal);
77+
this.terminal.fit();
78+
this.terminal.clear();
5479
55-
this.$parent.$on('socket::status', s => {
56-
if (s === Status.STATUS_OFF) {
57-
this.loadingConsole = false;
58-
}
59-
});
80+
if (this.connected) {
81+
this.$socket.emit('send server log');
82+
}
6083
},
6184
6285
data: function () {
@@ -76,7 +99,6 @@
7699
command: '',
77100
commandHistory: [],
78101
commandHistoryIndex: -1,
79-
loadingConsole: true,
80102
};
81103
},
82104
@@ -87,7 +109,7 @@
87109
sendCommand: function () {
88110
this.commandHistoryIndex = -1;
89111
this.commandHistory.unshift(this.command);
90-
this.$parent.$emit('send-command', this.command);
112+
this.$socket.emit('send command', this.command);
91113
this.command = '';
92114
},
93115

resources/assets/scripts/store/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,29 @@ import Vuex from 'vuex';
33
import auth from './modules/auth';
44
import dashboard from './modules/dashboard';
55
import server from './modules/server';
6+
import socket from './modules/socket';
67

78
Vue.use(Vuex);
89

910
const store = new Vuex.Store({
1011
strict: process.env.NODE_ENV !== 'production',
11-
modules: {auth, dashboard, server},
12+
modules: {auth, dashboard, server, socket},
1213
});
1314

1415
if (module.hot) {
1516
module.hot.accept(['./modules/auth'], () => {
1617
const newAuthModule = require('./modules/auth').default;
1718
const newDashboardModule = require('./modules/dashboard').default;
1819
const newServerModule = require('./modules/server').default;
20+
const newSocketModule = require('./modules/socket').default;
1921

2022
store.hotUpdate({
21-
modules: {newAuthModule, newDashboardModule, newServerModule},
23+
modules: {
24+
auth: newAuthModule,
25+
dashboard: newDashboardModule,
26+
server: newServerModule,
27+
socket: newSocketModule
28+
},
2229
});
2330
});
2431
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Status from './../../helpers/statuses';
2+
3+
export default {
4+
namespaced: true,
5+
state: {
6+
connected: false,
7+
connectionError: null,
8+
status: Status.STATUS_OFF,
9+
},
10+
actions: {
11+
},
12+
mutations: {
13+
SOCKET_CONNECT: (state) => {
14+
state.connected = true;
15+
},
16+
17+
SOCKET_ERROR: (state, err) => {
18+
state.connectionError = err;
19+
},
20+
21+
'SOCKET_INITIAL STATUS': (state, data) => {
22+
state.status = data.status;
23+
},
24+
25+
SOCKET_STATUS: (state, data) => {
26+
state.status = data.status;
27+
}
28+
},
29+
};

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,10 @@ camelcase@^4.0.0, camelcase@^4.1.0:
14901490
version "4.1.0"
14911491
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
14921492

1493+
camelcase@^5.0.0:
1494+
version "5.0.0"
1495+
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
1496+
14931497
caniuse-api@^1.5.2:
14941498
version "1.6.1"
14951499
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
@@ -6876,6 +6880,12 @@ vue-router@^3.0.1:
68766880
version "3.0.1"
68776881
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.1.tgz#d9b05ad9c7420ba0f626d6500d693e60092cc1e9"
68786882

6883+
vue-socket.io-extended@^3.1.0:
6884+
version "3.1.0"
6885+
resolved "https://registry.yarnpkg.com/vue-socket.io-extended/-/vue-socket.io-extended-3.1.0.tgz#0c1833377f902381c861c43a403a476eee542bc9"
6886+
dependencies:
6887+
camelcase "^5.0.0"
6888+
68796889
vue-style-loader@^4.0.1:
68806890
version "4.1.0"
68816891
resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.0.tgz#7588bd778e2c9f8d87bfc3c5a4a039638da7a863"

0 commit comments

Comments
 (0)