Browse Source

[add] client JS
[add] polling system
[quickfix] retab package.json
[add] debug flag removes cache
[add] serv slack cache

B Thibault 8 years ago
parent
commit
b344e6c085
13 changed files with 204 additions and 19 deletions
  1. 4 0
      .gitignore
  2. 24 0
      Makefile
  3. 18 0
      cli/data.js
  4. 5 0
      cli/ui.js
  5. 60 0
      cli/workflow.js
  6. 13 12
      package.json
  7. 1 0
      src/config.js
  8. 13 3
      src/public/index.html
  9. 2 0
      src/public/slack.min.js
  10. 26 0
      src/public/style.css
  11. 7 2
      src/src/httpServ.js
  12. 5 1
      src/src/slack.js
  13. 26 1
      src/src/slackManager.js

+ 4 - 0
.gitignore

@@ -1,3 +1,7 @@
+*.swp
+*.bak
+cli/closure-compiler-v*.jar
+
 # cache
 store.json
 

+ 24 - 0
Makefile

@@ -0,0 +1,24 @@
+
+SRC=		cli/ui.js		\
+			cli/data.js		\
+			cli/workflow.js
+
+OUTPUT=		src/public/slack.min.js
+
+CLOSURE=	cli/closure-compiler-v20170218.jar
+
+all:
+	java -jar ${CLOSURE} --compilation_level SIMPLE --js_output_file ${OUTPUT} ${SRC}
+
+debug:
+	java -jar ${CLOSURE} --compilation_level WHITESPACE_ONLY --js_output_file ${OUTPUT} ${SRC}
+
+$OUTPUT: all
+
+clean:
+	$(RM) $(OUTPUT)
+
+re:	clean all
+
+.PHONY: all debug clean re
+

+ 18 - 0
cli/data.js

@@ -0,0 +1,18 @@
+
+var
+    /**
+     * @type Slack
+    **/
+    SLACK;
+
+function Slack() {
+    /** @type {number} */
+    this.lastServerVersion = 0;
+}
+
+Slack.prototype.update = function(data) {
+    console.log(data);
+}
+
+SLACK = new Slack();
+

+ 5 - 0
cli/ui.js

@@ -0,0 +1,5 @@
+
+document.addEventListener('DOMContentLoaded', function() {
+    startPolling();
+});
+

+ 60 - 0
cli/workflow.js

@@ -0,0 +1,60 @@
+
+var
+    /**
+     * @type {number} next period to wait before next retry in case of failure, in seconds
+    **/
+    NEXT_RETRY = 5
+;
+
+function poll(callback) {
+    var xhr = new XMLHttpRequest();
+    xhr.timeout = 18000; // 2 min timeout
+    xhr.timeout = 1800;
+    xhr.onreadystatechange = function(e) {
+        if (xhr.readyState === 4) {
+            if (xhr.status === 0) {
+                poll(callback); // retry on timeout
+                NEXT_RETRY = 5;
+                return;
+            }
+            var resp = null
+                ,success = Math.floor(xhr.status / 100) === 2;
+
+            if (success) {
+                NEXT_RETRY = 5;
+                resp = xhr.response;
+                try {
+                    resp = JSON.parse(resp);
+                } catch (e) {
+                    resp = null;
+                }
+            } else {
+                NEXT_RETRY += Math.floor(NEXT_RETRY /2);
+                NEXT_RETRY = Math.min(60, NEXT_RETRY);
+            }
+            callback(success, resp);
+        }
+    };
+    xhr.open('GET', 'api?t=' +SLACK.lastServerVersion, true);
+    xhr.send(null);
+}
+
+/**
+ * @param {boolean} success
+ * @param {*} response
+**/
+function onPollResponse(success, response) {
+    if (success) {
+        if (response) {
+            SLACK.update(response);
+        }
+        startPolling();
+    } else {
+        setTimeout(startPolling, NEXT_RETRY * 1000);
+    }
+}
+
+function startPolling() {
+    poll(onPollResponse);
+}
+

+ 13 - 12
package.json

@@ -1,14 +1,15 @@
 {
-	"name": "knackigate-slack"
-	,"dependencies": [
-		"http"
-		,"client-sessions"
-		,"crypto"
-		,"node-file-cache"
-		,"sleep"
-	]
-	,"repository": {
-		"type": "git"
-		,"url": "git@git.knacki.info:isundil/knackigate-slack"
-	}
+  "name": "knackigate-slack",
+  "dependencies": [
+    "http",
+    "client-sessions",
+    "crypto",
+    "node-file-cache",
+    "memory-cache",
+    "sleep"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git@git.knacki.info:isundil/knackigate-slack"
+  }
 }

+ 1 - 0
src/config.js

@@ -2,4 +2,5 @@
 module.exports = {
     clientId: "secret client id"
     ,rootUrl: "local url"
+    ,isDebug: false
 };

+ 13 - 3
src/public/index.html

@@ -1,5 +1,15 @@
 <html>
-	<body>
-		<script src="cli.js"></script>
-	</body>
+    <head>
+        <link href="style.css" rel="stylesheet"/>
+    </head>
+    <body>
+        <aside class="slack-context">
+            <nav class="slack-context-menu"></nav>
+            <div class="slack-context-channellist"></div>
+            <div class="slack-context-imlist"></div>
+        </aside>
+        <div class="slack-chat-container">
+        </div>
+        <script src="slack.min.js"></script>
+    </body>
 </html>

+ 2 - 0
src/public/slack.min.js

@@ -0,0 +1,2 @@
+document.addEventListener("DOMContentLoaded",function(){startPolling()});var SLACK;function Slack(){this.lastServerVersion=0}Slack.prototype.update=function(b){console.log(b)};SLACK=new Slack;var NEXT_RETRY=5;function poll(b){var a=new XMLHttpRequest;a.timeout=18E3;a.timeout=1800;a.onreadystatechange=function(c){if(4===a.readyState)if(0===a.status)poll(b),NEXT_RETRY=5;else{c=null;var d=2===Math.floor(a.status/100);if(d){NEXT_RETRY=5;c=a.response;try{c=JSON.parse(c)}catch(e){c=null}}else NEXT_RETRY+=Math.floor(NEXT_RETRY/2),NEXT_RETRY=Math.min(60,NEXT_RETRY);b(d,c)}};a.open("GET","api?t="+SLACK.lastServerVersion,!0);a.send(null)}
+function onPollResponse(b,a){b?(a&&SLACK.update(a),startPolling()):setTimeout(startPolling,1E3*NEXT_RETRY)}function startPolling(){poll(onPollResponse)};

+ 26 - 0
src/public/style.css

@@ -0,0 +1,26 @@
+
+body {
+    margin: 0;
+    padding: 0;
+}
+
+.slack-context {
+    display: inline-block;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    width: 250px;
+    overflow-x: hidden;
+    overflow-y: scroll;
+}
+
+.slack-chat-container {
+    display: inline-block;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 250px;
+    right: 0;
+}
+

+ 7 - 2
src/src/httpServ.js

@@ -79,14 +79,19 @@ Server.prototype.onRequest = function(req, res) {
             });
         }
     } else if (req.urlObj.isPublic()) {
-        res.setHeader('Cache-Control', 'public, max-age=' +15 * 60);
+        if (!config.isDebug)
+            res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
         res.setHeader('Content-Length', req.urlObj.serve.stat.size);
         res.writeHeader("200");
         req.urlObj.getReadStream().pipe(res, { end: true });
         sessionManager.saveSession(req.session);
         return; // async pipe will close when finished
     } else {
-        res.writeHeader("200");
+        res.slack = slackManager.lazyGet(req.session);
+        //TODO stuff
+        res.writeHeader("200", {
+            "Content-Type": "application/json"
+        });
         res.write('"' +Math.floor(Date.now() /1000) +'"');
     }
     sessionManager.saveSession(req.session);

+ 5 - 1
src/src/slack.js

@@ -1,5 +1,9 @@
 
-function Slack() {
+function Slack(sess) {
+    console.log("creating new slack RTM for ", sess);
+}
+
+Slack.prototype.close = function() {
 }
 
 module.exports.Slack = Slack;

+ 26 - 1
src/src/slackManager.js

@@ -1,7 +1,12 @@
 
+const cache = require('memory-cache')
+    ,Slack = require('./slack.js').Slack;
+
 function SlackManager() {
 }
 
+var instance = new SlackManager();
+
 SlackManager.prototype.getScope = function() {
     return [
         "channels:read"
@@ -9,5 +14,25 @@ SlackManager.prototype.getScope = function() {
     ];
 }
 
-module.exports.SlackManager = new SlackManager();
+SlackManager.prototype.lazyGet = function(sess) {
+    var key = "SLACK_" +sess.sessId
+        ,val = cache.get(key);
+    if (val) {
+        cache.put(key, val, 1000 * 60 * 60 * 24, function(key, val) {
+            instance.removed(key, val);
+        });
+    } else {
+        val = new Slack(sess);
+        cache.put(key, val, 1000 * 60 * 60 * 24, function(key, val) {
+            instance.removed(key, val);
+        });
+    }
+    return val;
+}
+
+SlackManager.prototype.removed = function(key, slack) {
+    slack.close();
+}
+
+module.exports.SlackManager = instance;