/** @const */ var POLL_TIMEOUT = 55000; /** @interface */ function ChatSystem() { }; /** */ ChatSystem.prototype.onRequest = function() {}; /** * @return {string|null} **/ ChatSystem.prototype.getId = function() {}; /** * @return {ChatContext} **/ ChatSystem.prototype.getChatContext = function() {}; /** * Async fetch history * @param {Room} chan * @param {string} text **/ ChatSystem.prototype.sendMeMsg = function(chan, text) {}; /** * Async fetch history * @param {Room} chan * @param {string} text * @param {Object=} attachments **/ ChatSystem.prototype.sendMsg = function(chan, text, attachments) {}; /** * Async star msg * @param {Room} chan * @param {string} msgId **/ ChatSystem.prototype.starMsg = function(chan, msgId) {}; /** * Async remove star from msg * @param {Room} chan * @param {string} msgId **/ ChatSystem.prototype.unstarMsg = function(chan, msgId) {}; /** * Async fetch history * @param {Room} chan * @param {number} ts **/ ChatSystem.prototype.removeMsg = function(chan, ts) {}; /** * Edit msg * @param {Room} chan * @param {number} ts * @param {string} newText **/ ChatSystem.prototype.editMsg = function(chan, ts, newText) {}; /** * Add reaction * @param {Room} chan * @param {number} ts * @param {string} reaction **/ ChatSystem.prototype.addReaction = function(chan, ts, reaction) {}; /** * Add reaction * @param {Room} chan * @param {number} ts * @param {string} reaction **/ ChatSystem.prototype.removeReaction = function(chan, ts, reaction) {}; /** * Add reaction * @param {Room} chan * @param {string} contentType * @param {function((string|null))} callback **/ ChatSystem.prototype.openUploadFileStream = function(chan, contentType, callback) {}; /** * Async fetch history * @param {Room} chan **/ ChatSystem.prototype.fetchHistory = function(chan, cb) {}; /** * @param {Room} chan **/ ChatSystem.prototype.sendTyping = function(chan) {}; /** * @param {Room} chan * @param {number} ts **/ ChatSystem.prototype.markRead = function(chan, ts) {}; /** * @param {Room} chan * @param {string} cmd * @param {string} args **/ ChatSystem.prototype.sendCommand = function(chan, cmd, args) {}; /** * @param {number} knownVersion * @param {number} nowTs * @param {boolean} withTyping * @return {Object|null} **/ ChatSystem.prototype.poll = function(knownVersion, nowTs, withTyping) {}; /** * @param {string} path * @return {({url: string, headers: Object})|null} path to get **/ ChatSystem.prototype.getImage = function(path) {}; /** * @constructor **/ function MultiChatManager() { /** @type {Array} */ this.contexts = []; } /** * @param {ChatSystem} chatSystem **/ MultiChatManager.prototype.push = function(chatSystem) { this.contexts.push(chatSystem); }; /** * @param {string} id * @return {ChatSystem|null} **/ MultiChatManager.prototype.getById = function(id) { for (var i = 0, nbContexts = this.contexts.length; i < nbContexts; i++) if (id === this.contexts[i].getId()) return this.contexts[i]; return null; }; /** * You may want to return true to break the loop **/ MultiChatManager.prototype.foreachChannels = function(cb) { for (var i =0, nbCtx =this.contexts.length; i < nbCtx; i++) { var ctx = this.contexts[i].getChatContext(); for (var chanId in ctx.channels) if (cb(ctx.channels[chanId], chanId) === true) return; } }; /** * You may want to return true to break the loop **/ MultiChatManager.prototype.foreachContext = function(cb) { for (var i =0, nbCtx =this.contexts.length; i < nbCtx; i++) if (cb(this.contexts[i].getChatContext()) === true) return; }; /** * @param {string} chanId * @return {ChatSystem|null} **/ MultiChatManager.prototype.getChannelContext = function(chanId) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var ctx = this.contexts[i].getChatContext(); if (ctx.channels[chanId]) return this.contexts[i]; } return null; }; /** * @param {string} userId * @return {ChatSystem|null} **/ MultiChatManager.prototype.getUserContext = function(userId) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var ctx = this.contexts[i].getChatContext(); if (ctx.users[userId]) return this.contexts[i]; } return null; }; /** * @param {string} chanId * @return {Room|null} **/ MultiChatManager.prototype.getChannel = function(chanId) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var chan = this.contexts[i].getChatContext().channels[chanId]; if (chan) return chan; } return null; }; /** * @param {function(Room, ChatSystem, string):boolean=} filter (room, roomId) * @return {Array} **/ MultiChatManager.prototype.getChannelIds = function(filter) { var ids = []; for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var channels = this.contexts[i].getChatContext().channels; for (var chanId in channels) { if (!filter || filter(channels[chanId], this.contexts[i], chanId)) { ids.push(chanId); } } } return ids; }; MultiChatManager.prototype.getChatSystem =function(teamId) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var sys = this.contexts[i] ,ctx = sys.getChatContext(); if (ctx && ctx.team && ctx.team.id === teamId) return sys; } }; /** * @param {string} userId * @return {Chatter|null} **/ MultiChatManager.prototype.getUser = function(userId) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var user = this.contexts[i].getChatContext().users[userId]; if (user) return user; } return null; }; /** * @param {string} userId * @return {boolean} **/ MultiChatManager.prototype.isMe = function(userId) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) { var ctx = this.contexts[i].getChatContext(); if (ctx.self && ctx.self.id === userId) return true; } return false; }; MultiChatManager.prototype.pollPeriodical = function(knownVersion, withTyping) { var liveFeed ,staticFeed ,allTyping ,v = 0 ,now = Date.now() ,updated = false; this.contexts.forEach(function(ctx) { var id = ctx.getId(); if (id) { var res = ctx.poll(knownVersion, now, withTyping === undefined ? true : withTyping); if (res) { if (res["static"]) { if (!staticFeed) staticFeed = {}; staticFeed[id] = res["static"]; } if (res["live"]) if (!liveFeed) liveFeed = {}; for (var i in res["live"]) { liveFeed[i] = res["live"][i]; } if (res["typing"]) { if (!allTyping) allTyping = {}; for (var i in res["typing"]) allTyping[i] = res["typing"][i]; } v = Math.max(v, (res["v"] || 0)); updated = true; } } }); if (updated) return ({ "live": liveFeed, "static": staticFeed, "typing": allTyping, "v": Math.max(v, knownVersion) }); }; MultiChatManager.polling = []; /** * @param {number} knownVersion * @param {(function(number, function((Array<{expose:Function, modified: number}>|null))))=} checkConfigUpdate * @param {boolean=} withTyping default true **/ MultiChatManager.prototype.poll = function(knownVersion, reqT, checkConfigUpdate, withTyping) { var _this = this; _this.contexts.forEach(function(ctx) { ctx.onRequest(); }); var p = new Promise(function(succ, err) { function launchPolling() { var currentState = _this.pollPeriodical(knownVersion, withTyping); if (currentState) { succ(currentState); } else { var timeo = setTimeout(function() { for (var i =0, nbCtx = MultiChatManager.polling.length; i < nbCtx; i++) { if (MultiChatManager.polling[i].reqT === reqT && MultiChatManager.polling[i].ctx === _this && MultiChatManager.polling[i].knownVersion === knownVersion) { MultiChatManager.polling.splice(i, 1); break; } } err(); }, 55000); MultiChatManager.polling.push({ ctx: _this, knownVersion: knownVersion, reqT: reqT, checkConfigUpdate: checkConfigUpdate, withTyping: withTyping, promise: succ, timeo: timeo }); } }; if (checkConfigUpdate) { checkConfigUpdate(knownVersion, function(config) { if (config) { var exposedConfig = [], v = 0; config.forEach(function(conf) { exposedConfig.push(conf.expose()); v = Math.max(v, conf.modified); }); var res = _this.pollPeriodical(knownVersion, withTyping); if (res) { res["config"] = exposedConfig; succ(res); } else { succ({ "config": exposedConfig, "v": v }); } } else { launchPolling(); } }); } else { launchPolling(); } }); return p; }; MultiChatManager.prototype.containsCtx = function(ctx) { for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) if (ctx === this.contexts[i]) return true; return false; }; /** @param {ChatContext} ctx */ MultiChatManager.onCtxUpdated = function(ctx) { var i =0; while (MultiChatManager.polling[i]) { var pollingObj = MultiChatManager.polling[i]; if (pollingObj.ctx.containsCtx(ctx)) { var res = pollingObj.ctx.pollPeriodical(pollingObj.knownVersion, pollingObj.withTyping); if (res) { clearTimeout(pollingObj.timeo); pollingObj.promise(res); MultiChatManager.polling.splice(i, 1); } else { i++; } } } }; /** @suppress {undefinedVars,checkTypes} */ (function() { if (typeof module !== "undefined") { module.exports.MultiChatManager = MultiChatManager; } })();