You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

API.js 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /* global APP */
  2. /**
  3. * Implements API class that communicates with external api class
  4. * and provides interface to access Jitsi Meet features by external
  5. * applications that embed Jitsi Meet
  6. */
  7. import postis from 'postis';
  8. /**
  9. * List of the available commands.
  10. * @type {{
  11. * displayName: inputDisplayNameHandler,
  12. * toggleAudio: toggleAudio,
  13. * toggleVideo: toggleVideo,
  14. * toggleFilmStrip: toggleFilmStrip,
  15. * toggleChat: toggleChat,
  16. * toggleContactList: toggleContactList
  17. * }}
  18. */
  19. let commands = {};
  20. /**
  21. * Object that will execute sendMessage
  22. */
  23. let target = window.opener ? window.opener : window.parent;
  24. /**
  25. * Array of functions that are going to receive the objects passed to this
  26. * window
  27. */
  28. let messageListeners = [];
  29. /**
  30. * Current status (enabled/disabled) of Postis.
  31. */
  32. let enablePostis = false;
  33. /**
  34. * Current status (enabled/disabled) of Post Message API.
  35. */
  36. let enablePostMessage = false;
  37. function initCommands() {
  38. commands = {
  39. displayName: APP.UI.inputDisplayNameHandler,
  40. toggleAudio: APP.conference.toggleAudioMuted,
  41. toggleVideo: APP.conference.toggleVideoMuted,
  42. toggleFilmStrip: APP.UI.toggleFilmStrip,
  43. toggleChat: APP.UI.toggleChat,
  44. toggleContactList: APP.UI.toggleContactList
  45. };
  46. }
  47. /**
  48. * Maps the supported events and their status
  49. * (true it the event is enabled and false if it is disabled)
  50. * @type {{
  51. * incomingMessage: boolean,
  52. * outgoingMessage: boolean,
  53. * displayNameChange: boolean,
  54. * participantJoined: boolean,
  55. * participantLeft: boolean
  56. * }}
  57. */
  58. const events = {
  59. incomingMessage: false,
  60. outgoingMessage:false,
  61. displayNameChange: false,
  62. participantJoined: false,
  63. participantLeft: false
  64. };
  65. /**
  66. * Processes commands from external application.
  67. * @param message the object with the command
  68. */
  69. function processCommand(message) {
  70. if (message.action != "execute") {
  71. console.error("Unknown action of the message");
  72. return;
  73. }
  74. for (var key in message) {
  75. if(commands[key])
  76. commands[key].apply(null, message[key]);
  77. }
  78. }
  79. /**
  80. * Processes events objects from external applications
  81. * @param event the event
  82. */
  83. function processEvent(event) {
  84. if (!event.action) {
  85. console.error("Event with no action is received.");
  86. return;
  87. }
  88. var i = 0;
  89. switch(event.action) {
  90. case "add":
  91. for (; i < event.events.length; i++) {
  92. events[event.events[i]] = true;
  93. }
  94. break;
  95. case "remove":
  96. for (; i < event.events.length; i++) {
  97. events[event.events[i]] = false;
  98. }
  99. break;
  100. default:
  101. console.error("Unknown action for event.");
  102. }
  103. }
  104. /**
  105. * Processes a message event from the external application
  106. * @param event the message event
  107. */
  108. function processMessage(event) {
  109. var message;
  110. try {
  111. message = JSON.parse(event.data);
  112. } catch (e) {
  113. console.error("Cannot parse data", event.data);
  114. return;
  115. }
  116. switch (message.type) {
  117. case "command":
  118. processCommand(message);
  119. break;
  120. case "event":
  121. processEvent(message);
  122. break;
  123. default:
  124. console.warn("Unknown message type");
  125. }
  126. }
  127. /**
  128. * Sends message to the external application.
  129. * @param object {object} the object that will be sent as JSON string
  130. */
  131. function sendMessage(object) {
  132. if(enablePostMessage)
  133. target.postMessage(JSON.stringify(object), "*");
  134. }
  135. /**
  136. * Check whether the API should be enabled or not.
  137. * @returns {boolean}
  138. */
  139. function isEnabled () {
  140. let hash = location.hash;
  141. return !!(hash && hash.indexOf("external=true") > -1 && window.postMessage);
  142. }
  143. /**
  144. * Checks whether the event is enabled ot not.
  145. * @param name the name of the event.
  146. * @returns {*}
  147. */
  148. function isEventEnabled (name) {
  149. return events[name];
  150. }
  151. /**
  152. * Sends event object to the external application that has been subscribed
  153. * for that event.
  154. * @param name the name event
  155. * @param object data associated with the event
  156. */
  157. function triggerEvent (name, object) {
  158. if (isEventEnabled(name) && enablePostMessage) {
  159. sendMessage({
  160. type: "event",
  161. action: "result",
  162. event: name,
  163. result: object
  164. });
  165. }
  166. }
  167. export default {
  168. /**
  169. * Initializes the APIConnector. Setups message event listeners that will
  170. * receive information from external applications that embed Jitsi Meet.
  171. * It also sends a message to the external application that APIConnector
  172. * is initialized.
  173. * @param options {object}
  174. * @param enablePostis {boolean} if true the postis npm
  175. * package for comminication with the parent window will be enabled.
  176. * @param enablePostMessage {boolean} if true the postMessageAPI for
  177. * comminication with the parent window will be enabled.
  178. */
  179. init: function (options = {}) {
  180. options.enablePostMessage = options.enablePostMessage || isEnabled();
  181. if (!options.enablePostis &&
  182. !options.enablePostMessage) {
  183. return;
  184. }
  185. enablePostis = options.enablePostis;
  186. enablePostMessage = options.enablePostMessage;
  187. if(enablePostMessage) {
  188. initCommands();
  189. if (window.addEventListener) {
  190. window.addEventListener('message', processMessage, false);
  191. } else {
  192. window.attachEvent('onmessage', processMessage);
  193. }
  194. sendMessage({type: "system", loaded: true});
  195. }
  196. if(enablePostis) {
  197. this.postis = postis({window: target});
  198. }
  199. },
  200. /**
  201. * Notify external application (if API is enabled) that message was sent.
  202. * @param {string} body message body
  203. */
  204. notifySendingChatMessage (body) {
  205. triggerEvent("outgoingMessage", {"message": body});
  206. },
  207. /**
  208. * Sends message to the external application.
  209. * @param options {object}
  210. * @param method {string}
  211. * @param params {object} the object that will be sent as JSON string
  212. */
  213. sendPostisMessage(options) {
  214. if(enablePostis)
  215. this.postis.send(options);
  216. },
  217. /**
  218. * Adds listener for Postis messages.
  219. * @param method {string} postis mehtod
  220. * @param listener {function}
  221. */
  222. addPostisMessageListener (method, listener) {
  223. if(enablePostis)
  224. this.postis.listen(method, listener);
  225. },
  226. /**
  227. * Notify external application (if API is enabled) that
  228. * message was received.
  229. * @param {string} id user id
  230. * @param {string} nick user nickname
  231. * @param {string} body message body
  232. * @param {number} ts message creation timestamp
  233. */
  234. notifyReceivedChatMessage (id, nick, body, ts) {
  235. if (APP.conference.isLocalId(id)) {
  236. return;
  237. }
  238. triggerEvent(
  239. "incomingMessage",
  240. {"from": id, "nick": nick, "message": body, "stamp": ts}
  241. );
  242. },
  243. /**
  244. * Notify external application (if API is enabled) that
  245. * user joined the conference.
  246. * @param {string} id user id
  247. */
  248. notifyUserJoined (id) {
  249. triggerEvent("participantJoined", {id});
  250. },
  251. /**
  252. * Notify external application (if API is enabled) that
  253. * user left the conference.
  254. * @param {string} id user id
  255. */
  256. notifyUserLeft (id) {
  257. triggerEvent("participantLeft", {id});
  258. },
  259. /**
  260. * Notify external application (if API is enabled) that
  261. * user changed their nickname.
  262. * @param {string} id user id
  263. * @param {string} displayName user nickname
  264. */
  265. notifyDisplayNameChanged (id, displayName) {
  266. triggerEvent("displayNameChange", {id, displayname: displayName});
  267. },
  268. /**
  269. * Removes the listeners.
  270. */
  271. dispose: function () {
  272. if (enablePostMessage) {
  273. if (window.removeEventListener) {
  274. window.removeEventListener("message", processMessage, false);
  275. } else {
  276. window.detachEvent('onmessage', processMessage);
  277. }
  278. }
  279. if(enablePostis)
  280. this.postis.destroy();
  281. }
  282. };