1
0

Added WebSocket for responses

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-02-28 13:11:27 -08:00
parent 7ec798d0ed
commit 0bc96d5121
8 changed files with 130 additions and 120 deletions

View File

@ -530,8 +530,6 @@ class Table extends React.Component {
}; };
this.componentDidMount = this.componentDidMount.bind(this); this.componentDidMount = this.componentDidMount.bind(this);
this.throwDice = this.throwDice.bind(this); this.throwDice = this.throwDice.bind(this);
this.resetGameLoad = this.resetGameLoad.bind(this);
this.loadGame = this.loadGame.bind(this);
this.rollDice = this.rollDice.bind(this); this.rollDice = this.rollDice.bind(this);
this.setGameState = this.setGameState.bind(this); this.setGameState = this.setGameState.bind(this);
this.shuffleTable = this.shuffleTable.bind(this); this.shuffleTable = this.shuffleTable.bind(this);
@ -612,7 +610,6 @@ class Table extends React.Component {
this.setState({error: error.message}); this.setState({error: error.message});
}).then(() => { }).then(() => {
this.setState({ loading: this.state.loading - 1 }); this.setState({ loading: this.state.loading - 1 });
this.resetGameLoad();
}); });
} }
@ -679,53 +676,6 @@ class Table extends React.Component {
return this.sendAction('roll'); return this.sendAction('roll');
} }
loadGame() {
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
this.loadTimer = null;
}
if (!this.state.game) {
console.error('Attempting to loadGame with no game set');
return;
}
this.setState({ loading: this.state.loading + 1 });
return window.fetch(`${base}/api/v1/games/${this.state.game.id}`, {
method: "GET",
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
}
}).then((res) => {
if (res.status >= 400) {
console.log(res);
throw new Error(`Server temporarily unreachable.`);
}
return res.json();
}).then((game) => {
const error = (game.status !== 'success') ? game.status : undefined;
this.updateGame(game);
this.updateMessage();
this.setState({ error: error });
}).catch((error) => {
console.error(error);
this.setState({error: error.message});
}).then(() => {
this.setState({ loading: this.state.loading - 1 });
this.resetGameLoad();
});
}
resetGameLoad() {
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
this.loadTimer = 0;
}
this.loadTimer = window.setTimeout(this.loadGame, 1000);
}
setGameState(state) { setGameState(state) {
if (this.loadTimer) { if (this.loadTimer) {
window.clearTimeout(this.loadTimer); window.clearTimeout(this.loadTimer);
@ -755,7 +705,6 @@ class Table extends React.Component {
this.setState({error: error.message}); this.setState({error: error.message});
}).then(() => { }).then(() => {
this.setState({ loading: this.state.loading + 1 }); this.setState({ loading: this.state.loading + 1 });
this.resetGameLoad();
return this.game.state; return this.game.state;
}); });
} }
@ -808,7 +757,7 @@ class Table extends React.Component {
this.setState( { signature: game.signature }); this.setState( { signature: game.signature });
} }
// console.log("Update Game", game); // console.log("Update Game", game);
this.setState( { game: game }); this.setState( { game });
this.game = game; this.game = game;
} }
@ -904,21 +853,44 @@ class Table extends React.Component {
} else { } else {
new_uri = "ws"; new_uri = "ws";
} }
new_uri = `${new_uri}://${loc.host}${base}/ws`; new_uri = `${new_uri}://${loc.host}${base}/api/v1/games/ws/${this.id}`;
this.ws = new WebSocket(new_uri); this.ws = new WebSocket(new_uri);
this.ws.onopen = (event) => { this.ws.onopen = (event) => {
console.log(event); console.log(`WebSocket open:`, event);
//ws.send(JSON.stringify(apiCall));
}; };
this.ws.onmessage = (event) => { this.ws.onmessage = (event) => {
const json = JSON.parse(event.data); let data;
console.log(json); try {
}; data = JSON.parse(event.data);
} catch (error) {
this.setState({ error });
return;
}
let update;
switch (data.type) {
case 'game-update':
update = data.update;
const error = (update.status !== 'success') ? update.status : undefined;
this.updateGame(update);
this.updateMessage();
this.setState({ error });
break;
default:
console.log(`Unknown event type: ${data.type}`);
break;
}
}
this.ws.onerror = (event) => { this.ws.onerror = (event) => {
console.error(event); this.setState({ error: event.message });
console.error(`WebSocket error:`, event);
};
this.ws.onclose = (event) => {
this.setState({ error: event.message });
console.error(`WebSocket close:`, event);
}; };
const params = {}; const params = {};
@ -982,7 +954,6 @@ class Table extends React.Component {
this.setState({error: error.message}); this.setState({error: error.message});
}).then(() => { }).then(() => {
this.setState({ loading: this.state.loading - 1 }); this.setState({ loading: this.state.loading - 1 });
this.resetGameLoad();
}); });
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -4,7 +4,7 @@ module.exports = function(app) {
const base = process.env.PUBLIC_URL; const base = process.env.PUBLIC_URL;
console.log('http-proxy-middleware'); console.log('http-proxy-middleware');
app.use(createProxyMiddleware( app.use(createProxyMiddleware(
`${base}/ws`, { `${base}/api/v1/games/ws`, {
ws: true, ws: true,
target: 'http://localhost:8930', target: 'http://localhost:8930',
changeOrigin: true, changeOrigin: true,

View File

@ -10,7 +10,10 @@ const express = require("express"),
session = require('express-session'), session = require('express-session'),
hb = require("handlebars"), hb = require("handlebars"),
SQLiteStore = require('connect-sqlite3')(session), SQLiteStore = require('connect-sqlite3')(session),
basePath = require("./basepath"); basePath = require("./basepath"),
app = express(),
server = require("http").createServer(app),
ws = require('express-ws')(app, server);
require("./console-line.js"); /* Monkey-patch console.log with line numbers */ require("./console-line.js"); /* Monkey-patch console.log with line numbers */
@ -21,8 +24,6 @@ console.log("Hosting server from: " + basePath);
let userDB, gameDB; let userDB, gameDB;
const app = express();
app.use(bodyParser.json()); app.use(bodyParser.json());
@ -81,6 +82,7 @@ app.use(basePath, index);
/* /games loads the default index */ /* /games loads the default index */
app.use(basePath + "games", index); app.use(basePath + "games", index);
/* Allow access to the 'users' API w/out being logged in */ /* Allow access to the 'users' API w/out being logged in */
/* /*
const users = require("./routes/users"); const users = require("./routes/users");
@ -113,7 +115,8 @@ app.use(basePath, function(req, res, next) {
/* Everything below here requires a successful authentication */ /* Everything below here requires a successful authentication */
app.use(basePath, express.static(frontendPath, { index: false })); app.use(basePath, express.static(frontendPath, { index: false }));
app.use(basePath + "api/v1/games", require("./routes/games")); 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 */ /* Declare the "catch all" index route last; the final route is a 404 dynamic router */
app.use(basePath, index); app.use(basePath, index);
@ -123,8 +126,6 @@ app.use(basePath, index);
*/ */
app.set("port", serverConfig.port); app.set("port", serverConfig.port);
const server = require("http").createServer(app);
process.on('SIGINT', () => { process.on('SIGINT', () => {
server.close(() => { server.close(() => {
console.log("Gracefully shutting down from SIGINT (Ctrl-C)"); console.log("Gracefully shutting down from SIGINT (Ctrl-C)");
@ -132,8 +133,6 @@ process.on('SIGINT', () => {
}); });
}); });
const WebSocket = require('ws');
require("./db/games").then(function(db) { require("./db/games").then(function(db) {
gameDB = db; gameDB = db;
}).then(function() { }).then(function() {
@ -142,33 +141,6 @@ require("./db/games").then(function(db) {
}); });
}).then(function() { }).then(function() {
console.log("DB connected. Opening server."); console.log("DB connected. Opening server.");
/* Create web socket server on top of a regular http server */
const ws = new WebSocket.Server({
server
});
/* Mount the Express app here */
//server.on('request', app);
app.set('ws', ws);
ws.on('connection', (req) => {/*
sessionParser(req.upgradeReq, {}, () => {
console.log("New websocket connection:");
var sess = req.upgradeReq.session;
console.log("working = " + sess.working);
});*/
});
ws.on('message', (message) => {
console.log(`received: ${message}`);
ws.send(JSON.stringify({
answer: 42
}));
});
server.listen(serverConfig.port, () => { server.listen(serverConfig.port, () => {
console.log(`http/ws server listening on ${serverConfig.port}`); console.log(`http/ws server listening on ${serverConfig.port}`);
}); });

View File

@ -17,6 +17,7 @@
"core-js": "^3.2.1", "core-js": "^3.2.1",
"express": "^4.17.1", "express": "^4.17.1",
"express-session": "^1.17.1", "express-session": "^1.17.1",
"express-ws": "^5.0.2",
"handlebars": "^4.7.6", "handlebars": "^4.7.6",
"moment": "^2.24.0", "moment": "^2.24.0",
"morgan": "^1.9.1", "morgan": "^1.9.1",

21
server/pass Executable file
View File

@ -0,0 +1,21 @@
#!/bin/bash
ADMIN=$(jq -r .admin config/local.json)
if [[ "${ADMIN}" == "" ]]; then
echo "You need to set your { 'admin': 'secret' } in config/local.json"
exit 1
fi
id=$1
if [[ "${id}" == "" ]]; then
echo "Usage: pass GAME-ID"
exit 1
fi
curl --noproxy '*' -s -L \
--request PUT \
--header "PRIVATE-TOKEN: ${ADMIN}" \
--header "Content-Type: application/json" \
http://localhost:8930/ketr.ketran/api/v1/games/${id}/pass |
jq -r .status

8
server/reset Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
cp games/held_riding_farm_hat.67 games/held_riding_farm_hat
set -m
npm start &
sleep 3
./pass held_riding_farm_hat
./roll held_riding_farm_hat 3-3
fg %1

View File

@ -1,6 +1,7 @@
"use strict"; "use strict";
const express = require("express"), const express = require("express"),
router = express.Router(),
crypto = require("crypto"), crypto = require("crypto"),
{ readFile, writeFile } = require("fs").promises, { readFile, writeFile } = require("fs").promises,
fs = require("fs"), fs = require("fs"),
@ -19,8 +20,6 @@ require("../db/games").then(function(db) {
gameDB = db; gameDB = db;
}); });
const router = express.Router();
function shuffle(array) { function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex; var currentIndex = array.length, temporaryValue, randomIndex;
@ -2490,6 +2489,22 @@ router.put("/:id/:action/:value?", async (req, res) => {
return sendGame(req, res, game, error); return sendGame(req, res, game, error);
}) })
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];
const session = getSession(game, req.session);
if (session) {
console.log(`WebSocket connected for ${session.name}`);
session.ws = ws;
}
}
});
router.get("/:id", async (req, res/*, next*/) => { router.get("/:id", async (req, res/*, next*/) => {
const { id } = req.params; const { id } = req.params;
// console.log("GET games/" + id); // console.log("GET games/" + id);
@ -2640,6 +2655,9 @@ const sendGame = async (req, res, game, error) => {
if (reduced.player) { if (reduced.player) {
delete reduced.player; delete reduced.player;
} }
if (reduced.ws) {
delete reduced.ws;
}
reducedGame.sessions[id] = reduced; reducedGame.sessions[id] = reduced;
/* Do not send session-id as those are secrets */ /* Do not send session-id as those are secrets */
@ -2658,29 +2676,48 @@ const sendGame = async (req, res, game, error) => {
console.error(error); console.error(error);
}); });
const player = session.player ? session.player : undefined; for (let id in game.sessions) {
if (player) { const target = game.sessions[id],
player.haveResources = player.wheat > 0 || useWS = target !== session,
player.brick > 0 || player = target.player ? target.player : undefined;
player.sheep > 0 ||
player.stone > 0 ||
player.wood > 0;
}
/* Strip out data that should not be shared with players */ if (player) {
delete reducedGame.developmentCards; player.haveResources = player.wheat > 0 ||
player.brick > 0 ||
const playerGame = Object.assign({}, reducedGame, { player.sheep > 0 ||
timestamp: Date.now(), player.stone > 0 ||
status: error ? error : "success", player.wood > 0;
name: session.name, }
color: session.color,
order: (session.color in game.players) ? game.players[session.color].order : 0, /* Strip out data that should not be shared with players */
player: player, delete reducedGame.developmentCards;
sessions: reducedSessions,
layout: layout const playerGame = Object.assign({}, reducedGame, {
}); timestamp: Date.now(),
return res.status(200).send(playerGame); status: error ? error : "success",
name: target.name,
color: target.color,
order: (target.color in game.players) ? game.players[target.color].order : 0,
player: player,
sessions: reducedSessions,
layout: layout
});
if (useWS) {
if (!target.ws) {
console.error(`No WebSocket connection to ${target.name}`);
} else {
console.log(`Sending update to ${target.name}`);
target.ws.send(JSON.stringify({
type: 'game-update',
update: playerGame
}));
}
} else {
console.log(`Returning update to ${target.name}`);
res.status(200).send(playerGame);
}
}
} }
const resetGame = (game) => { const resetGame = (game) => {