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 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /* @flow */
  2. import _ from 'lodash';
  3. import parseURLParams from './parseURLParams';
  4. declare var $: Object;
  5. /**
  6. * The config keys to whitelist, the keys that can be overridden.
  7. * Currently we can only whitelist the first part of the properties, like
  8. * 'p2p.useStunTurn' and 'p2p.enabled' we whitelist all p2p options.
  9. * The whitelist is used only for config.js.
  10. *
  11. * @private
  12. * @type Array
  13. */
  14. const WHITELISTED_KEYS = [
  15. '_peerConnStatusOutOfLastNTimeout',
  16. '_peerConnStatusRtcMuteTimeout',
  17. 'abTesting',
  18. 'alwaysVisibleToolbar',
  19. 'autoEnableDesktopSharing',
  20. 'autoRecord',
  21. 'autoRecordToken',
  22. 'avgRtpStatsN',
  23. 'callStatsConfIDNamespace',
  24. 'callStatsID',
  25. 'callStatsSecret',
  26. 'channelLastN',
  27. 'constraints',
  28. 'debug',
  29. 'debugAudioLevels',
  30. 'defaultLanguage',
  31. 'desktopSharingChromeDisabled',
  32. 'desktopSharingChromeExtId',
  33. 'desktopSharingChromeMinExtVersion',
  34. 'desktopSharingChromeSources',
  35. 'desktopSharingFrameRate',
  36. 'desktopSharingFirefoxDisabled',
  37. 'desktopSharingSources',
  38. 'disable1On1Mode',
  39. 'disableAEC',
  40. 'disableAGC',
  41. 'disableAP',
  42. 'disableAudioLevels',
  43. 'disableDesktopSharing',
  44. 'disableDesktopSharing',
  45. 'disableH264',
  46. 'disableHPF',
  47. 'disableNS',
  48. 'disableRemoteControl',
  49. 'disableRtx',
  50. 'disableSuspendVideo',
  51. 'displayJids',
  52. 'enableDisplayNameInStats',
  53. 'enableLipSync',
  54. 'enableLocalVideoFlip',
  55. 'enableRecording',
  56. 'enableStatsID',
  57. 'enableTalkWhileMuted',
  58. 'enableUserRolesBasedOnToken',
  59. 'etherpad_base',
  60. 'failICE',
  61. 'firefox_fake_device',
  62. 'forceJVB121Ratio',
  63. 'hiddenDomain',
  64. 'hosts',
  65. 'iAmRecorder',
  66. 'iAmSipGateway',
  67. 'ignoreStartMuted',
  68. 'nick',
  69. 'openBridgeChannel',
  70. 'p2p',
  71. 'preferH264',
  72. 'recordingType',
  73. 'requireDisplayName',
  74. 'resolution',
  75. 'startAudioMuted',
  76. 'startAudioOnly',
  77. 'startBitrate',
  78. 'startScreenSharing',
  79. 'startVideoMuted',
  80. 'startWithAudioMuted',
  81. 'startWithVideoMuted',
  82. 'testing',
  83. 'useIPv6',
  84. 'useNicks',
  85. 'useStunTurn',
  86. 'webrtcIceTcpDisable',
  87. 'webrtcIceUdpDisable'
  88. ];
  89. const logger = require('jitsi-meet-logger').getLogger(__filename);
  90. // XXX The functions getRoomName and parseURLParams are split out of
  91. // functions.js because they are bundled in both app.bundle and
  92. // do_external_connect, webpack 1 does not support tree shaking, and we don't
  93. // want all functions to be bundled in do_external_connect.
  94. export { default as getRoomName } from './getRoomName';
  95. export { parseURLParams };
  96. /**
  97. * Sends HTTP POST request to specified {@code endpoint}. In request the name
  98. * of the room is included in JSON format:
  99. * {
  100. * "rooomName": "someroom12345"
  101. * }.
  102. *
  103. * @param {string} endpoint - The name of HTTP endpoint to which to send
  104. * the HTTP POST request.
  105. * @param {string} roomName - The name of the conference room for which config
  106. * is requested.
  107. * @param {Function} complete - The callback to invoke upon success or failure.
  108. * @returns {void}
  109. */
  110. export function obtainConfig(
  111. endpoint: string,
  112. roomName: string,
  113. complete: Function) {
  114. logger.info(`Send config request to ${endpoint} for room: ${roomName}`);
  115. $.ajax(
  116. endpoint,
  117. {
  118. contentType: 'application/json',
  119. data: JSON.stringify({ roomName }),
  120. dataType: 'json',
  121. method: 'POST',
  122. error(jqXHR, textStatus, errorThrown) {
  123. logger.error('Get config error: ', jqXHR, errorThrown);
  124. complete(false, `Get config response status: ${textStatus}`);
  125. },
  126. success(data) {
  127. const { config, interfaceConfig, loggingConfig } = window;
  128. try {
  129. overrideConfigJSON(
  130. config, interfaceConfig, loggingConfig,
  131. data);
  132. complete(true);
  133. } catch (e) {
  134. logger.error('Parse config error: ', e);
  135. complete(false, e);
  136. }
  137. }
  138. }
  139. );
  140. }
  141. /* eslint-disable max-params, no-shadow */
  142. /**
  143. * Overrides JSON properties in {@code config} and
  144. * {@code interfaceConfig} Objects with the values from {@code newConfig}.
  145. * Overrides only the whitelisted keys.
  146. *
  147. * @param {Object} config - The config Object in which we'll be overriding
  148. * properties.
  149. * @param {Object} interfaceConfig - The interfaceConfig Object in which we'll
  150. * be overriding properties.
  151. * @param {Object} loggingConfig - The loggingConfig Object in which we'll be
  152. * overriding properties.
  153. * @param {Object} json - Object containing configuration properties.
  154. * Destination object is selected based on root property name:
  155. * {
  156. * config: {
  157. * // config.js properties here
  158. * },
  159. * interfaceConfig: {
  160. * // interface_config.js properties here
  161. * },
  162. * loggingConfig: {
  163. * // logging_config.js properties here
  164. * }
  165. * }.
  166. * @returns {void}
  167. */
  168. export function overrideConfigJSON(
  169. config: Object, interfaceConfig: Object, loggingConfig: Object,
  170. json: Object) {
  171. for (const configName of Object.keys(json)) {
  172. let configObj;
  173. if (configName === 'config') {
  174. configObj = config;
  175. } else if (configName === 'interfaceConfig') {
  176. configObj = interfaceConfig;
  177. } else if (configName === 'loggingConfig') {
  178. configObj = loggingConfig;
  179. }
  180. if (configObj) {
  181. const configJSON
  182. = _getWhitelistedJSON(configName, json[configName]);
  183. if (!_.isEmpty(configJSON)) {
  184. logger.info(
  185. `Extending ${configName} with: ${
  186. JSON.stringify(configJSON)}`);
  187. // eslint-disable-next-line arrow-body-style
  188. _.mergeWith(configObj, configJSON, (oldValue, newValue) => {
  189. // XXX We don't want to merge the arrays, we want to
  190. // overwrite them.
  191. return Array.isArray(oldValue) ? newValue : undefined;
  192. });
  193. }
  194. }
  195. }
  196. }
  197. /**
  198. * Whitelist only config.js, skips this for others configs
  199. * (interfaceConfig, loggingConfig).
  200. * Only extracts overridden values for keys we allow to be overridden.
  201. *
  202. * @param {string} configName - The config name, one of config,
  203. * interfaceConfig, loggingConfig.
  204. * @param {Object} configJSON - The object with keys and values to override.
  205. * @returns {Object} - The result object only with the keys
  206. * that are whitelisted.
  207. * @private
  208. */
  209. function _getWhitelistedJSON(configName, configJSON) {
  210. if (configName !== 'config') {
  211. return configJSON;
  212. }
  213. return _.pick(configJSON, WHITELISTED_KEYS);
  214. }
  215. /* eslint-enable max-params, no-shadow */
  216. /**
  217. * Converts 'URL_PARAMS' to JSON object.
  218. * We have:
  219. * {
  220. * "config.disableAudioLevels": false,
  221. * "config.channelLastN": -1,
  222. * "interfaceConfig.APP_NAME": "Jitsi Meet"
  223. * }.
  224. * We want to have:
  225. * {
  226. * "config": {
  227. * "disableAudioLevels": false,
  228. * "channelLastN": -1
  229. * },
  230. * interfaceConfig: {
  231. * "APP_NAME": "Jitsi Meet"
  232. * }
  233. * }.
  234. *
  235. * @returns {void}
  236. */
  237. export function setConfigFromURLParams() {
  238. const params = parseURLParams(window.location);
  239. const { config, interfaceConfig, loggingConfig } = window;
  240. const json = {};
  241. // TODO We're still in the middle ground between old Web with config,
  242. // interfaceConfig, and loggingConfig used via global variables and new Web
  243. // and mobile reading the respective values from the redux store. On React
  244. // Native there's no interfaceConfig at all yet and loggingConfig is not
  245. // loaded but there's a default value in the redux store.
  246. config && (json.config = {});
  247. interfaceConfig && (json.interfaceConfig = {});
  248. loggingConfig && (json.loggingConfig = {});
  249. for (const param of Object.keys(params)) {
  250. let base = json;
  251. const names = param.split('.');
  252. const last = names.pop();
  253. for (const name of names) {
  254. base = base[name] = base[name] || {};
  255. }
  256. base[last] = params[param];
  257. }
  258. overrideConfigJSON(config, interfaceConfig, loggingConfig, json);
  259. }