Skip to content

Commit 5252f3f

Browse files
committed
Show error message when attempting to connect to a websocket
1 parent 41a94c6 commit 5252f3f

File tree

3 files changed

+57
-16
lines changed

3 files changed

+57
-16
lines changed

resources/scripts/components/server/ServerConsole.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export default () => {
154154
</div>
155155
</Can>
156156
</div>
157-
<div className={'flex-1 mx-4 mr-4'}>
157+
<div className={'flex-1 ml-4'}>
158158
<SuspenseSpinner>
159159
<ChunkedConsole/>
160160
<ChunkedStatGraphs/>

resources/scripts/components/server/WebsocketHandler.tsx

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import React, { useEffect } from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { Websocket } from '@/plugins/Websocket';
33
import { ServerContext } from '@/state/server';
44
import getWebsocketToken from '@/api/server/getWebsocketToken';
5+
import ContentContainer from '@/components/elements/ContentContainer';
6+
import { CSSTransition } from 'react-transition-group';
7+
import Spinner from '@/components/elements/Spinner';
58

69
export default () => {
710
const server = ServerContext.useStoreState(state => state.server.data);
8-
const { instance } = ServerContext.useStoreState(state => state.socket);
11+
const [ error, setError ] = useState(false);
12+
const { connected, instance } = ServerContext.useStoreState(state => state.socket);
913
const setServerStatus = ServerContext.useStoreActions(actions => actions.status.setServerStatus);
1014
const { setInstance, setConnectionState } = ServerContext.useStoreActions(actions => actions.socket);
1115

@@ -15,6 +19,16 @@ export default () => {
1519
.catch(error => console.error(error));
1620
};
1721

22+
useEffect(() => {
23+
connected && setError(false);
24+
}, [ connected ]);
25+
26+
useEffect(() => {
27+
return () => {
28+
instance && instance.close();
29+
};
30+
}, [ instance ]);
31+
1832
useEffect(() => {
1933
// If there is already an instance or there is no server, just exit out of this process
2034
// since we don't need to make a new connection.
@@ -26,7 +40,10 @@ export default () => {
2640

2741
socket.on('auth success', () => setConnectionState(true));
2842
socket.on('SOCKET_CLOSE', () => setConnectionState(false));
29-
socket.on('SOCKET_ERROR', () => setConnectionState(false));
43+
socket.on('SOCKET_ERROR', () => {
44+
setError(true);
45+
setConnectionState(false);
46+
});
3047
socket.on('status', (status) => setServerStatus(status));
3148

3249
socket.on('daemon error', message => {
@@ -47,5 +64,19 @@ export default () => {
4764
.catch(error => console.error(error));
4865
}, [ server ]);
4966

50-
return null;
67+
return (
68+
error ?
69+
<CSSTransition timeout={250} in={true} appear={true} classNames={'fade'}>
70+
<div className={'bg-red-500 py-2'}>
71+
<ContentContainer className={'flex items-center justify-center'}>
72+
<Spinner size={'tiny'}/>
73+
<p className={'ml-2 text-sm text-red-100'}>
74+
We're having some trouble connecting to the console, please wait...
75+
</p>
76+
</ContentContainer>
77+
</div>
78+
</CSSTransition>
79+
:
80+
null
81+
);
5182
};

resources/scripts/plugins/Websocket.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ export const SOCKET_EVENTS = [
99
];
1010

1111
export class Websocket extends EventEmitter {
12+
// Timer instance for this socket.
13+
private timer: any = null;
14+
15+
// The backoff for the timer, in milliseconds.
16+
private backoff = 5000;
17+
1218
// The socket instance being tracked.
1319
private socket: Sockette | null = null;
1420

@@ -25,6 +31,7 @@ export class Websocket extends EventEmitter {
2531
// Connects to the websocket instance and sets the token for the initial request.
2632
connect (url: string): this {
2733
this.url = url;
34+
2835
this.socket = new Sockette(`${this.url}`, {
2936
onmessage: e => {
3037
try {
@@ -35,6 +42,10 @@ export class Websocket extends EventEmitter {
3542
}
3643
},
3744
onopen: () => {
45+
// Clear the timers, we managed to connect just fine.
46+
this.timer && clearTimeout(this.timer);
47+
this.backoff = 5000;
48+
3849
this.emit('SOCKET_OPEN');
3950
this.authenticate();
4051
},
@@ -43,15 +54,19 @@ export class Websocket extends EventEmitter {
4354
this.authenticate();
4455
},
4556
onclose: () => this.emit('SOCKET_CLOSE'),
46-
onerror: () => this.emit('SOCKET_ERROR'),
57+
onerror: error => this.emit('SOCKET_ERROR', error),
4758
});
4859

49-
return this;
50-
}
60+
this.timer = setTimeout(() => {
61+
this.backoff = (this.backoff + 2500 >= 20000) ? 20000 : this.backoff + 2500;
62+
this.socket && this.socket.close();
63+
clearTimeout(this.timer);
64+
65+
// Re-attempt connecting to the socket.
66+
this.connect(url);
67+
}, this.backoff);
5168

52-
// Returns the URL connected to for the socket.
53-
getSocketUrl (): string | null {
54-
return this.url;
69+
return this;
5570
}
5671

5772
// Sets the authentication token to use when sending commands back and forth
@@ -66,11 +81,6 @@ export class Websocket extends EventEmitter {
6681
return this;
6782
}
6883

69-
// Returns the token being used at the current moment.
70-
getToken (): string {
71-
return this.token;
72-
}
73-
7484
authenticate () {
7585
if (this.url && this.token) {
7686
this.send('auth', this.token);

0 commit comments

Comments
 (0)