Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

middleware.ts 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import { IStore } from '../app/types';
  2. import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
  3. import { getCurrentConference } from '../base/conference/functions';
  4. import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
  5. import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
  6. import StateListenerRegistry from '../base/redux/StateListenerRegistry';
  7. import { playSound } from '../base/sounds/actions';
  8. import { INCOMING_MSG_SOUND_ID } from '../chat/constants';
  9. import { showNotification } from '../notifications/actions';
  10. import { NOTIFICATION_TIMEOUT_TYPE, NOTIFICATION_TYPE } from '../notifications/constants';
  11. import { RECEIVE_POLL } from './actionTypes';
  12. import { clearPolls, receiveAnswer, receivePoll } from './actions';
  13. import {
  14. COMMAND_ANSWER_POLL,
  15. COMMAND_NEW_POLL,
  16. COMMAND_OLD_POLLS
  17. } from './constants';
  18. import { IAnswer, IPoll, IPollData } from './types';
  19. /**
  20. * Set up state change listener to perform maintenance tasks when the conference
  21. * is left or failed, e.g. Clear messages or close the chat modal if it's left
  22. * open.
  23. */
  24. StateListenerRegistry.register(
  25. state => getCurrentConference(state),
  26. (conference, { dispatch }, previousConference) => {
  27. if (conference !== previousConference) {
  28. // conference changed, left or failed...
  29. // clean old polls
  30. dispatch(clearPolls());
  31. }
  32. });
  33. const parsePollData = (pollData: IPollData): IPoll | null => {
  34. if (typeof pollData !== 'object' || pollData === null) {
  35. return null;
  36. }
  37. const { id, senderId, senderName, question, answers } = pollData;
  38. if (typeof id !== 'string' || typeof senderId !== 'string' || typeof senderName !== 'string'
  39. || typeof question !== 'string' || !(answers instanceof Array)) {
  40. return null;
  41. }
  42. const answersParsed = [];
  43. for (const answer of answers) {
  44. const voters = new Map();
  45. for (const [ voterId, voter ] of Object.entries(answer.voters)) {
  46. if (typeof voter !== 'string') {
  47. return null;
  48. }
  49. voters.set(voterId, voter);
  50. }
  51. answersParsed.push({
  52. name: answer.name,
  53. voters
  54. });
  55. }
  56. return {
  57. changingVote: false,
  58. senderId,
  59. senderName,
  60. question,
  61. showResults: true,
  62. lastVote: null,
  63. answers: answersParsed
  64. };
  65. };
  66. MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
  67. const result = next(action);
  68. switch (action.type) {
  69. case CONFERENCE_JOIN_IN_PROGRESS: {
  70. const { conference } = action;
  71. conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
  72. (_: any, data: any) => _handleReceivePollsMessage(data, dispatch));
  73. conference.on(JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,
  74. (_: any, data: any) => _handleReceivePollsMessage(data, dispatch));
  75. break;
  76. }
  77. // Middleware triggered when a poll is received
  78. case RECEIVE_POLL: {
  79. const state = getState();
  80. const isChatOpen: boolean = state['features/chat'].isOpen;
  81. const isPollsTabFocused: boolean = state['features/chat'].isPollsTabFocused;
  82. // Finally, we notify user they received a new poll if their pane is not opened
  83. if (action.notify && (!isChatOpen || !isPollsTabFocused)) {
  84. dispatch(playSound(INCOMING_MSG_SOUND_ID));
  85. }
  86. break;
  87. }
  88. }
  89. return result;
  90. });
  91. /**
  92. * Handles receiving of polls message command.
  93. *
  94. * @param {Object} data - The json data carried by the polls message.
  95. * @param {Function} dispatch - The dispatch function.
  96. *
  97. * @returns {void}
  98. */
  99. function _handleReceivePollsMessage(data: any, dispatch: IStore['dispatch']) {
  100. switch (data.type) {
  101. case COMMAND_NEW_POLL: {
  102. const { question, answers, pollId, senderId, senderName } = data;
  103. const poll = {
  104. changingVote: false,
  105. senderId,
  106. senderName,
  107. showResults: false,
  108. lastVote: null,
  109. question,
  110. answers: answers.map((answer: IAnswer) => {
  111. return {
  112. name: answer,
  113. voters: new Map()
  114. };
  115. })
  116. };
  117. dispatch(receivePoll(pollId, poll, true));
  118. dispatch(showNotification({
  119. appearance: NOTIFICATION_TYPE.NORMAL,
  120. titleKey: 'polls.notification.title',
  121. descriptionKey: 'polls.notification.description'
  122. }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
  123. break;
  124. }
  125. case COMMAND_ANSWER_POLL: {
  126. const { pollId, answers, voterId, voterName } = data;
  127. const receivedAnswer: IAnswer = {
  128. voterId,
  129. voterName,
  130. pollId,
  131. answers
  132. };
  133. dispatch(receiveAnswer(pollId, receivedAnswer));
  134. break;
  135. }
  136. case COMMAND_OLD_POLLS: {
  137. const { polls } = data;
  138. for (const pollData of polls) {
  139. const poll = parsePollData(pollData);
  140. if (poll === null) {
  141. console.warn('[features/polls] Invalid old poll data');
  142. } else {
  143. dispatch(receivePoll(pollData.id, poll, false));
  144. }
  145. }
  146. break;
  147. }
  148. }
  149. }