您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

functions.js 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /* @flow */
  2. import JSSHA from 'jssha';
  3. import parseURLParams from './parseURLParams';
  4. declare var $: Object;
  5. /**
  6. * The config keys to ignore because, for example, their values identify scripts
  7. * and it is not desireable to inject these through URL params.
  8. *
  9. * @private
  10. * @type Array
  11. */
  12. const _KEYS_TO_IGNORE = [
  13. 'analyticsScriptUrls',
  14. 'callStatsCustomScriptUrl'
  15. ];
  16. const logger = require('jitsi-meet-logger').getLogger(__filename);
  17. // XXX The functions getRoomName and parseURLParams are split out of
  18. // functions.js because they are bundled in both app.bundle and
  19. // do_external_connect, webpack 1 does not support tree shaking, and we don't
  20. // want all functions to be bundled in do_external_connect.
  21. export { default as getRoomName } from './getRoomName';
  22. export { parseURLParams };
  23. /* eslint-disable no-shadow */
  24. /**
  25. * Looks for a list of possible BOSH addresses in {@code config.boshList} and
  26. * sets the value of {@code config.bosh} based on that list and
  27. * {@code roomName}.
  28. *
  29. * @param {Object} config - The configuration object.
  30. * @param {string} roomName - The name of the room/conference.
  31. * @returns {void}
  32. */
  33. export function chooseBOSHAddress(config: Object, roomName: string) {
  34. if (!roomName) {
  35. return;
  36. }
  37. const { boshList } = config;
  38. if (!boshList || !Array.isArray(boshList) || !boshList.length) {
  39. return;
  40. }
  41. // This implements the actual choice of an entry in the list based on
  42. // roomName. Please consider the implications for existing deployments
  43. // before introducing changes.
  44. const hash = (new JSSHA(roomName, 'TEXT')).getHash('SHA-1', 'HEX');
  45. const n = parseInt(hash.substr(-6), 16);
  46. let idx = n % boshList.length;
  47. config.bosh = boshList[idx];
  48. logger.log(`Setting config.bosh to ${config.bosh} (idx=${idx})`);
  49. const { boshAttemptFirstList } = config;
  50. if (boshAttemptFirstList
  51. && Array.isArray(boshAttemptFirstList)
  52. && boshAttemptFirstList.length > 0) {
  53. idx = n % boshAttemptFirstList.length;
  54. const attemptFirstAddress = boshAttemptFirstList[idx];
  55. if (attemptFirstAddress === config.bosh) {
  56. logger.log('Not setting config.boshAttemptFirst, address matches.');
  57. } else {
  58. config.boshAttemptFirst = attemptFirstAddress;
  59. logger.log(
  60. `Setting config.boshAttemptFirst=${attemptFirstAddress} (idx=${
  61. idx})`);
  62. }
  63. }
  64. }
  65. /* eslint-enable no-shadow */
  66. /**
  67. * Sends HTTP POST request to specified <tt>endpoint</tt>. In request the name
  68. * of the room is included in JSON format:
  69. * {
  70. * "rooomName": "someroom12345"
  71. * }.
  72. *
  73. * @param {string} endpoint - The name of HTTP endpoint to which to send
  74. * the HTTP POST request.
  75. * @param {string} roomName - The name of the conference room for which config
  76. * is requested.
  77. * @param {Function} complete - The callback to invoke upon success or failure.
  78. * @returns {void}
  79. */
  80. export function obtainConfig(
  81. endpoint: string,
  82. roomName: string,
  83. complete: Function) {
  84. logger.info(`Send config request to ${endpoint} for room: ${roomName}`);
  85. $.ajax(
  86. endpoint,
  87. {
  88. contentType: 'application/json',
  89. data: JSON.stringify({ roomName }),
  90. dataType: 'json',
  91. method: 'POST',
  92. error(jqXHR, textStatus, errorThrown) {
  93. logger.error('Get config error: ', jqXHR, errorThrown);
  94. complete(false, `Get config response status: ${textStatus}`);
  95. },
  96. success(data) {
  97. const { config, interfaceConfig, loggingConfig } = window;
  98. try {
  99. overrideConfigJSON(
  100. config, interfaceConfig, loggingConfig,
  101. data);
  102. complete(true);
  103. } catch (e) {
  104. logger.error('Parse config error: ', e);
  105. complete(false, e);
  106. }
  107. }
  108. }
  109. );
  110. }
  111. /* eslint-disable max-params, no-shadow */
  112. /**
  113. * Overrides JSON properties in {@code config} and
  114. * {@code interfaceConfig} Objects with the values from {@code newConfig}.
  115. *
  116. * @param {Object} config - The config Object in which we'll be overriding
  117. * properties.
  118. * @param {Object} interfaceConfig - The interfaceConfig Object in which we'll
  119. * be overriding properties.
  120. * @param {Object} loggingConfig - The loggingConfig Object in which we'll be
  121. * overriding properties.
  122. * @param {Object} json - Object containing configuration properties.
  123. * Destination object is selected based on root property name:
  124. * {
  125. * config: {
  126. * // config.js properties here
  127. * },
  128. * interfaceConfig: {
  129. * // interface_config.js properties here
  130. * },
  131. * loggingConfig: {
  132. * // logging_config.js properties here
  133. * }
  134. * }.
  135. * @returns {void}
  136. */
  137. export function overrideConfigJSON(
  138. config: Object, interfaceConfig: Object, loggingConfig: Object,
  139. json: Object) {
  140. for (const configName of Object.keys(json)) {
  141. let configObj;
  142. if (configName === 'config') {
  143. configObj = config;
  144. } else if (configName === 'interfaceConfig') {
  145. configObj = interfaceConfig;
  146. } else if (configName === 'loggingConfig') {
  147. configObj = loggingConfig;
  148. }
  149. if (configObj) {
  150. const configJSON = json[configName];
  151. for (const key of Object.keys(configJSON)) {
  152. const oldValue = configObj[key];
  153. const newValue = configJSON[key];
  154. if (oldValue && typeof oldValue !== typeof newValue) {
  155. logger.log(
  156. `Overriding a ${configName
  157. } property with a property of different type.`);
  158. }
  159. logger.info(`Overriding ${key} with: ${newValue}`);
  160. configObj[key] = newValue;
  161. }
  162. }
  163. }
  164. }
  165. /* eslint-enable max-params, no-shadow */
  166. /**
  167. * Converts 'URL_PARAMS' to JSON object.
  168. * We have:
  169. * {
  170. * "config.disableAudioLevels": false,
  171. * "config.channelLastN": -1,
  172. * "interfaceConfig.APP_NAME": "Jitsi Meet"
  173. * }.
  174. * We want to have:
  175. * {
  176. * "config": {
  177. * "disableAudioLevels": false,
  178. * "channelLastN": -1
  179. * },
  180. * interfaceConfig: {
  181. * "APP_NAME": "Jitsi Meet"
  182. * }
  183. * }.
  184. *
  185. * @returns {void}
  186. */
  187. export function setConfigFromURLParams() {
  188. const params = parseURLParams(window.location);
  189. const { config, interfaceConfig, loggingConfig } = window;
  190. const json = {};
  191. // TODO We're still in the middle ground between old Web with config,
  192. // interfaceConfig, and loggingConfig used via global variables and new Web
  193. // and mobile reading the respective values from the redux store. On React
  194. // Native there's no interfaceConfig at all yet and loggingConfig is not
  195. // loaded but there's a default value in the redux store.
  196. config && (json.config = {});
  197. interfaceConfig && (json.interfaceConfig = {});
  198. loggingConfig && (json.loggingConfig = {});
  199. for (const param of Object.keys(params)) {
  200. const objEnd = param.indexOf('.');
  201. if (objEnd !== -1) {
  202. const obj = param.substring(0, objEnd);
  203. if (json.hasOwnProperty(obj)) {
  204. const key = param.substring(objEnd + 1);
  205. // Prevent passing some parameters which can inject scripts.
  206. if (key && _KEYS_TO_IGNORE.indexOf(key) === -1) {
  207. json[obj][key] = params[param];
  208. }
  209. }
  210. }
  211. }
  212. overrideConfigJSON(config, interfaceConfig, loggingConfig, json);
  213. }