Support server-sent events
authorRaphaël Jakse <raphael.jakse@univ-grenoble-alpes.fr>
Sat, 4 Apr 2020 14:17:23 +0000 (16:17 +0200)
committerRaphaël Jakse <raphael.jakse@univ-grenoble-alpes.fr>
Sat, 4 Apr 2020 14:30:44 +0000 (16:30 +0200)
trivabble-server.js
trivabble.js

index 0e77c7657e84017d1d5b3b2834d6c1eb1dec43fe..933350c61c4965f6d09354bc57a37053e2adccca 100644 (file)
@@ -112,8 +112,12 @@ function Game() {
     this.pendingEvents = [];
 }
 
-function writeResponse(response, data, terminate) {
-    response[terminate ? "end" : "write"](data.length + data);
+function writeResponse(responseAndIsES, data, terminate) {
+    responseAndIsES[0][terminate ? "end" : "write"](
+        responseAndIsES[1]
+            ? "data:" + data + "\n\n"
+            : data.length + data
+    );
 }
 
 function newBoard() {
@@ -212,13 +216,13 @@ Game.prototype.playerJoined = function (playerName) {
     );
 };
 
-Game.prototype.addListeningPlayer = function (playerName, response) {
+Game.prototype.addListeningPlayer = function (playerName, responseAndIsES) {
     var that = this;
 
-    that.listeningPlayers.push(response);
+    that.listeningPlayers.push(responseAndIsES);
 
-    response.on("close", function () {
-        var index = that.listeningPlayers.indexOf(response);
+    responseAndIsES[0].on("close", function () {
+        var index = that.listeningPlayers.indexOf(responseAndIsES);
         if (index !== -1) {
             that.listeningPlayers[index] = that.listeningPlayers[that.listeningPlayers.length - 1];
             that.listeningPlayers.pop();
@@ -616,18 +620,16 @@ function handleCommand(cmd, gameNumber, playerName, response) {
     }
 }
 
-function handleCommands(cmds, response) {
+function handleCommands(cmds, responseAndIsES) {
     if (!cmds.cmds || !cmds.cmds.length) {
         var game = games[cmds.gameNumber];
 
         if (!game) {
-            writeResponse(response, '{"error":1,"reason":"Missing or bad game number"}', true);
+            writeResponse(responseAndIsES, "{\"error\":1,\"reason\":\"Missing or bad game number\"}", true);
             return;
         }
 
-        writeResponse(response,
-            JSON.stringify(
-                {
+        writeResponse(responseAndIsES,
                     "playerName":       cmds.playerName,
                     "gameNumber":       cmds.gameNumber,
                     "letterValues":     game.letterValues,
@@ -639,10 +641,12 @@ function handleCommands(cmds, response) {
             )
         );
 
-        game.addListeningPlayer(cmds.playerName, response);
+        game.addListeningPlayer(cmds.playerName, responseAndIsES);
         return;
     }
 
+    var response = responseAndIsES[0];
+
     response.write("[");
 
     for (var i = 0; i < cmds.cmds.length; i++) {
@@ -674,11 +678,21 @@ function handleRequest(request, response) {
     });
 
     request.on("end", function () {
-        response.setHeader("Content-Type",   "text/plain");
-        response.setHeader("Transfer-Encoding", "chunked");
+        var isEventSource = false;
+        var eventSourceMatch = request.url.match(/\/:[^/]+\/sse\/(?<data>[\s\S]+)$/u);
+
+        if (eventSourceMatch) {
+            response.setHeader("Content-Type", "text/event-stream");
+            post = decodeURIComponent(eventSourceMatch.groups.data);
+            isEventSource = true;
+        } else {
+            response.setHeader("Content-Type",   "text/plain");
+            response.setHeader("Transfer-Encoding", "chunked");
+        }
+
         dateNow = Date.now();
-        console.log("RECEIVED", post);
-        handleCommands(post && JSON.parse(post), response);
+        console.log("RECEIVED", request.url, post, isEventSource);
+        handleCommands(post && JSON.parse(post), [response, isEventSource]);
     });
 }
 
index 2a3f3c3ffd4a15b9faad54d6c2d757659f5a5790..07748d84c61df4544f13a811296a55fd4d3d6849 100644 (file)
             blockMove++;
         }
 
+        if (thisRequestIsPolling && window.EventSource) {
+            var es = new EventSource('/:trivabble/sse/' + JSON.stringify(data));
+
+            es.onopen = function () {
+                pollingReady = true;
+            };
+
+            es.onmessage = function (e) {
+                pollingReady = true;
+                handleReceivedData(JSON.parse(e.data));
+            };
+
+            es.onerror = retryPolling;
+            return;
+        }
+
         var xhr = new XMLHttpRequest();
 
         xhr.open("POST", "/:trivabble", true);