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.

connection.js 7.3KB

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