From a7048fba0644fd37edce4aa7f26ed15afe99c42e Mon Sep 17 00:00:00 2001 From: paweldomas Date: Fri, 21 Aug 2015 14:33:05 +0200 Subject: [PATCH] Implements HTTP POST query for fetching app configuration. --- app.js | 33 +++++++++++++- config.js | 1 + modules/UI/UI.js | 25 ++++++----- modules/URLProcessor/URLProcessor.js | 50 --------------------- modules/config/HttpConfigFetch.js | 55 +++++++++++++++++++++++ modules/config/URLProcessor.js | 65 ++++++++++++++++++++++++++++ modules/config/Util.js | 49 +++++++++++++++++++++ modules/xmpp/moderator.js | 5 ++- modules/xmpp/recording.js | 6 ++- modules/xmpp/xmpp.js | 1 + 10 files changed, 226 insertions(+), 64 deletions(-) delete mode 100644 modules/URLProcessor/URLProcessor.js create mode 100644 modules/config/HttpConfigFetch.js create mode 100644 modules/config/URLProcessor.js create mode 100644 modules/config/Util.js diff --git a/app.js b/app.js index 01beff590..acfe554da 100644 --- a/app.js +++ b/app.js @@ -16,6 +16,7 @@ var APP = this.settings = require("./modules/settings/Settings"); this.DTMF = require("./modules/DTMF/DTMF"); this.members = require("./modules/members/MemberList"); + this.configFetch = require("./modules/config/HttpConfigFetch"); } }; @@ -30,10 +31,38 @@ function init() { APP.members.start(); } +/** + * If we have HTTP endpoint for getting confgi.json configured we're going to + * read it and override properties from config.js and interfaceConfig.js. + * If there is no endpoint we'll just continue with initialization. + * Keep in mind that if the endpoint has been configured and we fail to obtain + * the config for any reason then the conference won't start and error message + * will be displayed to the user. + */ +function obtainConfigAndInit() { + if (config.configLocation) { + APP.configFetch.obtainConfig( + config.configLocation, APP.UI.getRoomNode(), + // Get config result callback + function(success, error) { + if (success) { + init(); + } else { + // Show obtain config error, + // pass the error object for report + APP.UI.messageHandler.openReportDialog( + null, "dialog.connectError", error); + } + }); + } else { + init(); + } +} + $(document).ready(function () { - var URLProcessor = require("./modules/URLProcessor/URLProcessor"); + var URLProcessor = require("./modules/config/URLProcessor"); URLProcessor.setConfigParametersFromUrl(); APP.init(); @@ -42,7 +71,7 @@ $(document).ready(function () { if(APP.API.isEnabled()) APP.API.init(); - APP.UI.start(init); + APP.UI.start(obtainConfigAndInit); }); diff --git a/config.js b/config.js index 8c8637ebc..ec5fe8990 100644 --- a/config.js +++ b/config.js @@ -1,4 +1,5 @@ var config = { +// configLocation: './config.json', // see ./modules/HttpConfigFetch.js hosts: { domain: 'jitsi-meet.example.com', //anonymousdomain: 'guest.example.com', diff --git a/modules/UI/UI.js b/modules/UI/UI.js index b3f08bcf0..c73909fc9 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -33,6 +33,7 @@ var UIEvents = require("../../service/UI/UIEvents"); var MemberEvents = require("../../service/members/Events"); var eventEmitter = new EventEmitter(); +var roomNode = null; var roomName = null; @@ -684,17 +685,16 @@ UI.getLargeVideoResource = function () { return VideoLayout.getLargeVideoResource(); }; -UI.generateRoomName = function() { - if(roomName) - return roomName; - var roomnode = null; +UI.getRoomNode = function () { + if (roomNode) + return roomNode; var path = window.location.pathname; // determinde the room node from the url // TODO: just the roomnode or the whole bare jid? if (config.getroomnode && typeof config.getroomnode === 'function') { // custom function might be responsible for doing the pushstate - roomnode = config.getroomnode(path); + roomNode = config.getroomnode(path); } else { /* fall back to default strategy * this is making assumptions about how the URL->room mapping happens. @@ -705,17 +705,22 @@ UI.generateRoomName = function() { } */ if (path.length > 1) { - roomnode = path.substr(1).toLowerCase(); + roomNode = path.substr(1).toLowerCase(); } else { var word = RoomNameGenerator.generateRoomWithoutSeparator(); - roomnode = word.toLowerCase(); - + roomNode = word.toLowerCase(); window.history.pushState('VideoChat', - 'Room: ' + word, window.location.pathname + word); + 'Room: ' + word, window.location.pathname + word); } } + return roomNode; +}; - roomName = roomnode + '@' + config.hosts.muc; +UI.generateRoomName = function () { + if (roomName) + return roomName; + var roomNode = UI.getRoomNode(); + roomName = roomNode + '@' + config.hosts.muc; return roomName; }; diff --git a/modules/URLProcessor/URLProcessor.js b/modules/URLProcessor/URLProcessor.js deleted file mode 100644 index 0aee2ee53..000000000 --- a/modules/URLProcessor/URLProcessor.js +++ /dev/null @@ -1,50 +0,0 @@ -/* global $, $iq, config, interfaceConfig */ -var params = {}; -function getConfigParamsFromUrl() { - if(!location.hash) - return {}; - var hash = location.hash.substr(1); - var result = {}; - hash.split("&").forEach(function(part) { - var item = part.split("="); - result[item[0]] = JSON.parse( - decodeURIComponent(item[1]).replace(/\\&/, "&")); - }); - return result; -} - -params = getConfigParamsFromUrl(); - -var URLProcessor = { - setConfigParametersFromUrl: function () { - for(var key in params) { - if(typeof key !== "string") - continue; - - var confObj = null, confKey; - if (key.indexOf("config.") === 0) { - confObj = config; - confKey = key.substr("config.".length); - } else if (key.indexOf("interfaceConfig.") === 0) { - confObj = interfaceConfig; - confKey = key.substr("interfaceConfig.".length); - } - - if (!confObj) - continue; - - var value = params[key]; - if (confObj[confKey] && typeof confObj[confKey] !== typeof value) - { - console.warn("The type of " + key + - " is wrong. That parameter won't be updated in config.js."); - continue; - } - - confObj[confKey] = value; - } - - } -}; - -module.exports = URLProcessor; \ No newline at end of file diff --git a/modules/config/HttpConfigFetch.js b/modules/config/HttpConfigFetch.js new file mode 100644 index 000000000..270b59be0 --- /dev/null +++ b/modules/config/HttpConfigFetch.js @@ -0,0 +1,55 @@ +/* global $, $iq, config, interfaceConfig */ + +var configUtil = require('./Util'); + +var HttpConfig = { + /** + * Sends HTTP POST request to specified endpoint. In request + * the name of the room is included in JSON format: + * { + * "rooomName": "someroom12345" + * } + * @param endpoint the name of HTTP endpoint to which HTTP POST request will + * be sent. + * @param roomName the name of the conference room for which config will be + * requested. + * @param complete + */ + obtainConfig: function (endpoint, roomName, complete) { + console.info( + "Send config request to " + endpoint + " for room: " + roomName); + + var request = new XMLHttpRequest(); + var error = null; + request.onreadystatechange = function (aEvt) { + if (request.readyState == 4) { + var status = request.status; + if (status === 200) { + try { + var data = JSON.parse(request.responseText); + configUtil.overrideConfigJSON( + config, interfaceConfig, data); + complete(true); + return; + } catch (exception) { + console.error("Parse config error: ", exception); + error = exception; + } + } else { + console.error("Get config error: ", request, status); + error = "Get config response status: " + status; + } + complete(false, error); + } + }; + + request.open("POST", endpoint, true); + + request.setRequestHeader( + "Content-Type", "application/json;charset=UTF-8"); + + request.send({ "roomName": roomName }); + } +}; + +module.exports = HttpConfig; \ No newline at end of file diff --git a/modules/config/URLProcessor.js b/modules/config/URLProcessor.js new file mode 100644 index 000000000..ceb40b8a0 --- /dev/null +++ b/modules/config/URLProcessor.js @@ -0,0 +1,65 @@ +/* global $, $iq, config, interfaceConfig */ +var configUtils = require('./Util'); +var params = {}; +function getConfigParamsFromUrl() { + if (!location.hash) + return {}; + var hash = location.hash.substr(1); + var result = {}; + hash.split("&").forEach(function (part) { + var item = part.split("="); + result[item[0]] = JSON.parse( + decodeURIComponent(item[1]).replace(/\\&/, "&")); + }); + return result; +} + +params = getConfigParamsFromUrl(); + +var URLProcessor = { + setConfigParametersFromUrl: function () { + // Convert 'params' to JSON object + // We have: + // { + // "config.disableAudioLevels": false, + // "config.channelLastN": -1, + // "interfaceConfig.APP_NAME": "Jitsi Meet" + // } + // We want to have: + // { + // "config": { + // "disableAudioLevels": false, + // "channelLastN": -1 + // }, + // interfaceConfig: { + // APP_NAME: "Jitsi Meet" + // } + // } + var configJSON = { + config: {}, + interfaceConfig: {} + }; + for (var key in params) { + if (typeof key !== "string") { + console.warn("Invalid config key: ", key); + continue; + } + var confObj = null, confKey; + if (key.indexOf("config.") === 0) { + confObj = configJSON.config; + confKey = key.substr("config.".length); + } else if (key.indexOf("interfaceConfig.") === 0) { + confObj = configJSON.interfaceConfig; + confKey = key.substr("interfaceConfig.".length); + } + + if (!confObj) + continue; + + confObj[confKey] = params[key]; + } + configUtils.overrideConfigJSON(config, interfaceConfig, configJSON); + } +}; + +module.exports = URLProcessor; \ No newline at end of file diff --git a/modules/config/Util.js b/modules/config/Util.js new file mode 100644 index 000000000..3b45b9959 --- /dev/null +++ b/modules/config/Util.js @@ -0,0 +1,49 @@ +/* global $ */ +var ConfigUtil = { + /** + * Method overrides JSON properties in config and + * interfaceConfig Objects with the values from newConfig + * @param config the config object for which we'll be overriding properties + * @param interfaceConfig the interfaceConfig object for which we'll be + * overriding properties. + * @param newConfig object containing configuration properties. Destination + * object is selected based on root property name: + * { + * config: { + * // config.js properties to be + * }, + * interfaceConfig: { + * // interfaceConfig.js properties here + * } + * } + */ + overrideConfigJSON: function (config, interfaceConfig, newConfig) { + for (var configRoot in newConfig) { + + var confObj = null; + if (configRoot == "config") { + confObj = config; + } else if (configRoot == "interfaceConfig") { + confObj = interfaceConfig; + } else { + continue; + } + + for (var key in newConfig[configRoot]) { + var value = newConfig[configRoot][key]; + if (confObj[key] && typeof confObj[key] !== typeof value) + { + console.warn( + "The type of " + key + + " is wrong. That parameter won't be updated in: ", + confObj); + continue; + } + console.info("Overriding " + key + " with: " + value); + confObj[key] = value; + } + } + } +}; + +module.exports = ConfigUtil; \ No newline at end of file diff --git a/modules/xmpp/moderator.js b/modules/xmpp/moderator.js index 931d40c53..0c32057dc 100644 --- a/modules/xmpp/moderator.js +++ b/modules/xmpp/moderator.js @@ -35,7 +35,7 @@ var externalAuthEnabled = false; // Sip gateway can be enabled by configuring Jigasi host in config.js or // it will be enabled automatically if focus detects the component through // service discovery. -var sipGatewayEnabled = config.hosts.call_control !== undefined; +var sipGatewayEnabled; var eventEmitter = null; @@ -65,6 +65,9 @@ var Moderator = { this.xmppService = xmpp; eventEmitter = emitter; + sipGatewayEnabled = + config.hosts && config.hosts.call_control !== undefined; + // Message listener that talks to POPUP window function listener(event) { if (event.data && event.data.sessionId) { diff --git a/modules/xmpp/recording.js b/modules/xmpp/recording.js index af986b400..885aa58af 100644 --- a/modules/xmpp/recording.js +++ b/modules/xmpp/recording.js @@ -10,7 +10,7 @@ var recordingEnabled; * Whether to use a jirecon component for recording, or use the videobridge * through COLIBRI. */ -var useJirecon = (typeof config.hosts.jirecon != "undefined"); +var useJirecon; /** * The ID of the jirecon recording session. Jirecon generates it when we @@ -109,6 +109,10 @@ function setRecording(state, token, callback, connection) { } var Recording = { + init: function () { + useJirecon = config.hosts && + (typeof config.hosts.jirecon != "undefined"); + }, toggleRecording: function (tokenEmptyCallback, recordingStateChangeCallback, connection) { if (!Moderator.isModerator()) { console.log( diff --git a/modules/xmpp/xmpp.js b/modules/xmpp/xmpp.js index 6ee7db996..2e87ab201 100644 --- a/modules/xmpp/xmpp.js +++ b/modules/xmpp/xmpp.js @@ -270,6 +270,7 @@ var XMPP = { initStrophePlugins(); registerListeners(); Moderator.init(this, eventEmitter); + Recording.init(); var configDomain = config.hosts.anonymousdomain || config.hosts.domain; // Force authenticated domain if room is appended with '?login=true' if (config.hosts.anonymousdomain &&