Correctly handle socket state in the app and make it possible to listen for events
This commit is contained in:
parent
f0ca8bc3a3
commit
c8d89e0964
6 changed files with 89 additions and 16 deletions
|
@ -10,6 +10,7 @@
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"date-fns": "^1.29.0",
|
"date-fns": "^1.29.0",
|
||||||
"easy-peasy": "^2.5.0",
|
"easy-peasy": "^2.5.0",
|
||||||
|
"events": "^3.0.0",
|
||||||
"feather-icons": "^4.10.0",
|
"feather-icons": "^4.10.0",
|
||||||
"formik": "^1.5.7",
|
"formik": "^1.5.7",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
"@babel/preset-env": "^7.3.1",
|
"@babel/preset-env": "^7.3.1",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"@types/classnames": "^2.2.8",
|
"@types/classnames": "^2.2.8",
|
||||||
|
"@types/events": "^3.0.0",
|
||||||
"@types/feather-icons": "^4.7.0",
|
"@types/feather-icons": "^4.7.0",
|
||||||
"@types/lodash": "^4.14.119",
|
"@types/lodash": "^4.14.119",
|
||||||
"@types/query-string": "^6.3.0",
|
"@types/query-string": "^6.3.0",
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Actions, State, useStoreActions, useStoreState } from 'easy-peasy';
|
import { Actions, State, useStoreActions, useStoreState } from 'easy-peasy';
|
||||||
import { ApplicationState } from '@/state/types';
|
import { ApplicationState } from '@/state/types';
|
||||||
import Sockette from 'sockette';
|
import { Websocket } from '@/plugins/Websocket';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const server = useStoreState((state: State<ApplicationState>) => state.server.data);
|
const server = useStoreState((state: State<ApplicationState>) => state.server.data);
|
||||||
const instance = useStoreState((state: State<ApplicationState>) => state.server.socket.instance);
|
const instance = useStoreState((state: State<ApplicationState>) => state.server.socket.instance);
|
||||||
const setInstance = useStoreActions((actions: Actions<ApplicationState>) => actions.server.socket.setInstance);
|
const setServerStatus = useStoreActions((actions: Actions<ApplicationState>) => actions.server.setServerStatus);
|
||||||
const setConnectionState = useStoreActions((actions: Actions<ApplicationState>) => actions.server.socket.setConnectionState);
|
const { setInstance, setConnectionState } = useStoreActions((actions: Actions<ApplicationState>) => actions.server.socket);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If there is already an instance or there is no server, just exit out of this process
|
// If there is already an instance or there is no server, just exit out of this process
|
||||||
|
@ -16,19 +16,20 @@ export default () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('need to connect to instance');
|
console.log('Connecting!');
|
||||||
const socket = new Sockette(`wss://wings.pterodactyl.test:8080/api/servers/${server.uuid}/ws`, {
|
|
||||||
protocols: 'CC8kHCuMkXPosgzGO6d37wvhNcksWxG6kTrA',
|
|
||||||
// onmessage: (ev) => console.log(ev),
|
|
||||||
onopen: () => setConnectionState(true),
|
|
||||||
onclose: () => setConnectionState(false),
|
|
||||||
onerror: () => setConnectionState(false),
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Setting instance!');
|
const socket = new Websocket(
|
||||||
|
`wss://wings.pterodactyl.test:8080/api/servers/${server.uuid}/ws`,
|
||||||
|
'CC8kHCuMkXPosgzGO6d37wvhNcksWxG6kTrA'
|
||||||
|
);
|
||||||
|
|
||||||
|
socket.on('SOCKET_OPEN', () => setConnectionState(true));
|
||||||
|
socket.on('SOCKET_CLOSE', () => setConnectionState(false));
|
||||||
|
socket.on('SOCKET_ERROR', () => setConnectionState(false));
|
||||||
|
socket.on('status', (status) => setServerStatus(status));
|
||||||
|
|
||||||
setInstance(socket);
|
setInstance(socket);
|
||||||
}, [server]);
|
}, [ server ]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
53
resources/scripts/plugins/Websocket.ts
Normal file
53
resources/scripts/plugins/Websocket.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import Sockette from 'sockette';
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
|
|
||||||
|
export const SOCKET_EVENTS = [
|
||||||
|
'SOCKET_OPEN',
|
||||||
|
'SOCKET_RECONNECT',
|
||||||
|
'SOCKET_CLOSE',
|
||||||
|
'SOCKET_ERROR',
|
||||||
|
];
|
||||||
|
|
||||||
|
export class Websocket extends EventEmitter {
|
||||||
|
socket: Sockette;
|
||||||
|
|
||||||
|
constructor (url: string, protocol: string) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.socket = new Sockette(url, {
|
||||||
|
protocols: protocol,
|
||||||
|
onmessage: e => {
|
||||||
|
try {
|
||||||
|
let { event, args } = JSON.parse(e.data);
|
||||||
|
this.emit(event, ...args);
|
||||||
|
} catch (ex) {
|
||||||
|
console.warn('Failed to parse incoming websocket message.', ex);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onopen: () => this.emit('SOCKET_OPEN'),
|
||||||
|
onreconnect: () => this.emit('SOCKET_RECONNECT'),
|
||||||
|
onclose: () => this.emit('SOCKET_CLOSE'),
|
||||||
|
onerror: () => this.emit('SOCKET_ERROR'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close (code?: number, reason?: string) {
|
||||||
|
this.socket.close(code, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
open () {
|
||||||
|
this.socket.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
json (data: any) {
|
||||||
|
this.socket.json(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnect () {
|
||||||
|
this.socket.reconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
send (data: any) {
|
||||||
|
this.socket.send(data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,16 +2,21 @@ import getServer, { Server } from '@/api/server/getServer';
|
||||||
import { action, Action, thunk, Thunk } from 'easy-peasy';
|
import { action, Action, thunk, Thunk } from 'easy-peasy';
|
||||||
import socket, { SocketState } from './socket';
|
import socket, { SocketState } from './socket';
|
||||||
|
|
||||||
|
export type ServerStatus = 'offline' | 'starting' | 'stopping' | 'online';
|
||||||
|
|
||||||
export interface ServerState {
|
export interface ServerState {
|
||||||
data?: Server;
|
data?: Server;
|
||||||
|
status: ServerStatus;
|
||||||
socket: SocketState;
|
socket: SocketState;
|
||||||
getServer: Thunk<ServerState, string, {}, any, Promise<void>>;
|
getServer: Thunk<ServerState, string, {}, any, Promise<void>>;
|
||||||
setServer: Action<ServerState, Server>;
|
setServer: Action<ServerState, Server>;
|
||||||
|
setServerStatus: Action<ServerState, ServerStatus>;
|
||||||
clearServerState: Action<ServerState>;
|
clearServerState: Action<ServerState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const server: ServerState = {
|
const server: ServerState = {
|
||||||
socket,
|
socket,
|
||||||
|
status: 'offline',
|
||||||
getServer: thunk(async (actions, payload) => {
|
getServer: thunk(async (actions, payload) => {
|
||||||
const server = await getServer(payload);
|
const server = await getServer(payload);
|
||||||
actions.setServer(server);
|
actions.setServer(server);
|
||||||
|
@ -19,10 +24,14 @@ const server: ServerState = {
|
||||||
setServer: action((state, payload) => {
|
setServer: action((state, payload) => {
|
||||||
state.data = payload;
|
state.data = payload;
|
||||||
}),
|
}),
|
||||||
|
setServerStatus: action((state, payload) => {
|
||||||
|
state.status = payload;
|
||||||
|
}),
|
||||||
clearServerState: action(state => {
|
clearServerState: action(state => {
|
||||||
state.data = undefined;
|
state.data = undefined;
|
||||||
|
|
||||||
if (state.socket.instance) {
|
if (state.socket.instance) {
|
||||||
|
state.socket.instance.removeAllListeners();
|
||||||
state.socket.instance.close();
|
state.socket.instance.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Action, action } from 'easy-peasy';
|
import { Action, action } from 'easy-peasy';
|
||||||
import Sockette from 'sockette';
|
import { Websocket } from '@/plugins/Websocket';
|
||||||
|
|
||||||
export interface SocketState {
|
export interface SocketState {
|
||||||
instance: Sockette | null;
|
instance: Websocket | null;
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
setInstance: Action<SocketState, Sockette | null>;
|
setInstance: Action<SocketState, Websocket | null>;
|
||||||
setConnectionState: Action<SocketState, boolean>;
|
setConnectionState: Action<SocketState, boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -766,6 +766,10 @@
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||||
|
|
||||||
|
"@types/events@^3.0.0":
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||||
|
|
||||||
"@types/feather-icons@^4.7.0":
|
"@types/feather-icons@^4.7.0":
|
||||||
version "4.7.0"
|
version "4.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/feather-icons/-/feather-icons-4.7.0.tgz#ec66bc046bcd1513835f87541ecef54b50c57ec9"
|
resolved "https://registry.yarnpkg.com/@types/feather-icons/-/feather-icons-4.7.0.tgz#ec66bc046bcd1513835f87541ecef54b50c57ec9"
|
||||||
|
@ -3059,6 +3063,10 @@ events@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
|
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
|
||||||
|
|
||||||
|
events@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
|
||||||
|
|
||||||
eventsource@^1.0.7:
|
eventsource@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0"
|
resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0"
|
||||||
|
|
Loading…
Reference in a new issue