diff --git a/resources/scripts/components/server/ServerConsole.tsx b/resources/scripts/components/server/ServerConsole.tsx index 6a490ed8d..b808f8ef1 100644 --- a/resources/scripts/components/server/ServerConsole.tsx +++ b/resources/scripts/components/server/ServerConsole.tsx @@ -154,7 +154,7 @@ export default () => { -
+
diff --git a/resources/scripts/components/server/WebsocketHandler.tsx b/resources/scripts/components/server/WebsocketHandler.tsx index 930fb8894..f3516d23b 100644 --- a/resources/scripts/components/server/WebsocketHandler.tsx +++ b/resources/scripts/components/server/WebsocketHandler.tsx @@ -1,11 +1,15 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { Websocket } from '@/plugins/Websocket'; import { ServerContext } from '@/state/server'; import getWebsocketToken from '@/api/server/getWebsocketToken'; +import ContentContainer from '@/components/elements/ContentContainer'; +import { CSSTransition } from 'react-transition-group'; +import Spinner from '@/components/elements/Spinner'; export default () => { const server = ServerContext.useStoreState(state => state.server.data); - const { instance } = ServerContext.useStoreState(state => state.socket); + const [ error, setError ] = useState(false); + const { connected, instance } = ServerContext.useStoreState(state => state.socket); const setServerStatus = ServerContext.useStoreActions(actions => actions.status.setServerStatus); const { setInstance, setConnectionState } = ServerContext.useStoreActions(actions => actions.socket); @@ -15,6 +19,16 @@ export default () => { .catch(error => console.error(error)); }; + useEffect(() => { + connected && setError(false); + }, [ connected ]); + + useEffect(() => { + return () => { + instance && instance.close(); + }; + }, [ instance ]); + useEffect(() => { // If there is already an instance or there is no server, just exit out of this process // since we don't need to make a new connection. @@ -26,7 +40,10 @@ export default () => { socket.on('auth success', () => setConnectionState(true)); socket.on('SOCKET_CLOSE', () => setConnectionState(false)); - socket.on('SOCKET_ERROR', () => setConnectionState(false)); + socket.on('SOCKET_ERROR', () => { + setError(true); + setConnectionState(false); + }); socket.on('status', (status) => setServerStatus(status)); socket.on('daemon error', message => { @@ -47,5 +64,19 @@ export default () => { .catch(error => console.error(error)); }, [ server ]); - return null; + return ( + error ? + +
+ + +

+ We're having some trouble connecting to the console, please wait... +

+
+
+
+ : + null + ); }; diff --git a/resources/scripts/plugins/Websocket.ts b/resources/scripts/plugins/Websocket.ts index 385d66d4f..0aa13769d 100644 --- a/resources/scripts/plugins/Websocket.ts +++ b/resources/scripts/plugins/Websocket.ts @@ -9,6 +9,12 @@ export const SOCKET_EVENTS = [ ]; export class Websocket extends EventEmitter { + // Timer instance for this socket. + private timer: any = null; + + // The backoff for the timer, in milliseconds. + private backoff = 5000; + // The socket instance being tracked. private socket: Sockette | null = null; @@ -25,6 +31,7 @@ export class Websocket extends EventEmitter { // Connects to the websocket instance and sets the token for the initial request. connect (url: string): this { this.url = url; + this.socket = new Sockette(`${this.url}`, { onmessage: e => { try { @@ -35,6 +42,10 @@ export class Websocket extends EventEmitter { } }, onopen: () => { + // Clear the timers, we managed to connect just fine. + this.timer && clearTimeout(this.timer); + this.backoff = 5000; + this.emit('SOCKET_OPEN'); this.authenticate(); }, @@ -43,15 +54,19 @@ export class Websocket extends EventEmitter { this.authenticate(); }, onclose: () => this.emit('SOCKET_CLOSE'), - onerror: () => this.emit('SOCKET_ERROR'), + onerror: error => this.emit('SOCKET_ERROR', error), }); - return this; - } + this.timer = setTimeout(() => { + this.backoff = (this.backoff + 2500 >= 20000) ? 20000 : this.backoff + 2500; + this.socket && this.socket.close(); + clearTimeout(this.timer); - // Returns the URL connected to for the socket. - getSocketUrl (): string | null { - return this.url; + // Re-attempt connecting to the socket. + this.connect(url); + }, this.backoff); + + return this; } // Sets the authentication token to use when sending commands back and forth @@ -66,11 +81,6 @@ export class Websocket extends EventEmitter { return this; } - // Returns the token being used at the current moment. - getToken (): string { - return this.token; - } - authenticate () { if (this.url && this.token) { this.send('auth', this.token);