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.

functions.js 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* @flow */
  2. import _ from 'lodash';
  3. import Logger from 'jitsi-meet-logger';
  4. import persisterConfig from './persisterconfig.json';
  5. const logger = Logger.getLogger(__filename);
  6. const PERSISTED_STATE_NAME = 'jitsi-state';
  7. /**
  8. * Sets specific properties of a specific state to specific values and prevents
  9. * unnecessary state changes.
  10. *
  11. * @param {Object} target - The state on which the specified properties are to
  12. * be set.
  13. * @param {Object} source - The map of properties to values which are to be set
  14. * on the specified target.
  15. * @returns {Object} The specified target if the values of the specified
  16. * properties equal the specified values; otherwise, a new state constructed
  17. * from the specified target by setting the specified properties to the
  18. * specified values.
  19. */
  20. export function assign(target: Object, source: Object) {
  21. let t = target;
  22. for (const property in source) { // eslint-disable-line guard-for-in
  23. t = _set(t, property, source[property], t === target);
  24. }
  25. return t;
  26. }
  27. /**
  28. * Determines whether {@code a} equals {@code b} according to deep comparison
  29. * (which makes sense for Redux and its state definition).
  30. *
  31. * @param {*} a - The value to compare to {@code b}.
  32. * @param {*} b - The value to compare to {@code a}.
  33. * @returns {boolean} True if {@code a} equals {@code b} (according to deep
  34. * comparison); false, otherwise.
  35. */
  36. export function equals(a: any, b: any) {
  37. return _.isEqual(a, b);
  38. }
  39. /**
  40. * Prepares a filtered state-slice (Redux term) based on the config for
  41. * persisting or for retreival.
  42. *
  43. * @private
  44. * @param {Object} persistedSlice - The redux state-slice.
  45. * @param {Object} persistedSliceConfig - The related config sub-tree.
  46. * @returns {Object}
  47. */
  48. function _getFilteredSlice(persistedSlice, persistedSliceConfig) {
  49. const filteredpersistedSlice = {};
  50. for (const persistedKey of Object.keys(persistedSlice)) {
  51. if (persistedSliceConfig[persistedKey]) {
  52. filteredpersistedSlice[persistedKey] = persistedSlice[persistedKey];
  53. }
  54. }
  55. return filteredpersistedSlice;
  56. }
  57. /**
  58. * Prepares a filtered state from the actual or the
  59. * persisted Redux state, based on the config.
  60. *
  61. * @private
  62. * @param {Object} state - The actual or persisted redux state.
  63. * @returns {Object}
  64. */
  65. function _getFilteredState(state: Object) {
  66. const filteredState = {};
  67. for (const slice of Object.keys(persisterConfig)) {
  68. filteredState[slice] = _getFilteredSlice(
  69. state[slice],
  70. persisterConfig[slice]
  71. );
  72. }
  73. return filteredState;
  74. }
  75. /**
  76. * Returns the persisted redux state. This function takes
  77. * the persisterConfig into account as we may have persisted something
  78. * in the past that we don't want to retreive anymore. The next
  79. * {@link #persistState} will remove those values.
  80. *
  81. * @returns {Object}
  82. */
  83. export function getPersistedState() {
  84. let persistedState = window.localStorage.getItem(PERSISTED_STATE_NAME);
  85. if (persistedState) {
  86. try {
  87. persistedState = JSON.parse(persistedState);
  88. } catch (error) {
  89. return {};
  90. }
  91. const filteredPersistedState = _getFilteredState(persistedState);
  92. logger.info('Redux state rehydrated', filteredPersistedState);
  93. return filteredPersistedState;
  94. }
  95. return {};
  96. }
  97. /**
  98. * Persists a filtered subtree of the redux state into {@code localStorage}.
  99. *
  100. * @param {Object} state - The redux state.
  101. * @returns {void}
  102. */
  103. export function persistState(state: Object) {
  104. const filteredState = _getFilteredState(state);
  105. window.localStorage.setItem(
  106. PERSISTED_STATE_NAME,
  107. JSON.stringify(filteredState)
  108. );
  109. logger.info('Redux state persisted');
  110. }
  111. /**
  112. * Sets a specific property of a specific state to a specific value. Prevents
  113. * unnecessary state changes (when the specified {@code value} is equal to the
  114. * value of the specified {@code property} of the specified {@code state}).
  115. *
  116. * @param {Object} state - The (Redux) state from which a new state is to be
  117. * constructed by setting the specified {@code property} to the specified
  118. * {@code value}.
  119. * @param {string} property - The property of {@code state} which is to be
  120. * assigned the specified {@code value} (in the new state).
  121. * @param {*} value - The value to assign to the specified {@code property}.
  122. * @returns {Object} The specified {@code state} if the value of the specified
  123. * {@code property} equals the specified <tt>value/tt>; otherwise, a new state
  124. * constructed from the specified {@code state} by setting the specified
  125. * {@code property} to the specified {@code value}.
  126. */
  127. export function set(state: Object, property: string, value: any) {
  128. return _set(state, property, value, /* copyOnWrite */ true);
  129. }
  130. /* eslint-disable max-params */
  131. /**
  132. * Sets a specific property of a specific state to a specific value. Prevents
  133. * unnecessary state changes (when the specified {@code value} is equal to the
  134. * value of the specified {@code property} of the specified {@code state}).
  135. *
  136. * @param {Object} state - The (Redux) state from which a state is to be
  137. * constructed by setting the specified {@code property} to the specified
  138. * {@code value}.
  139. * @param {string} property - The property of {@code state} which is to be
  140. * assigned the specified {@code value}.
  141. * @param {*} value - The value to assign to the specified {@code property}.
  142. * @param {boolean} copyOnWrite - If the specified {@code state} is to not be
  143. * modified, {@code true}; otherwise, {@code false}.
  144. * @returns {Object} The specified {@code state} if the value of the specified
  145. * {@code property} equals the specified <tt>value/tt> or {@code copyOnWrite}
  146. * is truthy; otherwise, a new state constructed from the specified
  147. * {@code state} by setting the specified {@code property} to the specified
  148. * {@code value}.
  149. */
  150. function _set(
  151. state: Object,
  152. property: string,
  153. value: any,
  154. copyOnWrite: boolean) {
  155. // Delete state properties that are to be set to undefined. (It is a matter
  156. // of personal preference, mostly.)
  157. if (typeof value === 'undefined'
  158. && Object.prototype.hasOwnProperty.call(state, property)) {
  159. const newState = copyOnWrite ? { ...state } : state;
  160. if (delete newState[property]) {
  161. return newState;
  162. }
  163. }
  164. if (state[property] !== value) {
  165. if (copyOnWrite) {
  166. return {
  167. ...state,
  168. [property]: value
  169. };
  170. }
  171. state[property] = value;
  172. }
  173. return state;
  174. }
  175. /* eslint-enable max-params */
  176. /**
  177. * Returns redux state from the specified {@code stateful} which is presumed to
  178. * be related to the redux state (e.g. the redux store, the redux
  179. * {@code getState} function).
  180. *
  181. * @param {Function|Object} stateful - The entity such as the redux store or the
  182. * redux {@code getState} function from which the redux state is to be
  183. * returned.
  184. * @returns {Object} The redux state.
  185. */
  186. export function toState(stateful: Function | Object) {
  187. if (stateful) {
  188. if (typeof stateful === 'function') {
  189. return stateful();
  190. }
  191. const { getState } = stateful;
  192. if (typeof getState === 'function') {
  193. return getState();
  194. }
  195. }
  196. return stateful;
  197. }