1
0

WebSocket seems to be working

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-02-28 17:34:17 -08:00
parent 0bc96d5121
commit 0e91755c72
5 changed files with 130 additions and 41 deletions

View File

@ -150,6 +150,11 @@
clip-path: polygon(25% 0%,75% 0%,100% 50%,75% 100%,25% 100%,0% 50%);
}
div[disabled] .Option {
cursor: pointer;
pointer-events: none;
}
.Option {
cursor: pointer;
pointer-events: all;

View File

@ -502,6 +502,18 @@ const Board = ({ table, game }) => {
return (game && game.turn && Array.isArray(game.turn.actions) && game.turn.actions.indexOf(action) !== -1);
};
const canRoad = (canAction('place-road')
&& game.turn.color === game.color
&& (game.state === 'initial-placement' || game.state === 'normal'));
const canCorner = ((canAction('place-settlement') || canAction('place-city'))
&& game.turn.color === game.color
&& (game.state === 'initial-placement' || game.state === 'normal'));
const canPip = (canAction('place-robber')
&& game.turn.color === game.color
&& (game.state === 'initial-placement' || game.state === 'normal'));
return (
<div className="Board">
<div className="BoardBox">
@ -512,13 +524,13 @@ const Board = ({ table, game }) => {
<div className="Tiles" disabled>
{ tiles }
</div>
<div className="Pips" disabled={!canAction('place-robber') || game.turn.color !== game.color || (game.state !== 'initial-placement' && game.state !== 'normal')}>
<div className="Pips" disabled={!canPip}>
{ pips }
</div>
<div className="Corners" disabled={!canAction('place-settlement') || game.turn.color !== game.color || (game.state !== 'initial-placement' && game.state !== 'normal')}>
<div className="Corners" disabled={!canCorner}>
{ corners }
</div>
<div className="Roads" disabled={!canAction('place-road') || game.turn.color !== game.color || (game.state !== 'initial-placement' && game.state !== 'normal')}>
<div className="Roads" disabled={!canRoad}>
{ roads }
</div>
</> }

View File

@ -403,7 +403,7 @@ const Action = ({ table }) => {
<StartButton table={table}/>
<Button disabled={game.color ? false : true} onClick={newTableClick}>New table</Button>
<Button disabled={game.color ? true : false} onClick={() => {table.setState({ pickName: true})}}>Change name</Button> </> }
{ game.state === 'normal' && <>
{ !inLobby && <>
<Button disabled={robberActions || !isTurn || hasRolled} onClick={rollClick}>Roll Dice</Button>
<Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={tradeClick}>Trade</Button>
<Button disabled={robberActions || !isTurn || !hasRolled || !haveResources} onClick={buildClicked}>Build</Button>
@ -430,7 +430,8 @@ const PlayerName = ({table}) => {
if (name !== table.game.name) {
table.setPlayerName(name);
} else {
table.setState({ pickName: false, error: "" });
table.setError("");
table.setState({ pickName: false });
}
}
@ -604,10 +605,10 @@ class Table extends React.Component {
const error = (game.status !== 'success') ? game.status : undefined;
this.updateGame(game);
this.updateMessage();
this.setState({ error: error });
this.setError(error);
}).catch((error) => {
console.error(error);
this.setState({error: error.message});
this.setError(error.message);
}).then(() => {
this.setState({ loading: this.state.loading - 1 });
});
@ -640,7 +641,7 @@ class Table extends React.Component {
shuffleTable() {
return this.sendAction('shuffle')
.then(() => {
this.setState({ error: "Table shuffled!" });
this.setError("Table shuffled!");
});
}
@ -676,6 +677,19 @@ class Table extends React.Component {
return this.sendAction('roll');
}
setError(error) {
if (!error) {
return;
}
if (this.errorTimeout) {
clearTimeout(this.errorTimeout);
}
setTimeout(() => this.setState({error: undefined}), 3000);
if (this.state.error !== error) {
this.setState({ error });
}
}
setGameState(state) {
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
@ -702,9 +716,9 @@ class Table extends React.Component {
this.updateMessage();
}).catch((error) => {
console.error(error);
this.setState({error: error.message});
this.setError(error.message);
}).then(() => {
this.setState({ loading: this.state.loading + 1 });
this.setState({ loading: this.state.loading - 1 });
return this.game.state;
});
}
@ -865,7 +879,7 @@ class Table extends React.Component {
try {
data = JSON.parse(event.data);
} catch (error) {
this.setState({ error });
this.setError(error);
return;
}
let update;
@ -875,7 +889,16 @@ class Table extends React.Component {
const error = (update.status !== 'success') ? update.status : undefined;
this.updateGame(update);
this.updateMessage();
this.setState({ error });
this.setError(error);
break;
case 'ping':
if (this.keepAlive) {
clearTimeout(this.keepAlive);
}
this.keepAlive = setTimeout(() => {
console.error(`No server ping for 5 seconds!`);
}, 5000);
this.ws.send(JSON.stringify({ type: 'pong', timestamp: data.ping }));
break;
default:
console.log(`Unknown event type: ${data.type}`);
@ -925,7 +948,7 @@ class Table extends React.Component {
error = `Unable to find game ${this.id}. Starting new game.`
console.log(error);
this.setState({ error: error });
this.setError(error);
params.url = `${base}/api/v1/games/${this.id}`;
params.method = "POST";
@ -951,7 +974,7 @@ class Table extends React.Component {
this.setState({ error: "" });
}).catch((error) => {
console.error(error);
this.setState({error: error.message});
this.setError(error.message);
}).then(() => {
this.setState({ loading: this.state.loading - 1 });
});
@ -961,10 +984,16 @@ class Table extends React.Component {
if (this.loadTimer) {
clearTimeout(this.loadTimer);
}
if (this.keepAlive) {
clearTimeout(this.keepAlive);
}
if (this.updateSizeTimer) {
clearTimeout(this.updateSizeTimer);
this.updateSizeTimer = 0;
}
if (this.errorTimeout) {
clearTimeout(this.errorTimeout);
}
}
cardClicked(card) {
@ -1098,7 +1127,7 @@ class Table extends React.Component {
(!game.player || !game.player.mustDiscard) && <WaitingForPlayer table={this}/>
}
{ this.state.error && <Paper className="Error"><div>{this.state.error}</div></Paper> }
{ this.state.error && <Paper onClick={() => this.setState({ error: undefined })} className="Error"><div>{this.state.error}</div></Paper> }
</div>
);

View File

@ -115,7 +115,6 @@ app.use(basePath, function(req, res, next) {
/* Everything below here requires a successful authentication */
app.use(basePath, express.static(frontendPath, { index: false }));
app.set('ws', ws);
app.use(`${basePath}api/v1/games`, require("./routes/games"));
/* Declare the "catch all" index route last; the final route is a 404 dynamic router */
@ -127,10 +126,9 @@ app.use(basePath, index);
app.set("port", serverConfig.port);
process.on('SIGINT', () => {
server.close(() => {
console.log("Gracefully shutting down from SIGINT (Ctrl-C)");
process.exit(1);
});
console.log("Gracefully shutting down from SIGINT (Ctrl-C) in 2 seconds");
setTimeout(() => process.exit(-1), 2000);
server.close(() => process.exit(1));
});
require("./db/games").then(function(db) {

View File

@ -8,6 +8,7 @@ const express = require("express"),
accessSync = fs.accessSync,
randomWords = require("random-words");
const session = require("express-session");
const layout = require('./layout.js');
const MAX_SETTLEMENTS = 5;
@ -2489,20 +2490,59 @@ router.put("/:id/:action/:value?", async (req, res) => {
return sendGame(req, res, game, error);
})
const ping = (session) => {
session.ping = Date.now();
session.ws.send(JSON.stringify({ type: 'ping', ping: session.ping }));
if (session.keepAlive) {
clearTimeout(session.keepAlive);
}
session.keepAlive = setTimeout(() => { ping(session); }, 2500);
}
router.ws("/ws/:id", (ws, req) => {
const { id } = req.params;
ws.on('message', (msg) => {
console.log(msg);
});
if (id in games) {
const game = games[id];
console.log(`WebSocket connect from game ${id}`);
let game;
if (!(id in games)) {
game = createGame(id);
} else {
game = games[id];
}
const session = getSession(game, req.session);
if (session) {
console.log(`WebSocket connected for ${session.name}`);
console.log(`WebSocket connected for ${session.name ? session.name : "Unnamed"}`);
session.ws = ws;
if (session.keepAlive) {
clearTimeout(session.keepAlive);
}
session.keepAlive = setTimeout(() => { ping(session); }, 2500);
} else {
console.log(`No session found for WebSocket with id ${id}`);
}
ws.on('error', (event) => {
console.error(`WebSocket error: `, event.message);
});
ws.on('open', (event) => {
console.log(`WebSocket open: `, event.message);
});
ws.on('message', (message) => {
try {
const data = JSON.parse(message);
switch (data.type) {
case 'pong':
console.log(`Latency for ${session.name ? session.name : 'Unammed'} is ${Date.now() - data.timestamp}`);
break;
}
} catch (error) {
console.error(error);
}
});
});
router.get("/:id", async (req, res/*, next*/) => {
@ -2658,6 +2698,9 @@ const sendGame = async (req, res, game, error) => {
if (reduced.ws) {
delete reduced.ws;
}
if (reduced.keepAlive) {
delete reduced.keepAlive;
}
reducedGame.sessions[id] = reduced;
/* Do not send session-id as those are secrets */
@ -2704,6 +2747,7 @@ const sendGame = async (req, res, game, error) => {
});
if (useWS) {
if (!error) {
if (!target.ws) {
console.error(`No WebSocket connection to ${target.name}`);
} else {
@ -2713,8 +2757,9 @@ const sendGame = async (req, res, game, error) => {
update: playerGame
}));
}
}
} else {
console.log(`Returning update to ${target.name}`);
console.log(`Returning update to ${target.name ? target.name : 'Unnamed'}`);
res.status(200).send(playerGame);
}
}
@ -2726,7 +2771,8 @@ const resetGame = (game) => {
Object.assign(game, {
startTime: Date.now(),
state: 'lobby',
turn: 0,
turns: 0,
turn: {},
sheep: 19,
ore: 19,
wool: 19,
@ -2738,7 +2784,6 @@ const resetGame = (game) => {
},
developmentCards: [],
chat: [],
turn: {},
pipOrder: game.pipOrder,
borderOrder: game.borderOrder,
tileOrder: game.tileOrder,