multichatManager.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /** @const */
  2. var POLL_TIMEOUT = 55000;
  3. /** @interface */
  4. function ChatSystem() {
  5. };
  6. /** */
  7. ChatSystem.prototype.onRequest = function() {};
  8. /**
  9. * @return {string|null}
  10. **/
  11. ChatSystem.prototype.getId = function() {};
  12. /**
  13. * @return {ChatContext}
  14. **/
  15. ChatSystem.prototype.getChatContext = function() {};
  16. /**
  17. * Async fetch history
  18. * @param {Room} chan
  19. * @param {string} text
  20. **/
  21. ChatSystem.prototype.sendMeMsg = function(chan, text) {};
  22. /**
  23. * Async fetch history
  24. * @param {Room} chan
  25. * @param {string} text
  26. * @param {Object=} attachments
  27. **/
  28. ChatSystem.prototype.sendMsg = function(chan, text, attachments) {};
  29. /**
  30. * Async star msg
  31. * @param {Room} chan
  32. * @param {string} msgId
  33. **/
  34. ChatSystem.prototype.starMsg = function(chan, msgId) {};
  35. /**
  36. * Async remove star from msg
  37. * @param {Room} chan
  38. * @param {string} msgId
  39. **/
  40. ChatSystem.prototype.unstarMsg = function(chan, msgId) {};
  41. /**
  42. * Async fetch history
  43. * @param {Room} chan
  44. * @param {number} ts
  45. **/
  46. ChatSystem.prototype.removeMsg = function(chan, ts) {};
  47. /**
  48. * Edit msg
  49. * @param {Room} chan
  50. * @param {number} ts
  51. * @param {string} newText
  52. **/
  53. ChatSystem.prototype.editMsg = function(chan, ts, newText) {};
  54. /**
  55. * Add reaction
  56. * @param {Room} chan
  57. * @param {number} ts
  58. * @param {string} reaction
  59. **/
  60. ChatSystem.prototype.addReaction = function(chan, ts, reaction) {};
  61. /**
  62. * Add reaction
  63. * @param {Room} chan
  64. * @param {number} ts
  65. * @param {string} reaction
  66. **/
  67. ChatSystem.prototype.removeReaction = function(chan, ts, reaction) {};
  68. /**
  69. * Add reaction
  70. * @param {Room} chan
  71. * @param {string} contentType
  72. * @param {function((string|null))} callback
  73. **/
  74. ChatSystem.prototype.openUploadFileStream = function(chan, contentType, callback) {};
  75. /**
  76. * Async fetch history
  77. * @param {Room} chan
  78. **/
  79. ChatSystem.prototype.fetchHistory = function(chan, cb) {};
  80. /**
  81. * @param {Room} chan
  82. **/
  83. ChatSystem.prototype.sendTyping = function(chan) {};
  84. /**
  85. * @param {Room} chan
  86. * @param {number} ts
  87. **/
  88. ChatSystem.prototype.markRead = function(chan, ts) {};
  89. /**
  90. * @param {Room} chan
  91. * @param {string} cmd
  92. * @param {string} args
  93. **/
  94. ChatSystem.prototype.sendCommand = function(chan, cmd, args) {};
  95. /**
  96. * @param {number} knownVersion
  97. * @param {number} nowTs
  98. * @return {Object|null}
  99. **/
  100. ChatSystem.prototype.poll = function(knownVersion, nowTs) {};
  101. /**
  102. * @constructor
  103. **/
  104. function MultiChatManager() {
  105. /** @type {Array<ChatSystem>} */
  106. this.contexts = [];
  107. }
  108. /**
  109. * @param {ChatSystem} chatSystem
  110. **/
  111. MultiChatManager.prototype.push = function(chatSystem) {
  112. this.contexts.push(chatSystem);
  113. };
  114. /**
  115. * @param {string} id
  116. * @return {ChatSystem|null}
  117. **/
  118. MultiChatManager.prototype.getById = function(id) {
  119. for (var i = 0, nbContexts = this.contexts.length; i < nbContexts; i++)
  120. if (id === this.contexts[i].getId())
  121. return this.contexts[i];
  122. return null;
  123. };
  124. /**
  125. * You may want to return true to break the loop
  126. **/
  127. MultiChatManager.prototype.foreachChannels = function(cb) {
  128. for (var i =0, nbCtx =this.contexts.length; i < nbCtx; i++) {
  129. var ctx = this.contexts[i].getChatContext();
  130. for (var chanId in ctx.channels)
  131. if (cb(ctx.channels[chanId], chanId) === true)
  132. return;
  133. }
  134. };
  135. /**
  136. * You may want to return true to break the loop
  137. **/
  138. MultiChatManager.prototype.foreachContext = function(cb) {
  139. for (var i =0, nbCtx =this.contexts.length; i < nbCtx; i++)
  140. if (cb(this.contexts[i].getChatContext()) === true)
  141. return;
  142. };
  143. /**
  144. * @param {string} chanId
  145. * @return {ChatSystem|null}
  146. **/
  147. MultiChatManager.prototype.getChannelContext = function(chanId) {
  148. for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
  149. var ctx = this.contexts[i].getChatContext();
  150. if (ctx.channels[chanId])
  151. return this.contexts[i];
  152. }
  153. return null;
  154. };
  155. /**
  156. * @param {string} userId
  157. * @return {ChatSystem|null}
  158. **/
  159. MultiChatManager.prototype.getUserContext = function(userId) {
  160. for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
  161. var ctx = this.contexts[i].getChatContext();
  162. if (ctx.users[userId])
  163. return this.contexts[i];
  164. }
  165. return null;
  166. };
  167. /**
  168. * @param {string} chanId
  169. * @return {Room|null}
  170. **/
  171. MultiChatManager.prototype.getChannel = function(chanId) {
  172. for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
  173. var chan = this.contexts[i].getChatContext().channels[chanId];
  174. if (chan)
  175. return chan;
  176. }
  177. return null;
  178. };
  179. /**
  180. * @param {function(Room, ChatSystem, string):boolean=} filter (room, roomId)
  181. * @return {Array<string>}
  182. **/
  183. MultiChatManager.prototype.getChannelIds = function(filter) {
  184. var ids = [];
  185. for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
  186. var channels = this.contexts[i].getChatContext().channels;
  187. for (var chanId in channels) {
  188. if (!filter || filter(channels[chanId], this.contexts[i], chanId)) {
  189. ids.push(chanId);
  190. }
  191. }
  192. }
  193. return ids;
  194. };
  195. /**
  196. * @param {string} userId
  197. * @return {Chatter|null}
  198. **/
  199. MultiChatManager.prototype.getUser = function(userId) {
  200. for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
  201. var user = this.contexts[i].getChatContext().users[userId];
  202. if (user)
  203. return user;
  204. }
  205. return null;
  206. };
  207. /**
  208. * @param {string} userId
  209. * @return {boolean}
  210. **/
  211. MultiChatManager.prototype.isMe = function(userId) {
  212. for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++)
  213. if (this.contexts[i].getChatContext().self.id === userId)
  214. return true;
  215. return false;
  216. };
  217. MultiChatManager.prototype.pollPeriodical = function(knownVersion) {
  218. var liveFeed
  219. ,staticFeed
  220. ,allTyping
  221. ,v = 0
  222. ,now = Date.now()
  223. ,updated = false;
  224. this.contexts.forEach(function(ctx) {
  225. var id = ctx.getId();
  226. if (id) {
  227. var res = ctx.poll(knownVersion, now);
  228. if (res) {
  229. if (res["static"]) {
  230. if (!staticFeed)
  231. staticFeed = {};
  232. staticFeed[id] = res["static"];
  233. }
  234. if (res["live"])
  235. if (!liveFeed)
  236. liveFeed = {};
  237. for (var i in res["live"]) {
  238. liveFeed[i] = res["live"][i];
  239. }
  240. if (res["typing"]) {
  241. if (!allTyping)
  242. allTyping = {};
  243. for (var i in res["typing"])
  244. allTyping[i] = res["typing"][i];
  245. }
  246. v = Math.max(v, (res["v"] || 0));
  247. updated = true;
  248. }
  249. }
  250. });
  251. if (updated)
  252. return ({
  253. "live": liveFeed,
  254. "static": staticFeed,
  255. "typing": allTyping,
  256. "v": Math.max(v, knownVersion)
  257. });
  258. };
  259. MultiChatManager.prototype.startPolling = function(knownVersion, reqT, callback) {
  260. var _this = this;
  261. var res = _this.pollPeriodical(knownVersion),
  262. now = Date.now();
  263. if (res) {
  264. callback(res);
  265. } else if (now -reqT > POLL_TIMEOUT) {
  266. callback({
  267. "v": knownVersion
  268. });
  269. } else {
  270. setTimeout(function() { _this.startPolling(knownVersion, reqT, callback); }, 2000);
  271. }
  272. };
  273. /**
  274. * @param {number} knownVersion
  275. * @param {Function} callback
  276. * @param {(function(number, function((Array<{expose:Function, modified: number}>|null))))=} checkConfigUpdate
  277. **/
  278. MultiChatManager.prototype.poll = function(knownVersion, reqT, callback, checkConfigUpdate) {
  279. this.contexts.forEach(function(ctx) {
  280. ctx.onRequest();
  281. });
  282. var _this = this;
  283. if (checkConfigUpdate) {
  284. checkConfigUpdate(knownVersion, function(config) {
  285. if (config) {
  286. var exposedConfig = [],
  287. v = 0;
  288. config.forEach(function(conf) {
  289. exposedConfig.push(conf.expose());
  290. v = Math.max(v, conf.modified);
  291. });
  292. var res = _this.pollPeriodical(knownVersion);
  293. if (res) {
  294. res["config"] = exposedConfig;
  295. callback(res);
  296. } else {
  297. callback({
  298. "config": exposedConfig,
  299. "v": v
  300. });
  301. }
  302. } else {
  303. _this.startPolling(knownVersion, reqT, callback);
  304. }
  305. });
  306. } else {
  307. _this.startPolling(knownVersion, reqT, callback);
  308. }
  309. };
  310. /** @suppress {undefinedVars,checkTypes} */
  311. (function() {
  312. if (typeof module !== "undefined") {
  313. module.exports.MultiChatManager = MultiChatManager;
  314. }
  315. })();