Browse Source

[Fix] pushall update live
[Fix #10] network error layer

B Thibault 8 years ago
parent
commit
02cde0d5b1
9 changed files with 50 additions and 24 deletions
  1. 1 0
      cli/resources.js
  2. 4 0
      cli/ui.js
  3. 16 5
      cli/workflow.js
  4. 1 0
      srv/public/index.html
  5. 12 12
      srv/public/slack.min.js
  6. 2 0
      srv/public/style.css
  7. 3 5
      srv/src/slack.js
  8. 1 0
      srv/src/slackData.js
  9. 10 2
      srv/src/slackHistory.js

+ 1 - 0
cli/resources.js

@@ -14,6 +14,7 @@ var R = {
     ,klass: {
         selected: "selected"
         ,noRoomSelected: "no-room-selected"
+        ,noNetwork: "no-network"
         ,unread: "unread"
         ,unreadHi: "unreadHi"
         ,chatList: {

+ 4 - 0
cli/ui.js

@@ -60,6 +60,10 @@ function onContextUpdated() {
     document.getElementById(R.id.chanList).appendChild(chanListFram);
 }
 
+function onNetworkStateUpdated(isNetworkWorking) {
+    isNetworkWorking ? document.body.classList.remove(R.klass.noNetwork) : document.body.classList.add(R.klass.noNetwork);
+}
+
 function onRoomSelected() {
     var name = SELECTED_ROOM.name || (SELECTED_ROOM.user ? SELECTED_ROOM.user.name : undefined);
     if (!name) {

+ 16 - 5
cli/workflow.js

@@ -3,7 +3,7 @@ var
     /**
      * @type {number} next period to wait before next retry in case of failure, in seconds
     **/
-    NEXT_RETRY = 5
+    NEXT_RETRY = 0
 
     /**
      * @type {SlackChan|SlackIms|SlackGroup}
@@ -27,15 +27,21 @@ function poll(callback) {
     xhr.onreadystatechange = function(e) {
         if (xhr.readyState === 4) {
             if (xhr.status === 0) {
+                if (NEXT_RETRY) {
+                    NEXT_RETRY = 0;
+                    onNetworkStateUpdated(true);
+                }
                 poll(callback); // retry on timeout
-                NEXT_RETRY = 5;
                 return;
             }
             var resp = null
                 ,success = Math.floor(xhr.status / 100) === 2;
 
             if (success) {
-                NEXT_RETRY = 5;
+                if (NEXT_RETRY) {
+                    NEXT_RETRY = 0;
+                    onNetworkStateUpdated(true);
+                }
                 resp = xhr.response;
                 try {
                     resp = JSON.parse(/** @type {string} */ (resp));
@@ -43,8 +49,13 @@ function poll(callback) {
                     resp = null;
                 }
             } else {
-                NEXT_RETRY += Math.floor(NEXT_RETRY /2);
-                NEXT_RETRY = Math.min(60, NEXT_RETRY);
+                if (NEXT_RETRY) {
+                    NEXT_RETRY += Math.floor((NEXT_RETRY || 5)/2);
+                    NEXT_RETRY = Math.min(60, NEXT_RETRY);
+                } else {
+                    NEXT_RETRY = 5;
+                    onNetworkStateUpdated(false);
+                }
             }
             callback(success, resp);
         }

+ 1 - 0
srv/public/index.html

@@ -20,6 +20,7 @@
                 </form>
             </div>
         </div>
+        <div class="error" id="neterror">Cannot connect to chat !</div>
         <script src="slack.min.js"></script>
     </body>
 </html>

+ 12 - 12
srv/public/slack.min.js

@@ -1,13 +1,13 @@
-function g(b,a){this.id=b.id;this.name=b.name;this.b=parseFloat(b.last_read);this.a={};if(b.members)for(var c=0,e=b.members.length;c<e;c++){var f=h(a,b.members[c]);this.a[f.id]=f;f.c[this.id]=this}}function p(b,a){var c=[];this.id=a.id;this.a={};for(var e=0,f=a.members.length;e<f;e++){var d=h(b,a.members[e]);this.a[a.members[e]]=d;d.c[this.id]=this;c.push(d.name)}this.name=c.join(", ");this.b=parseFloat(a.last_read)}function q(b,a){this.id=a.id;this.f=b;this.b=parseFloat(a.last_read)}
+function g(b,a){this.id=b.id;this.name=b.name;this.b=parseFloat(b.last_read);this.a={};if(b.members)for(var c=0,e=b.members.length;c<e;c++){var f=h(a,b.members[c]);this.a[f.id]=f;f.c[this.id]=this}}function m(b,a){var c=[];this.id=a.id;this.a={};for(var e=0,f=a.members.length;e<f;e++){var d=h(b,a.members[e]);this.a[a.members[e]]=d;d.c[this.id]=this;c.push(d.name)}this.name=c.join(", ");this.b=parseFloat(a.last_read)}function q(b,a){this.id=a.id;this.f=b;this.b=parseFloat(a.last_read)}
 function r(b){this.id=b.id;this.name=b.name;this.status=b.status;this.b={w:b.profile.image_24,A:b.profile.image_32,j:b.profile.image_48,m:b.profile.image_72,u:b.profile.image_192,C:b.profile.image_512};this.c={};this.a=null}function u(b){this.id=b.id;this.name=b.name;this.b={B:b.icons.image_36,j:b.icons.image_48,m:b.icons.image_72};this.c={};this.a=null}function v(){this.c={};this.b={};this.f={};this.a={};this.h=null;this.i={}}function h(b,a){return b.a[a]||b.i[a]||null}
-"undefined"!==typeof module&&(module.l.o=v);function w(b){this.g=parseFloat(b.ts);this.raw=b}function x(b,a,c){this.id="string"===typeof b?b:b.id;this.a=[];this.b=a;c&&y(this,c)}function y(b,a){a.forEach(function(b){this.push(b)}.bind(b))}x.prototype.push=function(b){for(var a=parseFloat(b.ts),c=0,e=this.a.length;c<e;c++)if(this.a[c].g===a)return!1;for(this.a.push(new w(b));this.a.length>this.b;)this.a.shift()};"undefined"!==typeof module&&(module.l.s=x);function z(){var b=document.createDocumentFragment(),a=A.a.h?Object.keys(A.a.h.c):[];a.sort(function(b,a){return b[0]!==a[0]?b[0]-a[0]:(A.a.c[b]||A.a.b[b]).name.localeCompare((A.a.c[a]||A.a.b[a]).name)});a.forEach(function(a){a=A.a.c[a]||A.a.b[a];var c=document.createElement("li");c.id=a.id;"D"===a.id[0]?c.className="slack-context-room slack-ims":"G"===a.id[0]?c.className="slack-context-room slack-group":"C"===a.id[0]&&(c.className="slack-context-room slack-channel");c.textContent=a.name;c&&b.appendChild(c)});
-a=A.a.a?Object.keys(A.a.a):[];a.sort(function(b,a){return A.a.a[b].name.localeCompare(A.a.a[a].name)});a.forEach(function(a){a=A.a.a[a].a;var c=document.createElement("li");c.id=a.id;c.className="slack-context-room";c.textContent=a.f.name;c&&b.appendChild(c)});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(b)}
-function B(b,a){var c=document.createElement("div"),e=document.createElement("div"),f=document.createElement("div"),d=document.createElement("div"),l=document.createElement("img"),m=document.createElement("span"),k=document.createElement("ul"),n=document.createElement("li"),t=a.raw.user?A.a.a[a.raw.user]:A.a.i[a.raw.bot_id];c.id=b+"_"+a.g;c.className="slackmsg-item";e.className="slackmsg-ts";f.className="slackmsg-msg";d.className="slackmsg-author";l.className="slackmsg-author-img";m.className="slackmsg-author-name";
-k.className="slackmsg-hover";n.className="slackmsg-hover-reply";e.textContent=(new Date(1E3*a.g)).toLocaleTimeString();f.textContent=a.raw.text;m.textContent=t?t.name:a.raw.username||"?";l.src=t?t.b.j:"";d.appendChild(l);d.appendChild(m);k.appendChild(n);c.appendChild(d);c.appendChild(f);c.appendChild(e);c.appendChild(k);return c}function C(){var b=0,a;for(a in D)D.hasOwnProperty(a)&&(b+=D[a]);document.title=(b?"("+b+")":"")+" - gate"}
-function E(){var b=document.createDocumentFragment(),a=F.id;document.getElementById("chatWindow").textContent="";A.b[a]&&A.b[a].a.forEach(function(c){b.appendChild(B(a,c))});var c=document.getElementById("chatWindow");c.appendChild(b);c.scrollTop=c.scrollHeight-c.clientHeight}
-function G(b){for(;b.target!==b.currentTarget&&b.target;){if(b.target.classList.contains("slack-context-room")){if((b=A.a.c[b.target.id]||A.a.f[b.target.id]||A.a.b[b.target.id])&&b!==F){F&&document.getElementById(F.id).classList.remove("selected");document.getElementById(b.id).classList.add("selected");document.body.classList.remove("no-room-selected");F=b;b=void 0;var a=F.name||(F.f?F.f.name:void 0);if(!a){a=[];for(b in F.a)a.push(F.a[b].name);a=a.join(", ")}b=document.getElementById(F.id);b.classList.remove("unread");
-b.classList.remove("unreadHi");document.getElementById("currentRoomTitle").textContent=a;E();D[F.id]&&(D[F.id]=0,C());F.b&&!A.b[F.id]&&(b=new XMLHttpRequest,b.open("GET","api/hist?room="+F.id,!0),b.send(null))}break}b.target=b.target.parentElement}}
-function H(b){for(var a=b.target;a!==b.currentTarget&&a&&!a.classList.contains("slackmsg-hover");){if(a.classList.contains("slackmsg-hover-reply")){a:{for(a=a||b.target;a!==b.currentTarget&&a;){if(a.classList.contains("slackmsg-item")){b=a.id;break a}a=a.parentElement}b=void 0}if(b){b=parseFloat(b.split("_")[1]);for(var a=A.b[F.id].a,c=0,e=a.length;c<e&&a[c].g<=b;c++)if(a[c].g===b){console.log("Replying to ",a[c]);break}}break}a=a.parentElement}}
-document.addEventListener("DOMContentLoaded",function(){document.getElementById("chatList").addEventListener("click",G);document.getElementById("chatWindow").addEventListener("click",H);document.getElementById("msgForm").addEventListener("submit",function(b){b.preventDefault();b=document.getElementById("msgInput");if(F&&b.value){var a=new XMLHttpRequest;a.open("POST","api/msg?room="+F.id+"&text="+encodeURIComponent(b.value),!0);a.send(null);b.value=""}return!1});I()});var A,D={};A=new function(){this.f=0;this.a=new v;this.b={}};var J=5,F=null;function K(b){var a=new XMLHttpRequest;a.timeout=6E4;a.onreadystatechange=function(){if(4===a.readyState)if(a.status){var c=null,e=2===Math.floor(a.status/100);if(e){J=5;c=a.response;try{c=JSON.parse(c)}catch(f){c=null}}else J+=Math.floor(J/2),J=Math.min(60,J);b(e,c)}else K(b),J=5};a.open("GET","api?v="+A.f,!0);a.send(null)}
-function L(b,a){if(b){if(a){var c=A;a.v&&(c.f=a.v);if(a["static"]){for(var e=c.a,f=a["static"],d=0,l=f.bots.length;d<l;d++)e.i[f.bots[d].id]=new u(f.bots[d]);d=0;for(l=f.users.length;d<l;d++)e.a[f.users[d].id]=new r(f.users[d]);d=0;for(l=f.ims.length;d<l;d++){var m=h(e,f.ims[d].user);m&&(m.a=new q(m,f.ims[d]),e.f[m.a.id]=m.a)}d=0;for(l=f.channels.length;d<l;d++)e.c[f.channels[d].id]=new g(f.channels[d],e);d=0;for(l=f.groups.length;d<l;d++)e.b[f.groups[d].id]=new p(e,f.groups[d]);e.h=h(e,f.self.id);
-z()}if(a.live){for(var k in a.live)(e=c.b[k])?y(e,a.live[k]):c.b[k]=new x(k,500,a.live[k]);for(var n in a.live)F&&a.live[F.id]?E():(k=c.a,k=k.c[n]||k.f[n]||k.b[n]||null,e=a.live[n],k&&(document.getElementById(k.id).classList.add("unread"),D[k.id]=(D[k.id]||0)+e.length,C()))}}I()}else setTimeout(I,1E3*J)}function I(){K(L)};
+"undefined"!==typeof module&&(module.l.o=v);function w(b){this.g=parseFloat(b.ts);this.raw=b}function x(b,a,c){this.id="string"===typeof b?b:b.id;this.a=[];this.b=a;c&&y(this,c)}function y(b,a){var c=0;a.forEach(function(b){c=Math.max(this.push(b),c)}.bind(b))}x.prototype.push=function(b){for(var a=parseFloat(b.ts),c=0,e=this.a.length;c<e;c++)if(this.a[c].g===a)return a;for(this.a.push(new w(b));this.a.length>this.b;)this.a.shift();return a};"undefined"!==typeof module&&(module.l.s=x);function z(){var b=document.createDocumentFragment(),a=A.a.h?Object.keys(A.a.h.c):[];a.sort(function(b,a){return b[0]!==a[0]?b[0]-a[0]:(A.a.c[b]||A.a.b[b]).name.localeCompare((A.a.c[a]||A.a.b[a]).name)});a.forEach(function(a){a=A.a.c[a]||A.a.b[a];var c=document.createElement("li");c.id=a.id;"D"===a.id[0]?c.className="slack-context-room slack-ims":"G"===a.id[0]?c.className="slack-context-room slack-group":"C"===a.id[0]&&(c.className="slack-context-room slack-channel");c.textContent=a.name;c&&b.appendChild(c)});
+a=A.a.a?Object.keys(A.a.a):[];a.sort(function(b,a){return A.a.a[b].name.localeCompare(A.a.a[a].name)});a.forEach(function(a){a=A.a.a[a].a;var c=document.createElement("li");c.id=a.id;c.className="slack-context-room";c.textContent=a.f.name;c&&b.appendChild(c)});document.getElementById("chanList").textContent="";document.getElementById("chanList").appendChild(b)}function B(b){b?document.body.classList.remove("no-network"):document.body.classList.add("no-network")}
+function C(b,a){var c=document.createElement("div"),e=document.createElement("div"),f=document.createElement("div"),d=document.createElement("div"),l=document.createElement("img"),n=document.createElement("span"),k=document.createElement("ul"),p=document.createElement("li"),t=a.raw.user?A.a.a[a.raw.user]:A.a.i[a.raw.bot_id];c.id=b+"_"+a.g;c.className="slackmsg-item";e.className="slackmsg-ts";f.className="slackmsg-msg";d.className="slackmsg-author";l.className="slackmsg-author-img";n.className="slackmsg-author-name";
+k.className="slackmsg-hover";p.className="slackmsg-hover-reply";e.textContent=(new Date(1E3*a.g)).toLocaleTimeString();f.textContent=a.raw.text;n.textContent=t?t.name:a.raw.username||"?";l.src=t?t.b.j:"";d.appendChild(l);d.appendChild(n);k.appendChild(p);c.appendChild(d);c.appendChild(f);c.appendChild(e);c.appendChild(k);return c}function D(){var b=0,a;for(a in E)E.hasOwnProperty(a)&&(b+=E[a]);document.title=(b?"("+b+")":"")+" - gate"}
+function F(){var b=document.createDocumentFragment(),a=G.id;document.getElementById("chatWindow").textContent="";A.b[a]&&A.b[a].a.forEach(function(c){b.appendChild(C(a,c))});var c=document.getElementById("chatWindow");c.appendChild(b);c.scrollTop=c.scrollHeight-c.clientHeight}
+function H(b){for(;b.target!==b.currentTarget&&b.target;){if(b.target.classList.contains("slack-context-room")){if((b=A.a.c[b.target.id]||A.a.f[b.target.id]||A.a.b[b.target.id])&&b!==G){G&&document.getElementById(G.id).classList.remove("selected");document.getElementById(b.id).classList.add("selected");document.body.classList.remove("no-room-selected");G=b;b=void 0;var a=G.name||(G.f?G.f.name:void 0);if(!a){a=[];for(b in G.a)a.push(G.a[b].name);a=a.join(", ")}b=document.getElementById(G.id);b.classList.remove("unread");
+b.classList.remove("unreadHi");document.getElementById("currentRoomTitle").textContent=a;F();E[G.id]&&(E[G.id]=0,D());G.b&&!A.b[G.id]&&(b=new XMLHttpRequest,b.open("GET","api/hist?room="+G.id,!0),b.send(null))}break}b.target=b.target.parentElement}}
+function I(b){for(var a=b.target;a!==b.currentTarget&&a&&!a.classList.contains("slackmsg-hover");){if(a.classList.contains("slackmsg-hover-reply")){a:{for(a=a||b.target;a!==b.currentTarget&&a;){if(a.classList.contains("slackmsg-item")){b=a.id;break a}a=a.parentElement}b=void 0}if(b){b=parseFloat(b.split("_")[1]);for(var a=A.b[G.id].a,c=0,e=a.length;c<e&&a[c].g<=b;c++)if(a[c].g===b){console.log("Replying to ",a[c]);break}}break}a=a.parentElement}}
+document.addEventListener("DOMContentLoaded",function(){document.getElementById("chatList").addEventListener("click",H);document.getElementById("chatWindow").addEventListener("click",I);document.getElementById("msgForm").addEventListener("submit",function(b){b.preventDefault();b=document.getElementById("msgInput");if(G&&b.value){var a=new XMLHttpRequest;a.open("POST","api/msg?room="+G.id+"&text="+encodeURIComponent(b.value),!0);a.send(null);b.value=""}return!1});J()});var A,E={};A=new function(){this.f=0;this.a=new v;this.b={}};var K=0,G=null;function L(b){var a=new XMLHttpRequest;a.timeout=6E4;a.onreadystatechange=function(){if(4===a.readyState)if(a.status){var c=null,e=2===Math.floor(a.status/100);if(e){K&&(K=0,B(!0));c=a.response;try{c=JSON.parse(c)}catch(f){c=null}}else K?(K+=Math.floor((K||5)/2),K=Math.min(60,K)):(K=5,B(!1));b(e,c)}else K&&(K=0,B(!0)),L(b)};a.open("GET","api?v="+A.f,!0);a.send(null)}
+function M(b,a){if(b){if(a){var c=A;a.v&&(c.f=a.v);if(a["static"]){for(var e=c.a,f=a["static"],d=0,l=f.bots.length;d<l;d++)e.i[f.bots[d].id]=new u(f.bots[d]);d=0;for(l=f.users.length;d<l;d++)e.a[f.users[d].id]=new r(f.users[d]);d=0;for(l=f.ims.length;d<l;d++){var n=h(e,f.ims[d].user);n&&(n.a=new q(n,f.ims[d]),e.f[n.a.id]=n.a)}d=0;for(l=f.channels.length;d<l;d++)e.c[f.channels[d].id]=new g(f.channels[d],e);d=0;for(l=f.groups.length;d<l;d++)e.b[f.groups[d].id]=new m(e,f.groups[d]);e.h=h(e,f.self.id);
+z()}if(a.live){for(var k in a.live)(e=c.b[k])?y(e,a.live[k]):c.b[k]=new x(k,500,a.live[k]);for(var p in a.live)G&&a.live[G.id]?F():(k=c.a,k=k.c[p]||k.f[p]||k.b[p]||null,e=a.live[p],k&&(document.getElementById(k.id).classList.add("unread"),E[k.id]=(E[k.id]||0)+e.length,D()))}}J()}else setTimeout(J,1E3*K)}function J(){L(M)};

+ 2 - 0
srv/public/style.css

@@ -29,6 +29,8 @@ body {
     background-color: lightgrey;
 }
 
+.error { display: none; position: fixed; top: 0; left: 0; right: 0; height: 2em; line-height: 2em; background: #ffa2a2; padding: 0.5em 1em; }
+.no-network .error { display: inline-block; }
 .slack-chat-content { height: calc(100vh - 8em); overflow: auto; }
 .slack-chat-title { display: inline-block; height: 1.75em; font-size: 1.75em; font-style: italic; }
 .slack-chat-control { display: inline-block; width: 100%; height: 2em; padding: 1.5em 0; }

+ 3 - 5
srv/src/slack.js

@@ -228,13 +228,11 @@ Slack.prototype.fetchHistory = function(targetId) {
     (status, resp) => {
         if (status === 200 && resp && resp.ok) {
             var history = _this.history[targetId];
-            if (history)
-                history.pushAll(resp.messages);
-            else {
-                history = _this.history[targetId] = new SlackHistory(targetId, HISTORY_LENGTH, resp.messages);
+            if (!history) {
+                history = _this.history[targetId] = new SlackHistory(targetId, HISTORY_LENGTH);
                 history.isNew = true;
             }
-            //TODO update this.data.liveV
+            this.data.liveV = Math.max(history.pushAll(resp.messages), this.data.liveV);
         }
     });
 };

+ 1 - 0
srv/src/slackData.js

@@ -370,6 +370,7 @@ SlackBot.prototype.toStatic = function() {
  * @param {*} data
 **/
 SlackData.prototype.updateStatic = function(data) {
+    //TODO make lazy to keep pointers
     for (var i =0, nbBots = data["bots"].length; i < nbBots; i++)
         this.bots[data["bots"][i].id] = new SlackBot(data["bots"][i]);
     for (var i =0, nbUsers = data["users"].length; i < nbUsers; i++)

+ 10 - 2
srv/src/slackHistory.js

@@ -40,24 +40,32 @@ SlackMessage.prototype.toStatic = function() {
 
 /**
  * @param {Array} evts
+ * @return {number} biggest ts
 **/
 SlackHistory.prototype.pushAll = function(evts) {
+    var result = 0;
+
     evts.forEach(function(e) {
-        this.push(e);
+        result = Math.max(this.push(e), result);
     }.bind(this));
+    return result;
 }
 
+/**
+ * @return {number} ts
+**/
 SlackHistory.prototype.push = function(ev) {
     var ts = parseFloat(ev["ts"]);
 
     for (var i =0, nbMsg = this.messages.length; i < nbMsg; i++) {
         if (this.messages[i].ts === ts) {
-            return false;
+            return ts;
         }
     }
     this.messages.push(new SlackMessage(ev));
     while (this.messages.length > this.keepMessages)
         this.messages.shift();
+    return ts;
 }
 
 /**