From b644ef7f0302dcb024e5214600d13883906faed0 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Thu, 24 Jan 2019 14:43:12 +0100
Subject: [PATCH] Arrange sockets.js (unimplemented yet)

---
 client/src/main.js               |   1 +
 server/app.js                    |   1 +
 server/config/parameters.js.dist |   2 +-
 server/sockets.js                | 263 ++++++++++++++++---------------
 4 files changed, 140 insertions(+), 127 deletions(-)

diff --git a/client/src/main.js b/client/src/main.js
index da3e6022..1fe69b2b 100644
--- a/client/src/main.js
+++ b/client/src/main.js
@@ -35,6 +35,7 @@ new Vue({
 			Vue.prototype.$variants = res.variantArray;
 		});
     Vue.prototype.$tr = {}; //to avoid a compiler error
+		// TODO: if there is a socket ID in localStorage, it means a live game was interrupted (and should resume)
 		const myid = localStorage["myid"] || util.getRandString();
 		// NOTE: in this version, we don't say on which page we are, yet
 		// ==> we'll say "enter/leave" page XY (in fact juste "enter", seemingly)
diff --git a/server/app.js b/server/app.js
index b1aee52c..d4aef286 100644
--- a/server/app.js
+++ b/server/app.js
@@ -4,6 +4,7 @@ var path = require('path');
 var cookieParser = require('cookie-parser');
 var logger = require('morgan');
 var favicon = require('serve-favicon');
+var params = require('./config/parameters');
 
 var app = express();
 
diff --git a/server/config/parameters.js.dist b/server/config/parameters.js.dist
index 0beabed0..2b0a6e7f 100644
--- a/server/config/parameters.js.dist
+++ b/server/config/parameters.js.dist
@@ -8,7 +8,7 @@ module.exports =
 	
 	// CORS: cross-origin resource sharing options
 	cors: {
-		enable: Parameters.env === "development",
+		enable: true,
 		allowedOrigin: "*",
 	},
 
diff --git a/server/sockets.js b/server/sockets.js
index 8a0614b1..4d15f331 100644
--- a/server/sockets.js
+++ b/server/sockets.js
@@ -1,5 +1,4 @@
 const url = require('url');
-const VariantModel = require("./models/Variant");
 
 // Node version in Ubuntu 16.04 does not know about URL class
 function getJsonFromUrl(url)
@@ -13,144 +12,156 @@ function getJsonFromUrl(url)
 	return result;
 }
 
+// Removal in array of strings (socket IDs)
+function remInArray(arr, item)
+{
+	const idx = arr.indexOf(item);
+	if (idx >= 0)
+		arr.splice(idx, 1);
+}
+
 // TODO: empêcher multi-log du même user (envoyer le user ID + secret en même temps que name et...)
 // --> si secret ne matche pas celui trouvé en DB, stop
-
-// TODO: this file in the end will be much simpler, just tracking connect/disconnect
+// TODO: this file "in the end" would be much simpler, essentially just tracking connect/disconnect
 // (everything else using WebRTC)
+// TODO: lorsque challenge accepté, seul le dernier joueur à accepter envoi message "please start game"
+// avec les coordonnées des participants. Le serveur renvoit alors les détails de la partie (couleurs, position)
+//TODO: programmatic re-navigation on current game if we receive a move and are not there
 
 module.exports = function(wss) {
-	VariantModel.getAll((err,variants) => {
-		let clients = { "index": {} };
-		let games = {}; //pending games (player sid)
-		for (const v of variants)
-			clients[v.id] = {};
-		// No-op function as a callback when sending messages
-		const noop = () => { };
-		wss.on("connection", (socket, req) => {
-//				const params = new URL("http://localhost" + req.url).searchParams;
-//				const sid = params.get("sid");
-//				const page = params.get("page");
-			var query = getJsonFromUrl(req.url);
-			const sid = query["sid"];
-			const page = query["page"];
-			// Ignore duplicate connections:
-			if (!!clients[page][sid])
-			{
-				socket.send(JSON.stringify({code:"duplicate"}));
-				return;
-			}
-			clients[page][sid] = socket;
-			if (page == "index")
+	let clients = {}; //associative array client sid --> {socket, curPath}
+	let pages = {}; //associative array path --> array of client sid
+	// No-op function as a callback when sending messages
+	const noop = () => { };
+	wss.on("connection", (socket, req) => {
+		const query = getJsonFromUrl(req.url);
+		const sid = query["sid"];
+		// Ignore duplicate connections (on the same live game that we play):
+		if (!!clients[sid])
+			return socket.send(JSON.stringify({code:"duplicate"}));
+		// We don't know yet on which page the user will be
+		clients[sid] = {socket: socket, path: ""};
+
+		socket.on("message", objtxt => {
+			let obj = JSON.parse(objtxt);
+			switch (obj.code)
 			{
-				// Send counting info
-				const countings = {};
-				for (const v of variants)
-					countings[v.id] = Object.keys(clients[v.id]).length;
-				socket.send(JSON.stringify({code:"counts",counts:countings}));
+				case "enter":
+					if (clients[sid].path.length > 0)
+						remInArray(pages[clients[sid].path], sid);
+					clients[sid].path = obj.path;
+					pages[obj.path].push(sid);
+					// TODO also: notify "old" sub-room that I left (if it was not index)
+					if (obj.path == "/")
+					{
+						// Send counting info
+						let countings = {};
+						Object.keys(pages).forEach(
+							path => { countings[path] = pages[path].length; });
+						socket.send(JSON.stringify({code:"counts",counts:countings}));
+					}
+					else
+					{
+						// Send to every client connected on index an update message for counts
+						pages["/"].forEach((id) => {
+							clients[id].socket.send(
+								JSON.stringify({code:"increase",path:obj.path}), noop);
+						});
+						// TODO: do not notify anything in rules and problems sections (no socket required)
+						// --> in fact only /Atomic (main hall) and inside a game: /Atomic/392f3ju
+						// Also notify the (sub-)room (including potential opponents):
+						Object.keys(clients[page]).forEach( k => {
+							clients[page][k].send(JSON.stringify({code:"connect",id:sid}), noop);
+						});
+						// Finally, receive (sub-)room composition
+						// TODO.
+					}
+// NOTE: no "leave" counterpart (because it's always to enter somewhere else)
+//				case "leave":
+//					break;
+				// Transmit chats and moves to current room
+				// TODO: WebRTC instead in this case (most demanding?)
+				case "newchat":
+					if (!!clients[page][obj.oppid])
+					{
+						clients[page][obj.oppid].send(
+							JSON.stringify({code:"newchat",msg:obj.msg}), noop);
+					}
+					break;
+				case "newmove":
+					if (!!clients[page][obj.oppid])
+					{
+						clients[page][obj.oppid].send(
+							JSON.stringify({code:"newmove",move:obj.move}), noop);
+					}
+					break;
+
+
+				// TODO: generalize that for several opponents
+				case "ping":
+					if (!!clients[page][obj.oppid])
+						socket.send(JSON.stringify({code:"pong",gameId:obj.gameId}));
+					break;
+				case "lastate":
+					if (!!clients[page][obj.oppid])
+					{
+						const oppId = obj.oppid;
+						obj.oppid = sid; //I'm oppid for my opponent
+						clients[page][oppId].send(JSON.stringify(obj), noop);
+					}
+					break;
+				// TODO: moreover, here, game info should be sent (through challenge; not stored here)
+				case "newgame":
+					if (!!games[page])
+					{
+						// Start a new game
+						const oppId = games[page]["id"];
+						const fen = games[page]["fen"];
+						const gameId = games[page]["gameid"];
+						delete games[page];
+						const mycolor = (Math.random() < 0.5 ? 'w' : 'b');
+						socket.send(JSON.stringify(
+							{code:"newgame",fen:fen,oppid:oppId,color:mycolor,gameid:gameId}));
+						if (!!clients[page][oppId])
+						{
+							clients[page][oppId].send(
+								JSON.stringify(
+									{code:"newgame",fen:fen,oppid:sid,color:mycolor=="w"?"b":"w",gameid:gameId}),
+								noop);
+						}
+					}
+					else
+						games[page] = {id:sid, fen:obj.fen, gameid:obj.gameid}; //wait for opponent
+					break;
+				case "cancelnewgame": //if a user cancel his seek
+					// TODO: just transmit event
+					//delete games[page];
+					break;
+				// TODO: also other challenge events
+				case "resign":
+					if (!!clients[page][obj.oppid])
+						clients[page][obj.oppid].send(JSON.stringify({code:"resign"}), noop);
+					break;
+				// TODO: case "challenge" (get ID) --> send to all, "acceptchallenge" (with ID) --> send to all, "cancelchallenge" --> send to all
+				// also, "sendgame" (give current game info, if any) --> to new connections, "sendchallenges" (same for challenges) --> to new connections
 			}
-			else
+		});
+		socket.on("close", () => {
+			delete clients[sid];
+			// TODO: carefully delete pages[.........]
+			// + adapt below:
+			if (page != "/")
 			{
 				// Send to every client connected on index an update message for counts
 				Object.keys(clients["index"]).forEach( k => {
 					clients["index"][k].send(
-						JSON.stringify({code:"increase",vid:page}), noop);
-				});
-				// Also notify potential opponents:
-				// hit all clients which check if sid corresponds
-				Object.keys(clients[page]).forEach( k => {
-					clients[page][k].send(JSON.stringify({code:"connect",id:sid}), noop);
-				});
-				socket.on("message", objtxt => {
-					let obj = JSON.parse(objtxt);
-					switch (obj.code)
-					{
-						case "newchat":
-							if (!!clients[page][obj.oppid])
-							{
-								clients[page][obj.oppid].send(
-									JSON.stringify({code:"newchat",msg:obj.msg}), noop);
-							}
-							break;
-						case "newmove":
-							if (!!clients[page][obj.oppid])
-							{
-								clients[page][obj.oppid].send(
-									JSON.stringify({code:"newmove",move:obj.move}), noop);
-							}
-							break;
-						case "ping":
-							if (!!clients[page][obj.oppid])
-								socket.send(JSON.stringify({code:"pong",gameId:obj.gameId}));
-							break;
-						case "myname":
-							// Reveal my username to opponent
-							if (!!clients[page][obj.oppid])
-							{
-								clients[page][obj.oppid].send(JSON.stringify({
-									code:"oppname", name:obj.name}));
-							}
-							break;
-						case "lastate":
-							if (!!clients[page][obj.oppid])
-							{
-								const oppId = obj.oppid;
-								obj.oppid = sid; //I'm oppid for my opponent
-								clients[page][oppId].send(JSON.stringify(obj), noop);
-							}
-							break;
-						case "newgame":
-							if (!!games[page])
-							{
-								// Start a new game
-								const oppId = games[page]["id"];
-								const fen = games[page]["fen"];
-								const gameId = games[page]["gameid"];
-								delete games[page];
-								const mycolor = (Math.random() < 0.5 ? 'w' : 'b');
-								socket.send(JSON.stringify(
-									{code:"newgame",fen:fen,oppid:oppId,color:mycolor,gameid:gameId}));
-								if (!!clients[page][oppId])
-								{
-									clients[page][oppId].send(
-										JSON.stringify(
-											{code:"newgame",fen:fen,oppid:sid,color:mycolor=="w"?"b":"w",gameid:gameId}),
-										noop);
-								}
-							}
-							else
-								games[page] = {id:sid, fen:obj.fen, gameid:obj.gameid}; //wait for opponent
-							break;
-						case "cancelnewgame": //if a user cancel his seek
-							delete games[page];
-							break;
-						case "resign":
-							if (!!clients[page][obj.oppid])
-								clients[page][obj.oppid].send(JSON.stringify({code:"resign"}), noop);
-							break;
-						// TODO: case "challenge" (get ID) --> send to all, "acceptchallenge" (with ID) --> send to all, "cancelchallenge" --> send to all
-						// also, "sendgame" (give current game info, if any) --> to new connections, "sendchallenges" (same for challenges) --> to new connections
-					}
+						JSON.stringify({code:"decrease",vid:page}), noop);
 				});
 			}
-			socket.on("close", () => {
-				delete clients[page][sid];
-				// Remove potential pending game
-				if (!!games[page] && games[page]["id"] == sid)
-					delete games[page];
-				if (page != "index")
-				{
-					// Send to every client connected on index an update message for counts
-					Object.keys(clients["index"]).forEach( k => {
-						clients["index"][k].send(
-							JSON.stringify({code:"decrease",vid:page}), noop);
-					});
-				}
-				// Also notify potential opponents:
-				// hit all clients which check if sid corresponds
-				Object.keys(clients[page]).forEach( k => {
-					clients[page][k].send(JSON.stringify({code:"disconnect",id:sid}), noop);
-				});
+			// Also notify potential opponents:
+			// hit all clients which check if sid corresponds
+			Object.keys(clients[page]).forEach( k => {
+				clients[page][k].send(JSON.stringify({code:"disconnect",id:sid}), noop);
 			});
 		});
 	});
-- 
2.44.0