feat: disconnected
This commit is contained in:
parent
216e528c13
commit
eb599c60c0
|
@ -1,5 +1,12 @@
|
||||||
|
import {encode} from '@/packets/index.js';
|
||||||
|
|
||||||
let connected = false;
|
let connected = false;
|
||||||
let socket;
|
let socket;
|
||||||
|
|
||||||
|
function onMessage(event) {
|
||||||
|
postMessage(event.data);
|
||||||
|
}
|
||||||
|
|
||||||
onmessage = async (event) => {
|
onmessage = async (event) => {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
const url = new URL(`wss://${event.data.host}/ws`)
|
const url = new URL(`wss://${event.data.host}/ws`)
|
||||||
|
@ -8,12 +15,21 @@ onmessage = async (event) => {
|
||||||
}
|
}
|
||||||
socket = new WebSocket(url.href);
|
socket = new WebSocket(url.href);
|
||||||
socket.binaryType = 'arraybuffer';
|
socket.binaryType = 'arraybuffer';
|
||||||
await new Promise((resolve) => {
|
const {promise, resolve, reject} = Promise.withResolvers();
|
||||||
socket.onopen = resolve;
|
socket.addEventListener('open', resolve);
|
||||||
|
socket.addEventListener('error', reject);
|
||||||
|
await promise;
|
||||||
|
socket.removeEventListener('open', resolve);
|
||||||
|
socket.removeEventListener('error', reject);
|
||||||
|
socket.addEventListener('message', onMessage);
|
||||||
|
socket.addEventListener('close', () => {
|
||||||
|
postMessage(encode({type: 'ConnectionAborted'}));
|
||||||
|
close();
|
||||||
|
});
|
||||||
|
socket.addEventListener('error', () => {
|
||||||
|
postMessage(encode({type: 'ConnectionAborted'}));
|
||||||
|
close();
|
||||||
});
|
});
|
||||||
socket.onmessage = (event) => {
|
|
||||||
postMessage(event.data);
|
|
||||||
};
|
|
||||||
connected = true;
|
connected = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
3
app/packets/connection-aborted.js
Normal file
3
app/packets/connection-aborted.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import Packet from '@/net/packet.js';
|
||||||
|
|
||||||
|
export default class ConnectionAborted extends Packet {}
|
27
app/react-components/disconnected.jsx
Normal file
27
app/react-components/disconnected.jsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import {useEffect, useState} from 'react';
|
||||||
|
|
||||||
|
import styles from './disconnected.module.css';
|
||||||
|
|
||||||
|
export default function Disconnected() {
|
||||||
|
const [dots, setDots] = useState(3);
|
||||||
|
const [delta, setDelta] = useState(1);
|
||||||
|
useEffect(() => {
|
||||||
|
const handle = setTimeout(() => {
|
||||||
|
const updated = dots + delta;
|
||||||
|
setDots(updated);
|
||||||
|
if (updated < 1 || updated > 5) {
|
||||||
|
setDelta(-delta);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handle);
|
||||||
|
};
|
||||||
|
}, [dots, delta]);
|
||||||
|
const rendered = Array(dots).fill('.').join('');
|
||||||
|
return (
|
||||||
|
<div className={styles.disconnected}>
|
||||||
|
<p>There's a problem with the connection.</p>
|
||||||
|
<p>{rendered}Reconnection attempt in progress{rendered}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
14
app/react-components/disconnected.module.css
Normal file
14
app/react-components/disconnected.module.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.disconnected {
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
p {
|
||||||
|
color: #cccccc;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import addKeyListener from '@/add-key-listener.js';
|
||||||
import {ACTION_MAP, RESOLUTION} from '@/constants.js';
|
import {ACTION_MAP, RESOLUTION} from '@/constants.js';
|
||||||
import ClientContext from '@/context/client.js';
|
import ClientContext from '@/context/client.js';
|
||||||
|
|
||||||
|
import Disconnected from './disconnected.jsx';
|
||||||
import Dom from './dom.jsx';
|
import Dom from './dom.jsx';
|
||||||
import HotBar from './hotbar.jsx';
|
import HotBar from './hotbar.jsx';
|
||||||
import Pixi from './pixi.jsx';
|
import Pixi from './pixi.jsx';
|
||||||
|
@ -16,7 +17,7 @@ const KEY_MAP = {
|
||||||
keyUp: 0,
|
keyUp: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Ui() {
|
export default function Ui({disconnected}) {
|
||||||
// Key input.
|
// Key input.
|
||||||
const client = useContext(ClientContext);
|
const client = useContext(ClientContext);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -43,6 +44,9 @@ export default function Ui() {
|
||||||
<Pixi />
|
<Pixi />
|
||||||
<Dom>
|
<Dom>
|
||||||
<HotBar active={0} slots={Array(10).fill(0).map(() => {})} />
|
<HotBar active={0} slots={Array(10).fill(0).map(() => {})} />
|
||||||
|
{disconnected && (
|
||||||
|
<Disconnected />
|
||||||
|
)}
|
||||||
</Dom>
|
</Dom>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,66 @@
|
||||||
|
import {useEffect, useState} from 'react';
|
||||||
|
import {useParams} from 'react-router-dom';
|
||||||
|
|
||||||
|
import ClientContext from '@/context/client.js';
|
||||||
|
import LocalClient from '@/net/client/local.js';
|
||||||
|
import RemoteClient from '@/net/client/remote.js';
|
||||||
|
import {decode, encode} from '@/packets/index.js';
|
||||||
import Ui from '@/react-components/ui.jsx';
|
import Ui from '@/react-components/ui.jsx';
|
||||||
|
|
||||||
|
import styles from './play.module.css';
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
|
const [client, setClient] = useState();
|
||||||
|
const [disconnected, setDisconnected] = useState();
|
||||||
|
const params = useParams();
|
||||||
|
const [type, url] = params['*'].split('/');
|
||||||
|
useEffect(() => {
|
||||||
|
let Client;
|
||||||
|
switch (type) {
|
||||||
|
case 'local':
|
||||||
|
Client = LocalClient;
|
||||||
|
break;
|
||||||
|
case 'remote':
|
||||||
|
Client = RemoteClient;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
class SilphiusClient extends Client {
|
||||||
|
accept(packed) {
|
||||||
|
super.accept(decode(packed));
|
||||||
|
}
|
||||||
|
transmit(packet) {
|
||||||
|
super.transmit(encode(packet));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const client = new SilphiusClient();
|
||||||
|
async function connect() {
|
||||||
|
await client.connect(url);
|
||||||
|
setClient(client);
|
||||||
|
}
|
||||||
|
connect();
|
||||||
|
return () => {
|
||||||
|
client.disconnect();
|
||||||
|
};
|
||||||
|
}, [type, url]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!client) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
function onConnectionAborted() {
|
||||||
|
setDisconnected(true);
|
||||||
|
}
|
||||||
|
client.addPacketListener('ConnectionAborted', onConnectionAborted);
|
||||||
|
return () => {
|
||||||
|
client.removePacketListener('ConnectionAborted', onConnectionAborted);
|
||||||
|
};
|
||||||
|
}, [client]);
|
||||||
return (
|
return (
|
||||||
<Ui />
|
<div className={styles.play}>
|
||||||
|
{client && (
|
||||||
|
<ClientContext.Provider value={client}>
|
||||||
|
<Ui disconnected={disconnected} />
|
||||||
|
</ClientContext.Provider>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
import {useEffect, useState} from 'react';
|
|
||||||
import {Outlet, useParams} from 'react-router-dom';
|
|
||||||
|
|
||||||
import ClientContext from '@/context/client.js';
|
|
||||||
import LocalClient from '@/net/client/local.js';
|
|
||||||
import RemoteClient from '@/net/client/remote.js';
|
|
||||||
import {decode, encode} from '@/packets/index.js';
|
|
||||||
|
|
||||||
import styles from './play.module.css';
|
|
||||||
|
|
||||||
export default function Index() {
|
|
||||||
const [client, setClient] = useState();
|
|
||||||
const params = useParams();
|
|
||||||
const [type, url] = params['*'].split('/');
|
|
||||||
useEffect(() => {
|
|
||||||
let Client;
|
|
||||||
switch (type) {
|
|
||||||
case 'local':
|
|
||||||
Client = LocalClient;
|
|
||||||
break;
|
|
||||||
case 'remote':
|
|
||||||
Client = RemoteClient;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
class SilphiusClient extends Client {
|
|
||||||
accept(packed) {
|
|
||||||
super.accept(decode(packed));
|
|
||||||
}
|
|
||||||
transmit(packet) {
|
|
||||||
super.transmit(encode(packet));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const client = new SilphiusClient();
|
|
||||||
async function connect() {
|
|
||||||
await client.connect(url);
|
|
||||||
setClient(client);
|
|
||||||
}
|
|
||||||
connect();
|
|
||||||
return () => {
|
|
||||||
client.disconnect();
|
|
||||||
};
|
|
||||||
}, [type, url]);
|
|
||||||
return (
|
|
||||||
<div className={styles.play}>
|
|
||||||
{client && (
|
|
||||||
<ClientContext.Provider value={client}>
|
|
||||||
<Outlet />
|
|
||||||
</ClientContext.Provider>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user