Browse Source

[add] live context
[add] poll live context (not yet saved);

B Thibault 8 years ago
parent
commit
98cf936d1d
4 changed files with 252 additions and 11 deletions
  1. 8 1
      cli/data.js
  2. 1 1
      src/public/slack.min.js
  3. 28 9
      src/src/slack.js
  4. 215 0
      src/src/slackData.js

+ 8 - 1
cli/data.js

@@ -11,7 +11,14 @@ function Slack() {
 }
 
 Slack.prototype.update = function(data) {
-    console.log(data);
+    if (data.v)
+        this.lastServerVersion = data.v;
+    if (data.static) {
+        console.log("updated static");
+    }
+    if (data.live) {
+        console.log("updated LIVE");
+    }
 }
 
 SLACK = new Slack();

+ 1 - 1
src/public/slack.min.js

@@ -1,2 +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=6E4;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?v="+SLACK.lastServerVersion,!0);a.send(null)}
+document.addEventListener("DOMContentLoaded",function(){startPolling()});var SLACK;function Slack(){this.lastServerVersion=0}Slack.prototype.update=function(b){b.v&&(this.lastServerVersion=b.v);b["static"]&&console.log("updated static");b.live&&console.log("updated LIVE")};SLACK=new Slack;var NEXT_RETRY=5;function poll(b){var a=new XMLHttpRequest;a.timeout=6E4;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?v="+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)};

+ 28 - 9
src/src/slack.js

@@ -12,12 +12,13 @@ const SLACK_ENDPOINT = "https://slack.com/api/"
 ,GETAPI = {
     rtmStart: "rtm.start"
     ,oauth: "oauth.access"
+    ,history: "channels.history"
 };
 
 function Slack(sess) {
     this.token = sess.slackToken;
     this.rtm = null;
-    this.data = new SlackData();
+    this.data = new SlackData(this);
     this.connected = false;
 }
 
@@ -74,9 +75,10 @@ Slack.prototype.connect = function(knownVersion) {
             _this.lastCb(_this);
             return;
         }
-        _this.data.updateStatic(body);
-        _this.connectRtm(body.url);
-        _this.waitForEvent(knownVersion);
+        _this.data.updateStatic(body, () => {
+            _this.connectRtm(body.url);
+            _this.waitForEvent(knownVersion);
+        });
     });
 }
 
@@ -87,16 +89,23 @@ Slack.prototype.waitForEvent = function(knownVersion) {
 
     interval = setInterval(() => {
         tick++;
-        var updated = this.data.getUpdates(knownVersion);
         if (!_this.lastCb) {
             clearInterval(interval);
+            return;
         }
-        if (updated.length > 0) {
-            clearInterval(interval);
-            _this.lastCb(_this, { v: knownVersion, u: updated });
-        } else if (tick === 55) { // < 1 minute timeout
+        if (_this.connected) {
+            var updated = _this.data.getUpdates(knownVersion);
+            if (updated["static"] || updated["live"]) {
+                updated["v"] = Math.max(_this.data.liveV, _this.data.staticV);
+                clearInterval(interval);
+                _this.lastCb(_this, updated);
+                return;
+            }
+        }
+        if (tick >= 55) { // < 1 minute timeout
             clearInterval(interval);
             _this.lastCb(_this, { v: knownVersion });
+            return;
         }
     }, 1000);
 }
@@ -142,5 +151,15 @@ Slack.getOauthToken = function(code, cb) {
     });
 }
 
+Slack.prototype.fetchHistory = function(targetId, cb) {
+    httpsRequest(SLACK_ENDPOINT +GETAPI.history
+        +"?token="+this.token
+        +"&channel=" +targetId
+        +"&count=25",
+    (status, resp) => {
+        cb(targetId, status === 200 && resp && resp.ok ? resp.messages : null);
+    });
+}
+
 module.exports.Slack = Slack;
 

+ 215 - 0
src/src/slackData.js

@@ -0,0 +1,215 @@
+
+function SlackTeam(teamData) {
+    this.id = teamData.id;
+    this.name = teamData.name;
+    this.domain = teamData.domain;
+    this.callApp = teamData.prefs.calling_app_id;
+    this.callAppName = teamData.prefs.calling_app_name;
+    this.fileUploadPermission = teamData.prefs.disable_file_uploads;
+    this.fileEditPermission = teamData.prefs.disable_file_editing;
+    this.fileDeletePermission = teamData.prefs.disable_file_deleting;
+    this.icons = teamData.icon; // image_34, image_44, image_68, image_88, image_102, image_132, image_230, image_default
+}
+
+function SlackChan(chanData, slackData) {
+    this.id = chanData.id;
+    this.name = chanData.name;
+    this.created = chanData.created;
+    this.creator = chanData.creator;
+    this.archived = chanData.is_archived;
+    this.isMember = chanData.is_member;
+    this.lastRead = chanData.last_read;
+    this.members = {};
+    for (var i =0, nbMembers = chanData.members.length; i < nbMembers; i++)
+        this.members[chanData.members[i]] = slackData.getMember(chanData.members[i]);
+    this.topic = chanData.topic.value;
+    this.topicCreator = slackData.getMember(chanData.topic.creator);
+    this.topicTs = chanData.topic.last_set;
+    this.purpose = chanData.purpose.value;
+    this.purposeCreator = slackData.getMember(chanData.purpose.creator);
+    this.purposeTs = chanData.purpose.last_set;
+}
+
+function SlackGroup(groupData) {
+    // TODO
+}
+
+function SlackIms(imsData) {
+    /*
+    * TODO
+     * { id: 'D4BTFBDT5',
+  created: 1488361588,
+  is_im: true,
+  is_org_shared: false,
+  user: 'USLACKBOT',
+  has_pins: false,
+  last_read: '1488364738.619420',
+  latest:
+   { type: 'message',
+     user: 'USLACKBOT',
+     text: 'Right now anyone on your team can invite a new member. If you’d like, you can restrict that to just administrators.\n_<slack-action://BSLACKBOT/users-invites/invites-only-admins/restrict/|Only allow administrators to invite>_',
+     ts: '1488364738.619420' },
+  unread_count: 0,
+  unread_count_display: 0,
+  is_open: true }
+    */
+}
+
+function SlackUser(userData) {
+    this.id = userData.id;
+    this.name = userData.name;
+    this.deleted = userData.deleted;
+    this.status = userData.status;
+    this.realName = userData.real_name || userData.profile.real_name;
+    this.presence = userData.presence !== 'away';
+    this.icons = {
+        image_24: userData.profile.image_24
+        ,image_32: userData.profile.image_32
+        ,image_48: userData.profile.image_48
+        ,image_72: userData.profile.image_72
+        ,image_192: userData.profile.image_192
+        ,image_512: userData.profile.image_512
+    };
+    this.email = userData.profile.email;
+    this.firstName = userData.profile.first_name;
+    this.lastName = userData.profile.last_name;
+}
+
+function SlackBot(botData) {
+    this.id = botData.id;
+    this.deleted = botData.deleted;
+    this.name = botData.name;
+    this.appId = botData.app_id;
+    // { image_36, image_48, image_72 }
+    this.icons = botData.icons;
+}
+
+function SlackHistory(target) {
+    this.id = target.id;
+    this.target = target;
+    this.v = 0;
+    this.messages = [];
+}
+
+function SlackData(slack) {
+    this.team = null;
+    this.channels = {};
+    this.groups = [];
+    this.ims = [];
+    this.users = {};
+    this.self = null;
+    this.bots = {};
+    // channel/ims id -> array of events
+    this.history = {};
+    this.slack = slack;
+
+    this.staticV = 0;
+    this.liveV = 0;
+}
+
+SlackTeam.prototype.toStatic = function() {
+    return this;
+}
+
+SlackHistory.prototype.update = function(messages) {
+    // TODO
+}
+
+SlackHistory.prototype.getUpdates = function(knownVersion) {
+    // TODO
+}
+
+SlackData.prototype.updateStatic = function(data, callback) {
+    for (var i =0, nbBots = data.bots.length; i < nbBots; i++)
+        this.bots[data.bots[i].id] = new SlackBot(data.bots[i]);
+    this.team = new SlackTeam(data.team);
+    for (var i =0, nbUsers = data.users.length; i < nbUsers; i++)
+        this.users[data.users[i].id] = new SlackUser(data.users[i]);
+    for (var i =0, nbChan = data.channels.length; i < nbChan; i++)
+        this.channels[data.channels[i].id] = new SlackChan(data.channels[i], this);
+    //this.groups.push(new SlackGroup(data.groups)); TODO
+    //this.ims.push(new SlackIms(data.ims[0])); TODO
+    this.staticV = parseFloat(data.latest_event_ts);
+
+    var fetchHistory = {}
+        ,doFetch = false;
+    for (var i in this.channels)
+        if (!this.history[i]) {
+            doFetch = true;
+            fetchHistory[i] = this.channels[i];
+        }
+    //TODO fetch group & ims history
+    if (!doFetch)
+        callback();
+    else for (var i in fetchHistory) {
+        var _this = this;
+
+        this.slack.fetchHistory(i, (currentUpdated, data) => {
+            if (data != null) {
+                _this.setHistory(fetchHistory[currentUpdated], data);
+                fetchHistory[currentUpdated] = null;
+                for (var i in fetchHistory) {
+                    if (fetchHistory[i])
+                        return;
+                }
+            }
+            callback();
+        });
+    }
+}
+
+SlackData.prototype.setHistory = function(target, data) {
+    if (!this.history[target.id])
+        this.history[target.id] = new SlackHistory(target);
+    this.history[target.id].update(data);
+}
+
+SlackData.prototype.getBotsByAppId = function(appId) {
+    var bots = [];
+
+    for (var botId in this.bots) {
+        if (this.bots[botId].appId === appId) {
+            bots.push(this.bots[botId]);
+        }
+    }
+    return bots;
+}
+
+SlackData.prototype.getMember = function(mId) {
+    return this.users[mId] || this.bots[mId] || null;
+}
+
+SlackData.prototype.buildLive = function(knownVersion) {
+    var res = {};
+    for (var i in this.history)
+        if (this.history[i].v > knownVersion)
+            res[i] = this.history[i].getUpdates(knownVersion);
+}
+
+SlackData.prototype.buildStatic = function() {
+    var res = {
+        team: this.team.toStatic()
+        ,channels: {}
+        ,groups: {}
+        ,ims: {}
+        ,users: {}
+        ,bots: {}
+    };
+    return res;
+}
+
+SlackData.prototype.getUpdates = function(knownVersion) {
+    var res = {};
+    if (this.liveV > knownVersion) {
+        res.live = this.buildLive();
+    }
+    if (this.staticV > knownVersion) {
+        res.static = this.buildStatic();
+    }
+    return res;
+}
+
+if (module.exports) {
+    module.exports.SlackData = SlackData;
+}
+