Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

connection.js 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* global APP, JitsiMeetJS, config */
  2. import { jitsiLocalStorage } from '@jitsi/js-utils';
  3. import Logger from 'jitsi-meet-logger';
  4. import { redirectToTokenAuthService } from './modules/UI/authentication/AuthHandler';
  5. import { hideLoginDialog } from './react/features/authentication/actions.web';
  6. import { LoginDialog } from './react/features/authentication/components';
  7. import { isTokenAuthEnabled } from './react/features/authentication/functions';
  8. import {
  9. connectionEstablished,
  10. connectionFailed
  11. } from './react/features/base/connection/actions';
  12. import { openDialog } from './react/features/base/dialog/actions';
  13. import {
  14. isFatalJitsiConnectionError,
  15. JitsiConnectionErrors,
  16. JitsiConnectionEvents
  17. } from './react/features/base/lib-jitsi-meet';
  18. import { setPrejoinDisplayNameRequired } from './react/features/prejoin/actions';
  19. const logger = Logger.getLogger(__filename);
  20. /**
  21. * The feature announced so we can distinguish jibri participants.
  22. *
  23. * @type {string}
  24. */
  25. export const DISCO_JIBRI_FEATURE = 'http://jitsi.org/protocol/jibri';
  26. /**
  27. * Checks if we have data to use attach instead of connect. If we have the data
  28. * executes attach otherwise check if we have to wait for the data. If we have
  29. * to wait for the attach data we are setting handler to APP.connect.handler
  30. * which is going to be called when the attach data is received otherwise
  31. * executes connect.
  32. *
  33. * @param {string} [id] user id
  34. * @param {string} [password] password
  35. * @param {string} [roomName] the name of the conference.
  36. */
  37. function checkForAttachParametersAndConnect(id, password, connection) {
  38. if (window.XMPPAttachInfo) {
  39. APP.connect.status = 'connecting';
  40. // When connection optimization is not deployed or enabled the default
  41. // value will be window.XMPPAttachInfo.status = "error"
  42. // If the connection optimization is deployed and enabled and there is
  43. // a failure the value will be window.XMPPAttachInfo.status = "error"
  44. if (window.XMPPAttachInfo.status === 'error') {
  45. connection.connect({
  46. id,
  47. password
  48. });
  49. return;
  50. }
  51. const attachOptions = window.XMPPAttachInfo.data;
  52. if (attachOptions) {
  53. connection.attach(attachOptions);
  54. delete window.XMPPAttachInfo.data;
  55. } else {
  56. connection.connect({
  57. id,
  58. password
  59. });
  60. }
  61. } else {
  62. APP.connect.status = 'ready';
  63. APP.connect.handler
  64. = checkForAttachParametersAndConnect.bind(
  65. null,
  66. id, password, connection);
  67. }
  68. }
  69. /**
  70. * Try to open connection using provided credentials.
  71. * @param {string} [id]
  72. * @param {string} [password]
  73. * @param {string} [roomName]
  74. * @returns {Promise<JitsiConnection>} connection if
  75. * everything is ok, else error.
  76. */
  77. export function connect(id, password, roomName) {
  78. const connectionConfig = Object.assign({}, config);
  79. const { jwt } = APP.store.getState()['features/base/jwt'];
  80. // Use Websocket URL for the web app if configured. Note that there is no 'isWeb' check, because there's assumption
  81. // that this code executes only on web browsers/electron. This needs to be changed when mobile and web are unified.
  82. let serviceUrl = connectionConfig.websocket || connectionConfig.bosh;
  83. serviceUrl += `?room=${roomName}`;
  84. // FIXME Remove deprecated 'bosh' option assignment at some point(LJM will be accepting only 'serviceUrl' option
  85. // in future). It's included for the time being for Jitsi Meet and lib-jitsi-meet versions interoperability.
  86. connectionConfig.serviceUrl = connectionConfig.bosh = serviceUrl;
  87. if (connectionConfig.websocketKeepAliveUrl) {
  88. connectionConfig.websocketKeepAliveUrl += `?room=${roomName}`;
  89. }
  90. const connection = new JitsiMeetJS.JitsiConnection(null, jwt, connectionConfig);
  91. if (config.iAmRecorder) {
  92. connection.addFeature(DISCO_JIBRI_FEATURE);
  93. }
  94. return new Promise((resolve, reject) => {
  95. connection.addEventListener(
  96. JitsiConnectionEvents.CONNECTION_ESTABLISHED,
  97. handleConnectionEstablished);
  98. connection.addEventListener(
  99. JitsiConnectionEvents.CONNECTION_FAILED,
  100. handleConnectionFailed);
  101. connection.addEventListener(
  102. JitsiConnectionEvents.CONNECTION_FAILED,
  103. connectionFailedHandler);
  104. connection.addEventListener(
  105. JitsiConnectionEvents.DISPLAY_NAME_REQUIRED,
  106. displayNameRequiredHandler
  107. );
  108. /* eslint-disable max-params */
  109. /**
  110. *
  111. */
  112. function connectionFailedHandler(error, message, credentials, details) {
  113. /* eslint-enable max-params */
  114. APP.store.dispatch(
  115. connectionFailed(
  116. connection, {
  117. credentials,
  118. details,
  119. message,
  120. name: error
  121. }));
  122. if (isFatalJitsiConnectionError(error)) {
  123. connection.removeEventListener(
  124. JitsiConnectionEvents.CONNECTION_FAILED,
  125. connectionFailedHandler);
  126. }
  127. }
  128. /**
  129. *
  130. */
  131. function unsubscribe() {
  132. connection.removeEventListener(
  133. JitsiConnectionEvents.CONNECTION_ESTABLISHED,
  134. handleConnectionEstablished);
  135. connection.removeEventListener(
  136. JitsiConnectionEvents.CONNECTION_FAILED,
  137. handleConnectionFailed);
  138. }
  139. /**
  140. *
  141. */
  142. function handleConnectionEstablished() {
  143. APP.store.dispatch(connectionEstablished(connection, Date.now()));
  144. unsubscribe();
  145. resolve(connection);
  146. }
  147. /**
  148. *
  149. */
  150. function handleConnectionFailed(err) {
  151. unsubscribe();
  152. logger.error('CONNECTION FAILED:', err);
  153. reject(err);
  154. }
  155. /**
  156. * Marks the display name for the prejoin screen as required.
  157. * This can happen if a user tries to join a room with lobby enabled.
  158. */
  159. function displayNameRequiredHandler() {
  160. APP.store.dispatch(setPrejoinDisplayNameRequired());
  161. }
  162. checkForAttachParametersAndConnect(id, password, connection);
  163. });
  164. }
  165. /**
  166. * Open JitsiConnection using provided credentials.
  167. * If retry option is true it will show auth dialog on PASSWORD_REQUIRED error.
  168. *
  169. * @param {object} options
  170. * @param {string} [options.id]
  171. * @param {string} [options.password]
  172. * @param {string} [options.roomName]
  173. * @param {boolean} [retry] if we should show auth dialog
  174. * on PASSWORD_REQUIRED error.
  175. *
  176. * @returns {Promise<JitsiConnection>}
  177. */
  178. export function openConnection({ id, password, retry, roomName }) {
  179. const usernameOverride
  180. = jitsiLocalStorage.getItem('xmpp_username_override');
  181. const passwordOverride
  182. = jitsiLocalStorage.getItem('xmpp_password_override');
  183. if (usernameOverride && usernameOverride.length > 0) {
  184. id = usernameOverride; // eslint-disable-line no-param-reassign
  185. }
  186. if (passwordOverride && passwordOverride.length > 0) {
  187. password = passwordOverride; // eslint-disable-line no-param-reassign
  188. }
  189. return connect(id, password, roomName).catch(err => {
  190. if (retry) {
  191. const { jwt } = APP.store.getState()['features/base/jwt'];
  192. if (err === JitsiConnectionErrors.PASSWORD_REQUIRED && !jwt) {
  193. return requestAuth(roomName);
  194. }
  195. }
  196. throw err;
  197. });
  198. }
  199. /**
  200. * Show Authentication Dialog and try to connect with new credentials.
  201. * If failed to connect because of PASSWORD_REQUIRED error
  202. * then ask for password again.
  203. * @param {string} [roomName] name of the conference room
  204. *
  205. * @returns {Promise<JitsiConnection>}
  206. */
  207. function requestAuth(roomName) {
  208. const config = APP.store.getState()['features/base/config'];
  209. if (isTokenAuthEnabled(config)) {
  210. // This Promise never resolves as user gets redirected to another URL
  211. return new Promise(() => redirectToTokenAuthService(roomName));
  212. }
  213. return new Promise(resolve => {
  214. const onSuccess = connection => {
  215. APP.store.dispatch(hideLoginDialog());
  216. resolve(connection);
  217. };
  218. APP.store.dispatch(
  219. openDialog(LoginDialog, { onSuccess,
  220. roomName })
  221. );
  222. });
  223. }