+ case "mdisconnect":
+ ArrayFun.remove(this.onMygames, sid => sid == data.from);
+ break;
+ case "getfocus": {
+ let player = this.people[data.from];
+ if (!!player) {
+ player.focus = true;
+ this.$forceUpdate(); //TODO: shouldn't be required
+ }
+ break;
+ }
+ case "losefocus": {
+ let player = this.people[data.from];
+ if (!!player) {
+ player.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
+ 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.focus is already set
+ player.name = user.name;
+ player.id = user.id;
+ this.$forceUpdate(); //TODO: shouldn't be required
+ // 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];
+ }
+ if (!this.killed[this.st.user.sid]) {
+ // Ask potentially missed last state, if opponent and I play
+ if (
+ !!this.game.mycolor &&
+ this.game.type == "live" &&
+ this.game.score == "*" &&
+ this.game.players.some(p => p.sid == user.sid)
+ ) {
+ this.send("asklastate", { target: user.sid });
+ let counter = 1;
+ this.askLastate = setInterval(
+ () => {
+ // Ask at most 3 times:
+ // if no reply after that there should be a network issue.
+ if (
+ counter < 3 &&
+ !this.gotLastate &&
+ !!this.people[user.sid]
+ ) {
+ this.send("asklastate", { target: user.sid });
+ counter++;
+ } else {
+ clearInterval(this.askLastate);
+ }
+ },
+ 1500
+ );
+ }
+ }
+ break;
+ }
+ case "askgame":
+ // Send current (live) game if not asked by any of the players
+ if (
+ this.game.type == "live" &&
+ this.game.players.every(p => p.sid != data.from[0])
+ ) {
+ const myGame = {
+ id: this.game.id,
+ fen: this.game.fen,
+ players: this.game.players,
+ vid: this.game.vid,
+ cadence: this.game.cadence,
+ score: this.game.score,
+ rid: this.st.user.sid //useful in Hall if I'm an observer
+ };
+ this.send("game", { data: myGame, target: data.from });
+ }
+ break;
+ case "askfullgame":
+ const gameToSend = Object.keys(this.game)
+ .filter(k =>
+ [
+ "id","fen","players","vid","cadence","fenStart","vname",
+ "moves","clocks","initime","score","drawOffer"
+ ].includes(k))
+ .reduce(
+ (obj, k) => {
+ obj[k] = this.game[k];
+ return obj;
+ },
+ {}
+ );
+ this.send("fullgame", { data: gameToSend, target: data.from });
+ break;
+ case "fullgame":
+ // Callback "roomInit" to poll clients only after game is loaded
+ this.loadGame(data.data, this.roomInit);
+ break;
+ case "asklastate":
+ // Sending informative last state if I played a move or score != "*"
+ if (
+ (this.game.moves.length > 0 && this.vr.turn != this.game.mycolor) ||
+ this.game.score != "*" ||
+ this.drawOffer == "sent"
+ ) {