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 &&