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.

middleware.js 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // @flow
  2. import { CONFERENCE_FAILED, CONFERENCE_JOINED } from '../base/conference';
  3. import { JitsiConferenceErrors, JitsiConferenceEvents } from '../base/lib-jitsi-meet';
  4. import { getFirstLoadableAvatarUrl, getParticipantDisplayName } from '../base/participants';
  5. import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
  6. import { NOTIFICATION_TYPE, showNotification } from '../notifications';
  7. import { isPrejoinPageEnabled } from '../prejoin/functions';
  8. import { KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED } from './actionTypes';
  9. import {
  10. hideLobbyScreen,
  11. knockingParticipantLeft,
  12. openLobbyScreen,
  13. participantIsKnockingOrUpdated,
  14. setLobbyModeEnabled,
  15. startKnocking,
  16. setPasswordJoinFailed
  17. } from './actions';
  18. MiddlewareRegistry.register(store => next => action => {
  19. switch (action.type) {
  20. case CONFERENCE_FAILED:
  21. return _conferenceFailed(store, next, action);
  22. case CONFERENCE_JOINED:
  23. return _conferenceJoined(store, next, action);
  24. case KNOCKING_PARTICIPANT_ARRIVED_OR_UPDATED: {
  25. // We need the full update result to be in the store already
  26. const result = next(action);
  27. _findLoadableAvatarForKnockingParticipant(store, action.participant);
  28. return result;
  29. }
  30. }
  31. return next(action);
  32. });
  33. /**
  34. * Registers a change handler for state['features/base/conference'].conference to
  35. * set the event listeners needed for the lobby feature to operate.
  36. */
  37. StateListenerRegistry.register(
  38. state => state['features/base/conference'].conference,
  39. (conference, { dispatch, getState }, previousConference) => {
  40. if (conference && !previousConference) {
  41. conference.on(JitsiConferenceEvents.MEMBERS_ONLY_CHANGED, enabled => {
  42. dispatch(setLobbyModeEnabled(enabled));
  43. });
  44. conference.on(JitsiConferenceEvents.LOBBY_USER_JOINED, (id, name) => {
  45. dispatch(participantIsKnockingOrUpdated({
  46. id,
  47. name
  48. }));
  49. });
  50. conference.on(JitsiConferenceEvents.LOBBY_USER_UPDATED, (id, participant) => {
  51. dispatch(participantIsKnockingOrUpdated({
  52. ...participant,
  53. id
  54. }));
  55. });
  56. conference.on(JitsiConferenceEvents.LOBBY_USER_LEFT, id => {
  57. dispatch(knockingParticipantLeft(id));
  58. });
  59. conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, (origin, sender) =>
  60. _maybeSendLobbyNotification(origin, sender, {
  61. dispatch,
  62. getState
  63. })
  64. );
  65. }
  66. });
  67. /**
  68. * Function to handle the conference failed event and navigate the user to the lobby screen
  69. * based on the failure reason.
  70. *
  71. * @param {Object} store - The Redux store.
  72. * @param {Function} next - The Redux next function.
  73. * @param {Object} action - The Redux action.
  74. * @returns {Object}
  75. */
  76. function _conferenceFailed({ dispatch, getState }, next, action) {
  77. const { error } = action;
  78. const state = getState();
  79. const nonFirstFailure = Boolean(state['features/base/conference'].membersOnly);
  80. if (error.name === JitsiConferenceErrors.MEMBERS_ONLY_ERROR) {
  81. if (typeof error.recoverable === 'undefined') {
  82. error.recoverable = true;
  83. }
  84. const result = next(action);
  85. dispatch(openLobbyScreen());
  86. if (isPrejoinPageEnabled(state) && !state['features/lobby'].knocking) {
  87. // prejoin is enabled, so we knock automatically
  88. dispatch(startKnocking());
  89. }
  90. dispatch(setPasswordJoinFailed(nonFirstFailure));
  91. return result;
  92. }
  93. dispatch(hideLobbyScreen());
  94. if (error.name === JitsiConferenceErrors.CONFERENCE_ACCESS_DENIED) {
  95. dispatch(showNotification({
  96. appearance: NOTIFICATION_TYPE.ERROR,
  97. hideErrorSupportLink: true,
  98. titleKey: 'lobby.joinRejectedMessage'
  99. }));
  100. }
  101. return next(action);
  102. }
  103. /**
  104. * Handles cleanup of lobby state when a conference is joined.
  105. *
  106. * @param {Object} store - The Redux store.
  107. * @param {Function} next - The Redux next function.
  108. * @param {Object} action - The Redux action.
  109. * @returns {Object}
  110. */
  111. function _conferenceJoined({ dispatch }, next, action) {
  112. dispatch(hideLobbyScreen());
  113. return next(action);
  114. }
  115. /**
  116. * Finds the loadable avatar URL and updates the participant accordingly.
  117. *
  118. * @param {Object} store - The Redux store.
  119. * @param {Object} participant - The knocking participant.
  120. * @returns {void}
  121. */
  122. function _findLoadableAvatarForKnockingParticipant({ dispatch, getState }, { id }) {
  123. const updatedParticipant = getState()['features/lobby'].knockingParticipants.find(p => p.id === id);
  124. const { disableThirdPartyRequests } = getState()['features/base/config'];
  125. if (!disableThirdPartyRequests && updatedParticipant && !updatedParticipant.loadableAvatarUrl) {
  126. getFirstLoadableAvatarUrl(updatedParticipant).then(loadableAvatarUrl => {
  127. if (loadableAvatarUrl) {
  128. dispatch(participantIsKnockingOrUpdated({
  129. loadableAvatarUrl,
  130. id
  131. }));
  132. }
  133. });
  134. }
  135. }
  136. /**
  137. * Check the endpoint message that arrived through the conference and
  138. * sends a lobby notification, if the message belongs to the feature.
  139. *
  140. * @param {Object} origin - The origin (initiator) of the message.
  141. * @param {Object} message - The actual message.
  142. * @param {Object} store - The Redux store.
  143. * @returns {void}
  144. */
  145. function _maybeSendLobbyNotification(origin, message, { dispatch, getState }) {
  146. if (!origin?._id || message?.type !== 'lobby-notify') {
  147. return;
  148. }
  149. const notificationProps: any = {
  150. descriptionArguments: {
  151. originParticipantName: getParticipantDisplayName(getState, origin._id),
  152. targetParticipantName: message.name
  153. },
  154. titleKey: 'lobby.notificationTitle'
  155. };
  156. switch (message.event) {
  157. case 'LOBBY-ENABLED':
  158. notificationProps.descriptionKey = `lobby.notificationLobby${message.value ? 'En' : 'Dis'}abled`;
  159. break;
  160. case 'LOBBY-ACCESS-GRANTED':
  161. notificationProps.descriptionKey = 'lobby.notificationLobbyAccessGranted';
  162. break;
  163. case 'LOBBY-ACCESS-DENIED':
  164. notificationProps.descriptionKey = 'lobby.notificationLobbyAccessDenied';
  165. break;
  166. }
  167. dispatch(showNotification(notificationProps, 5000));
  168. }