On the way to multi-tabs support
[vchess.git] / client / src / views / Hall.vue
index fbd5e28..e53dd56 100644 (file)
@@ -78,6 +78,7 @@ import { store } from "@/store";
 import { checkChallenge } from "@/data/challengeCheck";
 import { ArrayFun } from "@/utils/array";
 import { ajax } from "@/utils/ajax";
+import params from "@/parameters";
 import { getRandString, shuffle } from "@/utils/alea";
 import Chat from "@/components/Chat.vue";
 import GameList from "@/components/GameList.vue";
@@ -109,6 +110,9 @@ export default {
         timeControl: localStorage.getItem("timeControl") || "",
       },
       newChat: "",
+      conn: null,
+      page: "",
+      tempId: "", //to distinguish several tabs
     };
   },
   watch: {
@@ -135,21 +139,8 @@ export default {
   created: function() {
     // Always add myself to players' list
     const my = this.st.user;
-    this.$set(this.people, my.sid, {id:my.id, name:my.name});
-    // Retrieve live challenge (not older than 30 minute) if any:
-    const chall = JSON.parse(localStorage.getItem("challenge") || "false");
-    if (!!chall)
-    {
-      // NOTE: a challenge survives 3 minutes, for potential connection issues
-      if ((Date.now() - chall.added)/1000 <= 3*60)
-      {
-        chall.added = Date.now(); //update added time, for next disconnect...
-        this.challenges.push(chall);
-        localStorage.setItem("challenge", JSON.stringify(chall));
-      }
-      else
-        localStorage.removeItem("challenge");
-    }
+    this.tempId = getRandString();
+    this.$set(this.people, my.sid, {id:my.id, name:my.name, tmpId: [this.tempId]});
     // Ask server for current corr games (all but mines)
     ajax(
       "/games",
@@ -213,23 +204,25 @@ export default {
     );
     // 0.1] Ask server for room composition:
     const funcPollClients = () => {
-      // Same strategy as in Game.vue: send connection
-      // after we're sure WebSocket is initialized
-      this.st.conn.send(JSON.stringify({code:"connect"}));
-      this.st.conn.send(JSON.stringify({code:"pollclients"}));
-      this.st.conn.send(JSON.stringify({code:"pollgamers"}));
+      this.conn.send(JSON.stringify({code:"connect"}));
+      this.conn.send(JSON.stringify({code:"pollclients"}));
+      this.conn.send(JSON.stringify({code:"pollgamers"}));
     };
-    if (!!this.st.conn && this.st.conn.readyState == 1) //1 == OPEN state
-      funcPollClients();
-    else //socket not ready yet (initial loading)
-      this.st.conn.onopen = funcPollClients;
-    this.st.conn.onmessage = this.socketMessageListener;
+    // Initialize connection
+    this.page = this.$route.path;
+    const connexionString = params.socketUrl +
+      "/?sid=" + this.st.user.sid +
+      "&tmpId=" + this.tempId +
+      "&page=" + encodeURIComponent(this.page);
+    this.conn = new WebSocket(connexionString);
+    this.conn.onopen = funcPollClients;
+    this.conn.onmessage = this.socketMessageListener;
     const socketCloseListener = () => {
-      store.socketCloseListener(); //reinitialize connexion (in store.js)
-      this.st.conn.addEventListener('message', this.socketMessageListener);
-      this.st.conn.addEventListener('close', socketCloseListener);
+      this.conn = new WebSocket(connexionString);
+      this.conn.addEventListener('message', this.socketMessageListener);
+      this.conn.addEventListener('close', socketCloseListener);
     };
-    this.st.conn.onclose = socketCloseListener;
+    this.conn.onclose = socketCloseListener;
   },
   mounted: function() {
     [document.getElementById("infoDiv"),document.getElementById("newgameDiv")]
@@ -240,6 +233,9 @@ export default {
       )}
     );
   },
+  beforeDestroy: function() {
+    this.conn.send(JSON.stringify({code:"disconnect",page:this.page}));
+  },
   methods: {
     // Helpers:
     filterChallenges: function(type) {
@@ -274,11 +270,11 @@ export default {
     },
     processChat: function(chat) {
       // When received on server, this will trigger a "notifyRoom"
-      this.st.conn.send(JSON.stringify({code:"newchat", chat: chat}));
+      this.conn.send(JSON.stringify({code:"newchat", chat: chat}));
     },
     sendSomethingTo: function(to, code, obj, warnDisconnected) {
       const doSend = (code, obj, sid) => {
-        this.st.conn.send(JSON.stringify(Object.assign(
+        this.conn.send(JSON.stringify(Object.assign(
           {code: code},
           obj,
           {target: sid}
@@ -307,7 +303,7 @@ export default {
           if (!targetSid)
           {
             if (!!warnDisconnected)
-              alert(this.st.tr["Warning: target is not connected"]);
+              alert(this.st.tr["Target is not connected"]);
             return false;
           }
         }
@@ -321,15 +317,17 @@ export default {
       switch (data.code)
       {
         case "duplicate":
-          alert(this.st.tr["Warning: multi-tabs not supported"]);
+          this.conn.send(JSON.stringify({code:"duplicate", page:"/"}));
+          this.conn.send = () => {};
+          alert(this.st.tr["This tab is now offline"]);
           break;
         // 0.2] Receive clients list (just socket IDs)
         case "pollclients":
           data.sockIds.forEach(sid => {
             this.$set(this.people, sid, {id:0, name:""});
             // Ask identity and challenges
-            this.st.conn.send(JSON.stringify({code:"askidentity", target:sid}));
-            this.st.conn.send(JSON.stringify({code:"askchallenge", target:sid}));
+            this.conn.send(JSON.stringify({code:"askidentity", target:sid}));
+            this.conn.send(JSON.stringify({code:"askchallenge", target:sid}));
           });
           break;
         case "pollgamers":
@@ -337,17 +335,16 @@ export default {
           // and gamers, but is it necessary?
           data.sockIds.forEach(sid => {
             this.$set(this.people, sid, {id:0, name:"", gamer:true});
-            this.st.conn.send(JSON.stringify({code:"askidentity", target:sid}));
+            this.conn.send(JSON.stringify({code:"askidentity", target:sid}));
           });
           // Also ask current games to all playing peers (TODO: some design issue)
-          this.st.conn.send(JSON.stringify({code:"askgames"}));
+          this.conn.send(JSON.stringify({code:"askgames"}));
           break;
         case "askidentity":
-        {
           // Request for identification: reply if I'm not anonymous
           if (this.st.user.id > 0)
           {
-            this.st.conn.send(JSON.stringify({code:"identity",
+            this.conn.send(JSON.stringify({code:"identity",
               user: {
                 // NOTE: decompose to avoid revealing email
                 name: this.st.user.name,
@@ -357,9 +354,7 @@ export default {
               target:data.from}));
           }
           break;
-        }
         case "identity":
-        {
           this.$set(this.people, data.user.sid,
             {
               id: data.user.id,
@@ -367,7 +362,6 @@ export default {
               gamer: this.people[data.user.sid].gamer,
             });
           break;
-        }
         case "askchallenge":
         {
           // Send my current live challenge (if any)
@@ -398,13 +392,12 @@ export default {
               timeControl: c.timeControl,
               added: c.added,
             };
-            this.st.conn.send(JSON.stringify({code:"challenge",
+            this.conn.send(JSON.stringify({code:"challenge",
               chall:myChallenge, target:data.from}));
           }
           break;
         }
         case "challenge":
-        {
           // Receive challenge from some player (+sid)
           // NOTE about next condition: see "askchallenge" case.
           if (!data.chall.to || data.chall.to == this.st.user.name)
@@ -417,7 +410,6 @@ export default {
             this.challenges.push(newChall);
           }
           break;
-        }
         case "game":
         {
           // Receive game from some player (+sid)
@@ -442,7 +434,6 @@ export default {
           break;
         }
         case "newgame":
-        {
           // New game just started: data contain all information
           if (this.classifyObject(data.gameInfo) == "live")
             this.startNewGame(data.gameInfo);
@@ -456,32 +447,25 @@ export default {
             setTimeout(() => { modalBox.checked = false; }, 3000);
           }
           break;
-        }
         case "newchat":
           this.newChat = data.chat;
           break;
         case "refusechallenge":
-        {
           ArrayFun.remove(this.challenges, c => c.id == data.cid);
-          localStorage.removeItem("challenge");
           alert(this.st.tr["Challenge declined"]);
           break;
-        }
         case "deletechallenge":
-        {
           // NOTE: the challenge may be already removed
           ArrayFun.remove(this.challenges, c => c.id == data.cid);
-          localStorage.removeItem("challenge"); //in case of
           break;
-        }
         case "connect":
         case "gconnect":
           this.$set(this.people, data.from, {name:"", id:0, gamer:data.code[0]=='g'});
-          this.st.conn.send(JSON.stringify({code:"askidentity", target:data.from}));
+          this.conn.send(JSON.stringify({code:"askidentity", target:data.from}));
           if (data.code == "connect")
-            this.st.conn.send(JSON.stringify({code:"askchallenge", target:data.from}));
+            this.conn.send(JSON.stringify({code:"askchallenge", target:data.from}));
           else
-            this.st.conn.send(JSON.stringify({code:"askgame", target:data.from}));
+            this.conn.send(JSON.stringify({code:"askgame", target:data.from}));
           break;
         case "disconnect":
         case "gdisconnect":
@@ -509,17 +493,18 @@ export default {
       this.newchallenge.to = this.people[sid].name;
       doClick("modalNewgame");
     },
-    challOrWatch: function(sid, e) {
-      switch (e.target.innerHTML)
+    challOrWatch: function(sid) {
+      if (!this.people[sid].gamer)
       {
-        case "Available":
-          this.tryChallenge(sid);
-          break;
-        case "Playing":
-          this.showGame(this.games.find(
-            g => g.players.some(pl => pl.sid == sid || pl.uid == this.people[sid].id)));
-          break;
-      };
+        // Available, in Hall
+        this.tryChallenge(sid);
+      }
+      else
+      {
+        // Playing, in Game
+        this.showGame(this.games.find(
+          g => g.players.some(pl => pl.sid == sid || pl.uid == this.people[sid].id)));
+      }
     },
     newChallenge: async function() {
       if (this.newchallenge.vid == "")
@@ -575,9 +560,7 @@ export default {
           name: this.st.user.name,
         };
         this.challenges.push(chall);
-        if (ctype == "live")
-          localStorage.setItem("challenge", JSON.stringify(chall));
-        // Also remember timeControl  + vid for quicker further challenges:
+        // Remember timeControl  + vid for quicker further challenges:
         localStorage.setItem("timeControl", chall.timeControl);
         localStorage.setItem("vid", chall.vid);
         document.getElementById("modalNewgame").checked = false;
@@ -622,7 +605,7 @@ export default {
         }
         else
         {
-          this.st.conn.send(JSON.stringify({
+          this.conn.send(JSON.stringify({
             code: "refusechallenge",
             cid: c.id, target: c.from.sid}));
         }
@@ -638,8 +621,6 @@ export default {
             {id: c.id}
           );
         }
-        else //live
-          localStorage.removeItem("challenge");
         this.sendSomethingTo({name:c.to}, "deletechallenge", {cid:c.id});
       }
       // In all cases, the challenge is consumed:
@@ -668,7 +649,7 @@ export default {
       const tryNotifyOpponent = () => {
         if (!!oppsid) //opponent is online
         {
-          this.st.conn.send(JSON.stringify({code:"newgame",
+          this.conn.send(JSON.stringify({code:"newgame",
             gameInfo:gameInfo, target:oppsid, cid:c.id}));
         }
       };
@@ -695,7 +676,7 @@ export default {
       Object.keys(this.people).forEach(sid => {
         if (![this.st.user.sid,oppsid].includes(sid))
         {
-          this.st.conn.send(JSON.stringify({code:"game",
+          this.conn.send(JSON.stringify({code:"game",
             game: { //minimal game info:
               id: gameInfo.id,
               players: gameInfo.players,