Commit | Line | Data |
---|---|---|
a29d9d6b | 1 | const url = require('url'); |
1d184b4c | 2 | |
2807f530 | 3 | // Node version in Ubuntu 16.04 does not know about URL class |
98db2082 BA |
4 | function getJsonFromUrl(url) |
5 | { | |
80ee5d5a BA |
6 | const query = url.substr(2); //starts with "/?" |
7 | let result = {}; | |
8 | query.split("&").forEach((part) => { | |
5bd05dba BA |
9 | const item = part.split("="); |
10 | result[item[0]] = decodeURIComponent(item[1]); | |
11 | }); | |
12 | return result; | |
2807f530 BA |
13 | } |
14 | ||
1d184b4c | 15 | module.exports = function(wss) { |
5bd05dba BA |
16 | let clients = {}; //associative array sid --> socket |
17 | wss.on("connection", (socket, req) => { | |
18 | const query = getJsonFromUrl(req.url); | |
19 | const sid = query["sid"]; | |
5bd05dba BA |
20 | if (!!clients[sid]) |
21 | return socket.send(JSON.stringify({code:"duplicate"})); | |
92a523d1 | 22 | clients[sid] = {sock: socket, page: query["page"]}; |
c6788ecf | 23 | const notifyRoom = (page,code,obj={},excluded=[]) => { |
92a523d1 | 24 | Object.keys(clients).forEach(k => { |
c6788ecf BA |
25 | if (k in excluded) |
26 | return; | |
92a523d1 | 27 | if (k != sid && clients[k].page == page) |
5c8e044f BA |
28 | { |
29 | clients[k].sock.send(JSON.stringify(Object.assign( | |
c6788ecf | 30 | {code:code, from:sid}, obj))); |
5c8e044f | 31 | } |
92a523d1 BA |
32 | }); |
33 | }; | |
c6788ecf | 34 | notifyRoom(query["page"], "connect"); //Hall or Game |
bcaa8c00 BA |
35 | if (query["page"].indexOf("/game/") >= 0) |
36 | notifyRoom("/", "connect"); //notify main hall | |
5a3da968 | 37 | socket.on("message", objtxt => { |
5bd05dba | 38 | let obj = JSON.parse(objtxt); |
5a3da968 | 39 | if (!!obj.target && !clients[obj.target]) |
b4d619d1 | 40 | return; //receiver not connected, nothing we can do |
5bd05dba BA |
41 | switch (obj.code) |
42 | { | |
81d9ce72 | 43 | case "pollclients": |
f41ce580 | 44 | const curPage = clients[sid].page; |
81d9ce72 | 45 | socket.send(JSON.stringify({code:"pollclients", |
c6788ecf BA |
46 | sockIds: Object.keys(clients).filter(k => k != sid && |
47 | (clients[k].page == curPage || | |
48 | // Consider that people playing are in Hall too: | |
49 | (curPage == "/" && clients[k].page.indexOf("/game/") >= 0)) | |
50 | )})); | |
92a523d1 BA |
51 | break; |
52 | case "pagechange": | |
c6788ecf | 53 | notifyRoom(clients[sid].page, "disconnect"); |
bcaa8c00 BA |
54 | if (clients[sid].page.indexOf("/game/") >= 0) |
55 | notifyRoom("/", "disconnect"); | |
92a523d1 | 56 | clients[sid].page = obj.page; |
c6788ecf | 57 | notifyRoom(obj.page, "connect"); |
bcaa8c00 BA |
58 | if (obj.page.indexOf("/game/") >= 0) |
59 | notifyRoom("/", "connect"); | |
5a3da968 BA |
60 | break; |
61 | case "askidentity": | |
f41ce580 BA |
62 | clients[obj.target].sock.send(JSON.stringify( |
63 | {code:"askidentity",from:sid})); | |
81d9ce72 | 64 | break; |
dd75774d | 65 | case "askchallenge": |
f41ce580 BA |
66 | clients[obj.target].sock.send(JSON.stringify( |
67 | {code:"askchallenge",from:sid})); | |
81d9ce72 | 68 | break; |
cd0d7743 | 69 | case "askgames": |
dc284d90 | 70 | { |
c6788ecf | 71 | // Check all clients playing, and send them a "askgame" message |
dc284d90 BA |
72 | let gameSids = {}; //game ID --> [sid1, sid2] |
73 | const regexpGid = /\/[a-zA-Z0-9]+$/; | |
c6788ecf BA |
74 | Object.keys(clients).forEach(k => { |
75 | if (k != sid && clients[k].page.indexOf("/game/") >= 0) | |
76 | { | |
dc284d90 BA |
77 | const gid = clients[k].page.match(regexpGid)[0]; |
78 | if (!gameSids[gid]) | |
79 | gameSids[gid] = [k]; | |
80 | else | |
81 | gameSids[gid].push(k); | |
c6788ecf BA |
82 | } |
83 | }); | |
dc284d90 BA |
84 | // Request only one client out of 2 (TODO: this is a bit heavy) |
85 | // Alt: ask game to all, and filter later? | |
86 | Object.keys(gameSids).forEach(gid => { | |
87 | const L = gameSids[gid].length; | |
88 | const idx = L > 1 | |
89 | ? Math.floor(Math.random() * Math.floor(L)) | |
90 | : 0; | |
91 | const rid = gameSids[gid][idx]; | |
92 | clients[rid].sock.send(JSON.stringify( | |
ab6f48ea | 93 | {code:"askgame", from: sid})); |
dc284d90 BA |
94 | }); |
95 | break; | |
96 | } | |
97 | case "askfullgame": | |
98 | clients[obj.target].sock.send(JSON.stringify( | |
99 | {code:"askfullgame", from:sid})); | |
100 | break; | |
101 | case "fullgame": | |
102 | clients[obj.target].sock.send(JSON.stringify( | |
103 | {code:"fullgame", game:obj.game})); | |
5a3da968 BA |
104 | break; |
105 | case "identity": | |
f41ce580 BA |
106 | clients[obj.target].sock.send(JSON.stringify( |
107 | {code:"identity",user:obj.user})); | |
4d64881e | 108 | break; |
5bd05dba | 109 | case "refusechallenge": |
f41ce580 BA |
110 | clients[obj.target].sock.send(JSON.stringify( |
111 | {code:"refusechallenge", cid:obj.cid, from:sid})); | |
5bd05dba | 112 | break; |
98f48579 | 113 | case "deletechallenge": |
f41ce580 BA |
114 | clients[obj.target].sock.send(JSON.stringify( |
115 | {code:"deletechallenge", cid:obj.cid, from:sid})); | |
98f48579 | 116 | break; |
a6bddfc6 | 117 | case "newgame": |
92a523d1 | 118 | clients[obj.target].sock.send(JSON.stringify( |
5bd05dba | 119 | {code:"newgame", gameInfo:obj.gameInfo, cid:obj.cid})); |
a6bddfc6 | 120 | break; |
42c15a75 | 121 | case "challenge": |
92a523d1 | 122 | clients[obj.target].sock.send(JSON.stringify( |
42c15a75 BA |
123 | {code:"challenge", chall:obj.chall, from:sid})); |
124 | break; | |
dd75774d | 125 | case "game": |
c6788ecf BA |
126 | if (!!obj.target) |
127 | { | |
128 | clients[obj.target].sock.send(JSON.stringify( | |
80ee5d5a | 129 | {code:"game", game:obj.game, from:sid})); |
c6788ecf BA |
130 | } |
131 | else | |
132 | { | |
133 | // Notify all room except opponent and me: | |
80ee5d5a | 134 | notifyRoom("/", "game", {game:obj.game}, [obj.oppsid]); |
c6788ecf | 135 | } |
4d64881e | 136 | break; |
5bd05dba | 137 | case "newchat": |
c97830ea BA |
138 | // WARNING: do not use query["page"], because the page may change |
139 | notifyRoom(clients[sid].page, "newchat", | |
140 | {msg: obj.msg, name: obj.name}); | |
5bd05dba | 141 | break; |
5bd05dba BA |
142 | // TODO: WebRTC instead in this case (most demanding?) |
143 | case "newmove": | |
f41ce580 | 144 | clients[obj.target].sock.send(JSON.stringify( |
c6788ecf | 145 | {code:"newmove", move:obj.move})); |
5bd05dba BA |
146 | break; |
147 | case "lastate": | |
f41ce580 BA |
148 | clients[obj.target].sock.send(JSON.stringify( |
149 | {code:"lastate", state:obj.state})); | |
5bd05dba | 150 | break; |
5bd05dba | 151 | case "resign": |
f41ce580 | 152 | clients[obj.target].sock.send(JSON.stringify( |
3837d4f7 | 153 | {code:"resign", side:obj.side})); |
5bd05dba | 154 | break; |
b988c726 | 155 | case "abort": |
f41ce580 | 156 | clients[obj.target].sock.send(JSON.stringify( |
3837d4f7 | 157 | {code:"abort"})); |
b988c726 | 158 | break; |
2cc10cdb | 159 | case "drawoffer": |
f41ce580 BA |
160 | clients[obj.target].sock.send(JSON.stringify( |
161 | {code:"drawoffer"})); | |
2cc10cdb BA |
162 | break; |
163 | case "draw": | |
f41ce580 BA |
164 | clients[obj.target].sock.send(JSON.stringify( |
165 | {code:"draw"})); | |
2cc10cdb | 166 | break; |
5bd05dba BA |
167 | } |
168 | }); | |
169 | socket.on("close", () => { | |
92a523d1 | 170 | const page = clients[sid].page; |
5bd05dba | 171 | delete clients[sid]; |
92a523d1 | 172 | notifyRoom(page, "disconnect"); |
bcaa8c00 BA |
173 | if (page.indexOf("/game/") >= 0) |
174 | notifyRoom("/", "disconnect"); //notify main hall | |
5bd05dba BA |
175 | }); |
176 | }); | |
1d184b4c | 177 | } |