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.8KB

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