+ switch (data.code) {
+ case "pollclientsandgamers": {
+ // Since people can be both in Hall and Game,
+ // need to track "askIdentity" requests:
+ let identityAsked = {};
+ data.sockIds.forEach(s => {
+ const page = s.page || "/";
+ if (s.sid != this.st.user.sid && !identityAsked[s.sid]) {
+ this.send("askidentity", { target: s.sid, page: page });
+ identityAsked[s.sid] = true;
+ }
+ if (!this.people[s.sid]) {
+ // Do not set name or id: identity unknown yet
+ this.people[s.sid] = { pages: [{path: page, focus: true}] };
+ }
+ else if (!(this.people[s.sid].pages.find(p => p.path == page)))
+ this.people[s.sid].pages.push({ path: page, focus: true });
+ if (!s.page)
+ // Peer is in Hall
+ this.send("askchallenge", { target: s.sid });
+ // Peer is in Game
+ else this.send("askgame", { target: s.sid, page: page });
+ });
+ break;
+ }
+ case "connect":
+ case "gconnect": {
+ const page = data.page || "/";
+ // Only ask game / challenge if first connexion:
+ if (!this.people[data.from]) {
+ this.people[data.from] = { pages: [{ path: page, focus: true }] };
+ if (data.code == "connect")
+ this.send("askchallenge", { target: data.from });
+ else this.send("askgame", { target: data.from, page: page });
+ } else {
+ // Append page if not already in list
+ if (!(this.people[data.from].pages.find(p => p.path == page)))
+ this.people[data.from].pages.push({ path: page, focus: true });
+ }
+ if (!this.people[data.from].name && this.people[data.from].id !== 0) {
+ // Identity not known yet
+ this.newConnect[data.from] = true; //for self multi-connects tests
+ this.send("askidentity", { target: data.from, page: page });
+ }
+ break;
+ }
+ case "disconnect":
+ case "gdisconnect": {
+ // If the user reloads the page twice very quickly (experienced with Firefox),
+ // the first reload won't have time to connect but will trigger a "close" event anyway.
+ // ==> Next check is required.
+ if (!this.people[data.from]) return;
+ // Disconnect means no more tmpIds:
+ if (data.code == "disconnect") {
+ // Remove the live challenge sent by this player:
+ ArrayFun.remove(
+ this.challenges,
+ c => c.type == "live" && c.from.sid == data.from
+ );
+ } else {
+ // Remove the matching live game if now unreachable
+ const gid = data.page.match(/[a-zA-Z0-9]+$/)[0];
+ const gidx = this.games.findIndex(g => g.id == gid);
+ if (gidx >= 0) {
+ const game = this.games[gidx];
+ if (
+ game.type == "live" &&
+ game.rids.length == 1 &&
+ game.rids[0] == data.from
+ ) {
+ this.games.splice(gidx, 1);
+ }
+ }
+ }
+ const page = data.page || "/";
+ ArrayFun.remove(this.people[data.from].pages, p => p.path == page);
+ if (this.people[data.from].pages.length == 0)
+ this.$delete(this.people, data.from);
+ break;
+ }
+ case "getfocus":
+ // If user reload a page, focus may arrive earlier than connect
+ if (!!this.people[data.from]) {
+ this.people[data.from].pages
+ .find(p => p.path == data.page).focus = true;
+ this.$forceUpdate(); //TODO: shouldn't be required
+ }
+ break;
+ case "losefocus":
+ if (!!this.people[data.from]) {
+ this.people[data.from].pages
+ .find(p => p.path == data.page).focus = false;
+ this.$forceUpdate(); //TODO: shouldn't be required
+ }
+ break;
+ case "killed":
+ // I logged in elsewhere:
+ this.conn = null;
+ alert(this.st.tr["New connexion detected: tab now offline"]);
+ break;
+ case "askidentity": {
+ // Request for identification (TODO: anonymous shouldn't need to reply)
+ const me = {
+ // Decompose to avoid revealing email
+ name: this.st.user.name,
+ sid: this.st.user.sid,
+ id: this.st.user.id
+ };
+ this.send("identity", { data: me, target: data.from });
+ break;
+ }
+ case "identity": {
+ const user = data.data;
+ let player = this.people[user.sid];
+ // player.pages is already set
+ player.id = user.id;
+ player.name = user.name;
+ // TODO: this.$set(people, ...) fails. So forceUpdate.
+ // But this shouldn't be like that!
+ this.$forceUpdate();
+ // If I multi-connect, kill current connexion if no mark (I'm older)
+ if (this.newConnect[user.sid]) {
+ if (
+ user.id > 0 &&
+ user.id == this.st.user.id &&
+ user.sid != this.st.user.sid &&
+ !this.killed[this.st.user.sid]
+ ) {
+ this.send("killme", { sid: this.st.user.sid });
+ this.killed[this.st.user.sid] = true;
+ }
+ delete this.newConnect[user.sid];
+ }
+ break;
+ }
+ case "askchallenge": {
+ // Send my current live challenge (if any)
+ const cIdx = this.challenges.findIndex(
+ c => c.from.sid == this.st.user.sid && c.type == "live"
+ );
+ if (cIdx >= 0) {
+ const c = this.challenges[cIdx];
+ // NOTE: in principle, should only send targeted challenge to the target.
+ // But we may not know yet the identity of the target (just name),
+ // so cannot decide if data.from is the target or not.
+ const myChallenge = {
+ id: c.id,
+ from: this.st.user.sid,
+ to: c.to,
+ randomness: c.randomness,
+ fen: c.fen,
+ vid: c.vid,
+ cadence: c.cadence,
+ added: c.added
+ };
+ this.send("challenge", { data: myChallenge, target: data.from });
+ }
+ break;
+ }
+ case "challenge": //after "askchallenge"
+ case "newchallenge": {
+ // NOTE about next condition: see "askchallenge" case.
+ const chall = data.data;
+ if (
+ !chall.to ||
+ (this.people[chall.from].id > 0 &&
+ (chall.from == this.st.user.sid || chall.to == this.st.user.name))
+ ) {
+ let newChall = Object.assign({}, chall);
+ newChall.type = this.classifyObject(chall);
+ newChall.randomness = chall.randomness;
+ newChall.added = Date.now();
+ let fromValues = Object.assign({}, this.people[chall.from]);
+ delete fromValues["pages"]; //irrelevant in this context
+ newChall.from = Object.assign({ sid: chall.from }, fromValues);
+ newChall.vname = this.getVname(newChall.vid);
+ this.challenges.push(newChall);
+ if (
+ (newChall.type == "live" && this.cdisplay == "corr") ||
+ (newChall.type == "corr" && this.cdisplay == "live")
+ ) {
+ document
+ .getElementById("btnC" + newChall.type)
+ .classList.add("somethingnew");
+ }
+ }