Add some suggestions for icons (from feather or...)
[vchess.git] / server / sockets.js
1 const url = require('url');
2 const VariantModel = require("./models/Variant");
3
4 // Node version in Ubuntu 16.04 does not know about URL class
5 function getJsonFromUrl(url)
6 {
7 const query = url.substr(2); //starts with "/?"
8 let result = {};
9 query.split("&").forEach((part) => {
10 const item = part.split("=");
11 result[item[0]] = decodeURIComponent(item[1]);
12 });
13 return result;
14 }
15
16 // TODO: empêcher multi-log du même user (envoyer le user ID + secret en même temps que name et...)
17 // --> si secret ne matche pas celui trouvé en DB, stop
18
19 // TODO: this file in the end will be much simpler, just tracking connect/disconnect
20 // (everything else using WebRTC)
21
22 module.exports = function(wss) {
23 VariantModel.getAll((err,variants) => {
24 let clients = { "index": {} };
25 let games = {}; //pending games (player sid)
26 for (const v of variants)
27 clients[v.id] = {};
28 // No-op function as a callback when sending messages
29 const noop = () => { };
30 wss.on("connection", (socket, req) => {
31 // const params = new URL("http://localhost" + req.url).searchParams;
32 // const sid = params.get("sid");
33 // const page = params.get("page");
34 var query = getJsonFromUrl(req.url);
35 const sid = query["sid"];
36 const page = query["page"];
37 // Ignore duplicate connections:
38 if (!!clients[page][sid])
39 {
40 socket.send(JSON.stringify({code:"duplicate"}));
41 return;
42 }
43 clients[page][sid] = socket;
44 if (page == "index")
45 {
46 // Send counting info
47 const countings = {};
48 for (const v of variants)
49 countings[v.id] = Object.keys(clients[v.id]).length;
50 socket.send(JSON.stringify({code:"counts",counts:countings}));
51 }
52 else
53 {
54 // Send to every client connected on index an update message for counts
55 Object.keys(clients["index"]).forEach( k => {
56 clients["index"][k].send(
57 JSON.stringify({code:"increase",vid:page}), noop);
58 });
59 // Also notify potential opponents:
60 // hit all clients which check if sid corresponds
61 Object.keys(clients[page]).forEach( k => {
62 clients[page][k].send(JSON.stringify({code:"connect",id:sid}), noop);
63 });
64 socket.on("message", objtxt => {
65 let obj = JSON.parse(objtxt);
66 switch (obj.code)
67 {
68 case "newchat":
69 if (!!clients[page][obj.oppid])
70 {
71 clients[page][obj.oppid].send(
72 JSON.stringify({code:"newchat",msg:obj.msg}), noop);
73 }
74 break;
75 case "newmove":
76 if (!!clients[page][obj.oppid])
77 {
78 clients[page][obj.oppid].send(
79 JSON.stringify({code:"newmove",move:obj.move}), noop);
80 }
81 break;
82 case "ping":
83 if (!!clients[page][obj.oppid])
84 socket.send(JSON.stringify({code:"pong",gameId:obj.gameId}));
85 break;
86 case "myname":
87 // Reveal my username to opponent
88 if (!!clients[page][obj.oppid])
89 {
90 clients[page][obj.oppid].send(JSON.stringify({
91 code:"oppname", name:obj.name}));
92 }
93 break;
94 case "lastate":
95 if (!!clients[page][obj.oppid])
96 {
97 const oppId = obj.oppid;
98 obj.oppid = sid; //I'm oppid for my opponent
99 clients[page][oppId].send(JSON.stringify(obj), noop);
100 }
101 break;
102 case "newgame":
103 if (!!games[page])
104 {
105 // Start a new game
106 const oppId = games[page]["id"];
107 const fen = games[page]["fen"];
108 const gameId = games[page]["gameid"];
109 delete games[page];
110 const mycolor = (Math.random() < 0.5 ? 'w' : 'b');
111 socket.send(JSON.stringify(
112 {code:"newgame",fen:fen,oppid:oppId,color:mycolor,gameid:gameId}));
113 if (!!clients[page][oppId])
114 {
115 clients[page][oppId].send(
116 JSON.stringify(
117 {code:"newgame",fen:fen,oppid:sid,color:mycolor=="w"?"b":"w",gameid:gameId}),
118 noop);
119 }
120 }
121 else
122 games[page] = {id:sid, fen:obj.fen, gameid:obj.gameid}; //wait for opponent
123 break;
124 case "cancelnewgame": //if a user cancel his seek
125 delete games[page];
126 break;
127 case "resign":
128 if (!!clients[page][obj.oppid])
129 clients[page][obj.oppid].send(JSON.stringify({code:"resign"}), noop);
130 break;
131 // TODO: case "challenge" (get ID) --> send to all, "acceptchallenge" (with ID) --> send to all, "cancelchallenge" --> send to all
132 // also, "sendgame" (give current game info, if any) --> to new connections, "sendchallenges" (same for challenges) --> to new connections
133 }
134 });
135 }
136 socket.on("close", () => {
137 delete clients[page][sid];
138 // Remove potential pending game
139 if (!!games[page] && games[page]["id"] == sid)
140 delete games[page];
141 if (page != "index")
142 {
143 // Send to every client connected on index an update message for counts
144 Object.keys(clients["index"]).forEach( k => {
145 clients["index"][k].send(
146 JSON.stringify({code:"decrease",vid:page}), noop);
147 });
148 }
149 // Also notify potential opponents:
150 // hit all clients which check if sid corresponds
151 Object.keys(clients[page]).forEach( k => {
152 clients[page][k].send(JSON.stringify({code:"disconnect",id:sid}), noop);
153 });
154 });
155 });
156 });
157 }