1 const url
= require('url');
3 // Node version in Ubuntu 16.04 does not know about URL class
4 // NOTE: url is already transformed, without ?xxx=yyy... parts
5 function getJsonFromUrl(url
)
7 const query
= url
.substr(2); //starts with "/?"
9 query
.split("&").forEach((part
) => {
10 const item
= part
.split("=");
11 result
[item
[0]] = decodeURIComponent(item
[1]);
16 module
.exports = function(wss
) {
17 // Associative array page --> sid --> tmpId --> socket
18 // "page" is either "/" for hall or "/game/some_gid" for Game,
19 // tmpId is required if a same user (browser) has different tabs
21 wss
.on("connection", (socket
, req
) => {
22 const query
= getJsonFromUrl(req
.url
);
23 const sid
= query
["sid"];
24 const tmpId
= query
["tmpId"];
25 const page
= query
["page"];
26 const notifyRoom
= (page
,code
,obj
={}) => {
27 Object
.keys(clients
[page
]).forEach(k
=> {
28 Object
.keys(clients
[page
][k
]).forEach(x
=> {
29 if (k
== sid
&& x
== tmpId
)
31 clients
[page
][k
][x
].send(JSON
.stringify(Object
.assign(
32 {code:code
, from:sid
}, obj
)));
36 const deleteConnexion
= () => {
37 if (!clients
[page
] || !clients
[page
][sid
] || !clients
[page
][sid
][tmpId
])
38 return; //job already done
39 delete clients
[page
][sid
][tmpId
];
40 if (Object
.keys(clients
[page
][sid
]).length
== 0)
42 delete clients
[page
][sid
];
43 if (Object
.keys(clients
[page
]) == 0)
47 const messageListener
= (objtxt
) => {
48 let obj
= JSON
.parse(objtxt
);
51 // Check if receiver is connected, because there may be some lag
52 // between a client disconnects and another notice.
53 if (Array
.isArray(obj
.target
))
55 if (!clients
[page
][obj
.target
[0]] ||
56 !clients
[page
][obj
.target
[0]][obj
.target
[1]])
61 else if (!clients
[page
][obj
.target
])
66 // Wait for "connect" message to notify connection to the room,
67 // because if game loading is slow the message listener might
68 // not be ready too early.
71 notifyRoom(page
, "connect");
72 if (page
.indexOf("/game/") >= 0)
73 notifyRoom("/", "gconnect", {page:page
});
79 if (!clients
[page
][sid
])
81 // I effectively disconnected from this page:
82 notifyRoom(page
, "disconnect");
83 if (page
.indexOf("/game/") >= 0)
84 notifyRoom("/", "gdisconnect", {page:page
});
87 case "pollclients": //from Hall or Game
90 Object
.keys(clients
[page
]).forEach(k
=> {
91 // Poll myself if I'm on at least another tab (same page)
92 if (k
!= sid
|| Object
.keys(clients
["/"][k
]).length
>= 2)
95 socket
.send(JSON
.stringify({code:"pollclients", sockIds:sockIds
}));
98 case "pollclientsandgamers": //from Hall
101 Object
.keys(clients
["/"]).forEach(k
=> {
102 // Poll myself if I'm on at least another tab (same page)
103 if (k
!= sid
|| Object
.keys(clients
["/"][k
]).length
>= 2)
104 sockIds
.push({sid:k
});
106 // NOTE: a "gamer" could also just be an observer
107 Object
.keys(clients
).forEach(p
=> {
110 Object
.keys(clients
[p
]).forEach(k
=> {
112 sockIds
.push({sid:k
, page:p
}); //page needed for gamers
116 socket
.send(JSON
.stringify({code:"pollclientsandgamers", sockIds:sockIds
}));
120 // Asking something: from is fully identified,
121 // but the requested resource can be from any tmpId (except current!)
128 const tmpIds
= Object
.keys(clients
[page
][obj
.target
]);
129 if (obj
.target
== sid
) //targetting myself
131 const idx_myTmpid
= tmpIds
.findIndex(x
=> x
== tmpId
);
132 if (idx_myTmpid
>= 0)
133 tmpIds
.splice(idx_myTmpid
, 1);
135 const tmpId_idx
= Math
.floor(Math
.random() * tmpIds
.length
);
136 clients
[page
][obj
.target
][tmpIds
[tmpId_idx
]].send(
137 JSON
.stringify({code:obj
.code
, from:[sid
,tmpId
]}));
141 // Some Hall events: target all tmpId's (except mine),
142 case "refusechallenge":
144 Object
.keys(clients
[page
][obj
.target
]).forEach(x
=> {
145 if (obj
.target
!= sid
|| x
!= tmpId
)
147 clients
[page
][obj
.target
][x
].send(JSON
.stringify(
148 {code:obj
.code
, data:obj
.data
}));
153 // Notify all room: mostly game events
157 case "deletechallenge":
163 notifyRoom(page
, obj
.code
, {data:obj
.data
});
166 // Passing, relaying something: from isn't needed,
167 // but target is fully identified (sid + tmpId)
173 clients
[page
][obj
.target
[0]][obj
.target
[1]].send(JSON
.stringify(
174 {code:obj
.code
, data:obj
.data
}));
178 const closeListener
= () => {
179 // For tab or browser closing:
182 // Update clients object: add new connexion
184 clients
[page
] = {[sid
]: {[tmpId
]: socket
}};
185 else if (!clients
[page
][sid
])
186 clients
[page
][sid
] = {[tmpId
]: socket
};
188 clients
[page
][sid
][tmpId
] = socket
;
189 socket
.on("message", messageListener
);
190 socket
.on("close", closeListener
);