Auto reconnect hooked up
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
689b498f6b
commit
def2afac6d
@ -15,10 +15,26 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between; /* left-justify 'board', right-justify 'game' */
|
|
||||||
background-image: url("./assets/tabletop.png");
|
background-image: url("./assets/tabletop.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Table .ErrorDialog {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #00000060;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Table .ErrorDialog .Error {
|
||||||
|
display: flex;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.Table .Game {
|
.Table .Game {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -34,8 +50,6 @@ body {
|
|||||||
.Table .Hand {
|
.Table .Hand {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
border: 1px solid orange;
|
|
||||||
margin: 1rem;
|
|
||||||
height: 11rem;
|
height: 11rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,8 +65,6 @@ body {
|
|||||||
.Table .Board {
|
.Table .Board {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin: 1rem;
|
|
||||||
border: 1px solid purple;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.Table .Sidebar .Chat {
|
.Table .Sidebar .Chat {
|
||||||
|
@ -7,8 +7,8 @@ import {
|
|||||||
Routes,
|
Routes,
|
||||||
useParams
|
useParams
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import { base, gamesPath } from './Common.js';
|
|
||||||
import history from "./history.js";
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
|
||||||
import { GlobalContext } from "./GlobalContext.js";
|
import { GlobalContext } from "./GlobalContext.js";
|
||||||
import { PingPong } from "./PingPong.js";
|
import { PingPong } from "./PingPong.js";
|
||||||
@ -17,7 +17,8 @@ import { Chat } from "./Chat.js";
|
|||||||
import { MediaAgent } from "./MediaControl.js";
|
import { MediaAgent } from "./MediaControl.js";
|
||||||
import { Board } from "./Board.js";
|
import { Board } from "./Board.js";
|
||||||
import { Actions } from "./Actions.js";
|
import { Actions } from "./Actions.js";
|
||||||
|
import { base, gamesPath, debounce } from './Common.js';
|
||||||
|
import history from "./history.js";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
const Table = () => {
|
const Table = () => {
|
||||||
@ -29,6 +30,7 @@ const Table = () => {
|
|||||||
const [ error, setError ] = useState(undefined);
|
const [ error, setError ] = useState(undefined);
|
||||||
const [ peers, setPeers ] = useState({});
|
const [ peers, setPeers ] = useState({});
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
|
const [connecting, setConnecting] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(peers);
|
console.log(peers);
|
||||||
@ -41,6 +43,7 @@ const Table = () => {
|
|||||||
/* We do not set the socket as bound until the 'open' message
|
/* We do not set the socket as bound until the 'open' message
|
||||||
* comes through */
|
* comes through */
|
||||||
setWs(event.target);
|
setWs(event.target);
|
||||||
|
setConnecting(false);
|
||||||
|
|
||||||
/* Request a game-update */
|
/* Request a game-update */
|
||||||
event.target.send(JSON.stringify({
|
event.target.send(JSON.stringify({
|
||||||
@ -75,18 +78,32 @@ const Table = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetConnection = (function () {
|
||||||
|
let timer = 0;
|
||||||
|
function reset() {
|
||||||
|
timer = 0;
|
||||||
|
setConnecting(false);
|
||||||
|
};
|
||||||
|
return _ => {
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
timer = setTimeout(reset, 5000);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
const onWsError = (event) => {
|
const onWsError = (event) => {
|
||||||
console.log(`ws: error`, event);
|
console.log(`ws: error`, event);
|
||||||
const error = `Connection to Ketr Ketran game server failed! ` +
|
const error = `Connection to Ketr Ketran game server failed! ` +
|
||||||
`Try refreshing in a few seconds.`;
|
`Connection attempt will be retried every 5 seconds.`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
resetConnection();
|
||||||
setError(error);
|
setError(error);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onWsClose = (event) => {
|
const onWsClose = (event) => {
|
||||||
console.log(`ws: close`);
|
console.log(`ws: close`);
|
||||||
setWs(undefined);
|
resetConnection();
|
||||||
global.ws = undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* callback refs are used to provide correct state reference
|
/* callback refs are used to provide correct state reference
|
||||||
@ -126,7 +143,7 @@ const Table = () => {
|
|||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.status >= 400) {
|
if (res.status >= 400) {
|
||||||
const error = `Unable to connect to Ketr Ketran game server! ` +
|
const error = `Unable to connect to Ketr Ketran game server! ` +
|
||||||
`Try refreshing in a few seconds.`;
|
`Try refreshing your browser in a few seconds.`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
setError(error);
|
setError(error);
|
||||||
throw error;
|
throw error;
|
||||||
@ -163,6 +180,7 @@ const Table = () => {
|
|||||||
new_uri = `${new_uri}://${loc.host}${base}/api/v1/games/ws/${gameId}`;
|
new_uri = `${new_uri}://${loc.host}${base}/api/v1/games/ws/${gameId}`;
|
||||||
console.log(`Attempting WebSocket connection to ${new_uri}`);
|
console.log(`Attempting WebSocket connection to ${new_uri}`);
|
||||||
socket = new WebSocket(new_uri);
|
socket = new WebSocket(new_uri);
|
||||||
|
setConnecting(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('table - bind');
|
console.log('table - bind');
|
||||||
@ -185,11 +203,7 @@ const Table = () => {
|
|||||||
socket.removeEventListener('message', cbMessage);
|
socket.removeEventListener('message', cbMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [ setWs, gameId, ws, refWsOpen, refWsMessage, refWsClose, refWsError ]);
|
}, [ setWs, connecting, setConnecting, gameId, ws, refWsOpen, refWsMessage, refWsClose, refWsError ]);
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return <div>{ error }</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Loaded: ${loaded}`);
|
console.log(`Loaded: ${loaded}`);
|
||||||
|
|
||||||
@ -198,6 +212,7 @@ const Table = () => {
|
|||||||
<MediaAgent/>
|
<MediaAgent/>
|
||||||
<PingPong/>
|
<PingPong/>
|
||||||
<div className="Table">
|
<div className="Table">
|
||||||
|
{ error && <div className="ErrorDialog"><Paper className="Error">{ error }</Paper></div> }
|
||||||
<div className="Game">
|
<div className="Game">
|
||||||
<Board/>
|
<Board/>
|
||||||
<div className="Hand">todo: player's hand</div>
|
<div className="Hand">todo: player's hand</div>
|
||||||
|
@ -9,9 +9,8 @@ const getPlayerName = (sessions, color) => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function debounce(fn, ms) {
|
function debounce(fn, ms) {
|
||||||
let timer
|
let timer;
|
||||||
return _ => {
|
return _ => {
|
||||||
clearTimeout(timer)
|
clearTimeout(timer)
|
||||||
timer = setTimeout(_ => {
|
timer = setTimeout(_ => {
|
||||||
@ -19,7 +18,7 @@ function debounce(fn, ms) {
|
|||||||
fn.apply(this, arguments)
|
fn.apply(this, arguments)
|
||||||
}, ms)
|
}, ms)
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const base = process.env.PUBLIC_URL;
|
const base = process.env.PUBLIC_URL;
|
||||||
|
|
||||||
|
@ -2746,29 +2746,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "state":
|
|
||||||
const state = value;
|
|
||||||
if (!state) {
|
|
||||||
error = `Invalid state.`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state === game.state) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case "game-order":
|
|
||||||
if (game.state !== 'lobby') {
|
|
||||||
error = `You cannot start a game from other than the lobby.`;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
addChatMessage(game, null, `${name} requested to start the game.`);
|
|
||||||
game.state = state;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sendGame(req, res, game, error);
|
return sendGame(req, res, game, error);
|
||||||
@ -2804,6 +2782,30 @@ const wsInactive = (game, req) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setGameState = (game, session, state) => {
|
||||||
|
if (!state) {
|
||||||
|
return `Invalid state.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session.color) {
|
||||||
|
return `You must have an active player to start the game.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state === game.state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case "game-order":
|
||||||
|
if (game.state !== 'lobby') {
|
||||||
|
return `You cannot start a game from other than the lobby.`;
|
||||||
|
}
|
||||||
|
addChatMessage(game, null, `${session.name} requested to start the game.`);
|
||||||
|
game.state = state;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const resetDisconnectCheck = (game, req) => {
|
const resetDisconnectCheck = (game, req) => {
|
||||||
if (req.disconnectCheck) {
|
if (req.disconnectCheck) {
|
||||||
clearTimeout(req.disconnectCheck);
|
clearTimeout(req.disconnectCheck);
|
||||||
@ -3122,6 +3124,15 @@ router.ws("/ws/:id", async (ws, req) => {
|
|||||||
console.log(`${id}:${getName(session)} - ${data.type} ${data.field} = ${data.value}`);
|
console.log(`${id}:${getName(session)} - ${data.type} ${data.field} = ${data.value}`);
|
||||||
update = {};
|
update = {};
|
||||||
switch (data.field) {
|
switch (data.field) {
|
||||||
|
case 'state':
|
||||||
|
error = setGameState(game, session, data.value);
|
||||||
|
if (error) {
|
||||||
|
console.warn(error);
|
||||||
|
session.ws.send(JSON.stringify({ type: 'error', error }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sendToPlayers(game, { state: game.state, chat });
|
||||||
|
break;
|
||||||
case 'color':
|
case 'color':
|
||||||
error = setPlayerColor(game, session, data.value);
|
error = setPlayerColor(game, session, data.value);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -3129,6 +3140,8 @@ router.ws("/ws/:id", async (ws, req) => {
|
|||||||
session.ws.send(JSON.stringify({ type: 'error', error }));
|
session.ws.send(JSON.stringify({ type: 'error', error }));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Can't use sendToPlayers as the player name is a top level field
|
||||||
|
* and is unique to each player */
|
||||||
for (let key in game.sessions) {
|
for (let key in game.sessions) {
|
||||||
const _session = game.sessions[key];
|
const _session = game.sessions[key];
|
||||||
if (!_session.ws) {
|
if (!_session.ws) {
|
||||||
@ -3143,7 +3156,7 @@ router.ws("/ws/:id", async (ws, req) => {
|
|||||||
await saveGame(game);
|
await saveGame(game);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`WARNING: Requested SET unsupported field: ${field}`);
|
console.warn(`WARNING: Requested SET unsupported field: ${data.field}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user