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.

actions.js 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // @flow
  2. import { getInviteURL } from '../base/connection';
  3. import { inviteVideoRooms } from '../videosipgw';
  4. import { getParticipants } from '../base/participants';
  5. import {
  6. ADD_PENDING_INVITE_REQUEST,
  7. BEGIN_ADD_PEOPLE,
  8. REMOVE_PENDING_INVITE_REQUESTS,
  9. SET_CALLEE_INFO_VISIBLE,
  10. UPDATE_DIAL_IN_NUMBERS_FAILED,
  11. UPDATE_DIAL_IN_NUMBERS_SUCCESS
  12. } from './actionTypes';
  13. import {
  14. getDialInConferenceID,
  15. getDialInNumbers,
  16. invitePeopleAndChatRooms
  17. } from './functions';
  18. const logger = require('jitsi-meet-logger').getLogger(__filename);
  19. /**
  20. * Creates a (redux) action to signal that a click/tap has been performed on
  21. * {@link InviteButton} and that the execution flow for adding/inviting people
  22. * to the current conference/meeting is to begin.
  23. *
  24. * @returns {{
  25. * type: BEGIN_ADD_PEOPLE
  26. * }}
  27. */
  28. export function beginAddPeople() {
  29. return {
  30. type: BEGIN_ADD_PEOPLE
  31. };
  32. }
  33. /**
  34. * Invites (i.e. sends invites to) an array of invitees (which may be a
  35. * combination of users, rooms, phone numbers, and video rooms).
  36. *
  37. * @param {Array<Object>} invitees - The recepients to send invites to.
  38. * @param {Array<Object>} showCalleeInfo - Indicates whether the
  39. * {@code CalleeInfo} should be displayed or not.
  40. * @returns {Promise<Array<Object>>} A {@code Promise} resolving with an array
  41. * of invitees who were not invited (i.e. invites were not sent to them).
  42. */
  43. export function invite(
  44. invitees: Array<Object>,
  45. showCalleeInfo: boolean = false) {
  46. return (
  47. dispatch: Dispatch<*>,
  48. getState: Function): Promise<Array<Object>> => {
  49. const state = getState();
  50. const participants = getParticipants(state);
  51. const { calleeInfoVisible } = state['features/invite'];
  52. if (showCalleeInfo
  53. && !calleeInfoVisible
  54. && invitees.length === 1
  55. && invitees[0].type === 'user'
  56. && participants.length === 1) {
  57. dispatch(setCalleeInfoVisible(true, invitees[0]));
  58. }
  59. const { conference } = state['features/base/conference'];
  60. if (typeof conference === 'undefined') {
  61. // Invite will fail before CONFERENCE_JOIN. The request will be
  62. // cached in order to be executed on CONFERENCE_JOIN.
  63. return new Promise(resolve => {
  64. dispatch(addPendingInviteRequest({
  65. invitees,
  66. callback: failedInvitees => resolve(failedInvitees)
  67. }));
  68. });
  69. }
  70. let allInvitePromises = [];
  71. let invitesLeftToSend = [ ...invitees ];
  72. const {
  73. callFlowsEnabled,
  74. inviteServiceUrl,
  75. inviteServiceCallFlowsUrl
  76. } = state['features/base/config'];
  77. const inviteUrl = getInviteURL(state);
  78. const { jwt } = state['features/base/jwt'];
  79. // First create all promises for dialing out.
  80. const phoneNumbers
  81. = invitesLeftToSend.filter(({ type }) => type === 'phone');
  82. // For each number, dial out. On success, remove the number from
  83. // {@link invitesLeftToSend}.
  84. const phoneInvitePromises = phoneNumbers.map(item => {
  85. const numberToInvite = item.number;
  86. return conference.dial(numberToInvite)
  87. .then(() => {
  88. invitesLeftToSend
  89. = invitesLeftToSend.filter(
  90. invitee => invitee !== item);
  91. })
  92. .catch(error =>
  93. logger.error('Error inviting phone number:', error));
  94. });
  95. allInvitePromises = allInvitePromises.concat(phoneInvitePromises);
  96. const usersAndRooms
  97. = invitesLeftToSend.filter(
  98. ({ type }) => type === 'user' || type === 'room');
  99. if (usersAndRooms.length) {
  100. // Send a request to invite all the rooms and users. On success,
  101. // filter all rooms and users from {@link invitesLeftToSend}.
  102. const peopleInvitePromise
  103. = invitePeopleAndChatRooms(
  104. callFlowsEnabled
  105. ? inviteServiceCallFlowsUrl : inviteServiceUrl,
  106. inviteUrl,
  107. jwt,
  108. usersAndRooms)
  109. .then(() => {
  110. invitesLeftToSend
  111. = invitesLeftToSend.filter(
  112. ({ type }) => type !== 'user' && type !== 'room');
  113. })
  114. .catch(error => {
  115. dispatch(setCalleeInfoVisible(false));
  116. logger.error('Error inviting people:', error);
  117. });
  118. allInvitePromises.push(peopleInvitePromise);
  119. }
  120. // Sipgw calls are fire and forget. Invite them to the conference, then
  121. // immediately remove them from invitesLeftToSend.
  122. const vrooms
  123. = invitesLeftToSend.filter(({ type }) => type === 'videosipgw');
  124. conference
  125. && vrooms.length > 0
  126. && dispatch(inviteVideoRooms(conference, vrooms));
  127. invitesLeftToSend
  128. = invitesLeftToSend.filter(({ type }) => type !== 'videosipgw');
  129. return (
  130. Promise.all(allInvitePromises)
  131. .then(() => invitesLeftToSend));
  132. };
  133. }
  134. /**
  135. * Sends AJAX requests for dial-in numbers and conference ID.
  136. *
  137. * @returns {Function}
  138. */
  139. export function updateDialInNumbers() {
  140. return (dispatch: Dispatch<*>, getState: Function) => {
  141. const state = getState();
  142. const { dialInConfCodeUrl, dialInNumbersUrl, hosts }
  143. = state['features/base/config'];
  144. const mucURL = hosts && hosts.muc;
  145. if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
  146. // URLs for fetching dial in numbers not defined
  147. return;
  148. }
  149. const { room } = state['features/base/conference'];
  150. Promise.all([
  151. getDialInNumbers(dialInNumbersUrl),
  152. getDialInConferenceID(dialInConfCodeUrl, room, mucURL)
  153. ])
  154. .then(([ dialInNumbers, { conference, id, message } ]) => {
  155. if (!conference || !id) {
  156. return Promise.reject(message);
  157. }
  158. dispatch({
  159. type: UPDATE_DIAL_IN_NUMBERS_SUCCESS,
  160. conferenceID: id,
  161. dialInNumbers
  162. });
  163. })
  164. .catch(error => {
  165. dispatch({
  166. type: UPDATE_DIAL_IN_NUMBERS_FAILED,
  167. error
  168. });
  169. });
  170. };
  171. }
  172. /**
  173. * Sets the visibility of {@code CalleeInfo}.
  174. *
  175. * @param {boolean|undefined} [calleeInfoVisible] - If {@code CalleeInfo} is
  176. * to be displayed/visible, then {@code true}; otherwise, {@code false} or
  177. * {@code undefined}.
  178. * @param {Object|undefined} [initialCalleeInfo] - Callee information.
  179. * @returns {{
  180. * type: SET_CALLEE_INFO_VISIBLE,
  181. * calleeInfoVisible: (boolean|undefined),
  182. * initialCalleeInfo
  183. * }}
  184. */
  185. export function setCalleeInfoVisible(
  186. calleeInfoVisible: boolean,
  187. initialCalleeInfo: ?Object) {
  188. return {
  189. type: SET_CALLEE_INFO_VISIBLE,
  190. calleeInfoVisible,
  191. initialCalleeInfo
  192. };
  193. }
  194. /**
  195. * Adds pending invite request.
  196. *
  197. * @param {Object} request - The request.
  198. * @returns {{
  199. * type: ADD_PENDING_INVITE_REQUEST,
  200. * request: Object
  201. * }}
  202. */
  203. export function addPendingInviteRequest(
  204. request: { invitees: Array<Object>, callback: Function }) {
  205. return {
  206. type: ADD_PENDING_INVITE_REQUEST,
  207. request
  208. };
  209. }
  210. /**
  211. * Removes all pending invite requests.
  212. *
  213. * @returns {{
  214. * type: REMOVE_PENDING_INVITE_REQUEST
  215. * }}
  216. */
  217. export function removePendingInviteRequests() {
  218. return {
  219. type: REMOVE_PENDING_INVITE_REQUESTS
  220. };
  221. }