From 74fbb20db7ae89671f020a60e77f8d55ec17ee1f Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 17 May 2020 12:40:44 -0700 Subject: [PATCH] Incorporate empires.js as a sub-app within lmno.js Now, instead of calling listen() the empires.js simply exports its app object so that the higher level lmno server can mount all of its available paths with app.use('/empires//', empires.app). At the same time, empires.js no longer constructs a Game object, but instead the higher-level /new API within lmno.js calls into empires.Game to create a game for a specific ID. Then, there's also a new middleware in lmno.js to lookup this game object by the ID from the path and add it as a property of the request object. So all of the empires.js entry points now fetch that game object from the request as their first statement. --- empires.js | 19 ++++++++++++++----- lmno.js | 46 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/empires.js b/empires.js index b744f0f..20dfa78 100644 --- a/empires.js +++ b/empires.js @@ -207,12 +207,11 @@ class Game { } } -const game = new Game(); - app.use(body_parser.urlencoded({ extended: false })); app.use(body_parser.json()); function handle_events(request, response) { + const game = request.game; /* These headers will keep the connection open so we can stream events. */ const headers = { "Content-type": "text/event-stream", @@ -251,59 +250,69 @@ function handle_events(request, response) { } app.post('/register', (request, response) => { + const game = request.game; game.add_player(request.body.name, request.body.character); response.send(); }); app.post('/deregister/:id', (request, response) => { + const game = request.game; game.remove_player(parseInt(request.params.id)); response.send(); }); app.post('/reveal', (request, response) => { + const game = request.game; game.reveal(); response.send(); }); app.post('/start', (request, response) => { + const game = request.game; game.start(); response.send(); }); app.post('/reset', (request, response) => { + const game = request.game; game.reset(); response.send(); }); app.post('/capture/:captor/:captee', (request, response) => { + const game = request.game; game.capture(parseInt(request.params.captor), parseInt(request.params.captee)); response.send(); }); app.post('/liberate/:id', (request, response) => { + const game = request.game; game.liberate(parseInt(request.params.id)); response.send(); }); app.post('/restart', (request, response) => { + const game = request.game; game.restart(parseInt(request.params.id)); response.send(); }); app.get('/characters', (request, response) => { + const game = request.game; response.send(game.characters); }); app.get('/empires', (request, response) => { + const game = request.game; response.send(game.empires); }); app.get('/players', (request, response) => { + const game = request.game; response.send(game.players); }); app.get('/events', handle_events); -app.listen(3000, function () { - console.log('Empires server listening on localhost:3000'); -}); +exports.app = app; +exports.Game = Game; diff --git a/lmno.js b/lmno.js index dc23fc2..f79da3a 100644 --- a/lmno.js +++ b/lmno.js @@ -5,6 +5,9 @@ const body_parser = require("body-parser"); const app = express(); app.use(cors()); +/* Load each of our game mini-apps. */ +var empires = require("./empires"); + class LMNO { constructor() { this.ids = {}; @@ -19,14 +22,15 @@ class LMNO { var id = this.generate_id(); } while (id in this.ids); - const game = { + const game = new empires.Game(); + + this.ids[id] = { id: id, engine: engine, + game: game }; - this.ids[id] = game; - - return game; + return id; } } @@ -44,10 +48,40 @@ const lmno = new LMNO(); app.post('/new/:game_engine', (request, response) => { const game_engine = request.params.game_engine; - const game = lmno.create_game(game_engine); - response.send(JSON.stringify(game.id)); + const game_id = lmno.create_game(game_engine); + response.send(JSON.stringify(game_id)); }); +/* Redirect any requests to a game ID at the top-level. + * + * Specifically, after obtaining the game ID (from the path) we simply + * lookup the game engine for the corresponding game and then redirect + * to the engine- and game-specific path. + */ +app.get('/[a-zA-Z0-9]{4}', (request, response) => { + const game_id = request.path.replace(/\//g, ""); + + const game = lmno.ids[game_id]; + if (game === undefined) { + response.sendStatus(404); + return; + } + response.redirect(301, `/${game.engine}/${game.id}/`); +}); + +/* LMNO middleware to lookup the game. */ +app.use('/empires/:game_id([a-zA-Z0-9]{4})', (request, response, next) => { + request.game = lmno.ids[request.params.game_id].game; + if (request.game === undefined) { + response.sendStatus(404); + return; + } + next(); +}); + +/* Mount sub apps. only _after_ we have done all the middleware we need. */ +app.use('/empires/[a-zA-Z0-9]{4}/', empires.app); + app.listen(4000, function () { console.log('LMNO server listening on localhost:4000'); }); -- 2.43.0