Merge pull request #561 from jitsi/connection_optimization

Implements server side connection establishment
This commit is contained in:
damencho 2016-03-30 14:30:36 -05:00
commit 8a80df2828
9 changed files with 207 additions and 51 deletions

View File

@ -31,8 +31,9 @@ deploy-appbundle:
deploy-lib-jitsi-meet:
cp $(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.js \
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map $(DEPLOY_DIR)
$(LIBJITSIMEET_DIR)/lib-jitsi-meet.min.map \
$(LIBJITSIMEET_DIR)/connection_optimization/external_connect.js \
$(DEPLOY_DIR)
deploy-css:
(cd css; cat $(CSS_FILES)) | $(CLEANCSS) > css/all.css

40
app.js
View File

@ -1,4 +1,4 @@
/* global $, JitsiMeetJS, config */
/* global $, JitsiMeetJS, config, getRoomName */
/* application specific logic */
import "babel-polyfill";
@ -23,40 +23,34 @@ import API from './modules/API/API';
import UIEvents from './service/UI/UIEvents';
function buildRoomName () {
let path = window.location.pathname;
let roomName;
// 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
roomName = config.getroomnode(path);
} else {
/* fall back to default strategy
* this is making assumptions about how the URL->room mapping happens.
* It currently assumes deployment at root, with a rewrite like the
* following one (for nginx):
location ~ ^/([a-zA-Z0-9]+)$ {
rewrite ^/(.*)$ / break;
}
/**
* Builds and returns the room name.
*/
if (path.length > 1) {
roomName = path.substr(1).toLowerCase();
} else {
function buildRoomName () {
let roomName = getRoomName();
if(!roomName) {
let word = RoomnameGenerator.generateRoomWithoutSeparator();
roomName = word.toLowerCase();
window.history.pushState(
'VideoChat', `Room: ${word}`, window.location.pathname + word
);
}
}
return roomName;
}
const APP = {
// Used by do_external_connect.js if we receive the attach data after
// connect was already executed. status property can be "initialized",
// "ready" or "connecting". We are interested in "ready" status only which
// means that connect was executed but we have to wait for the attach data.
// In status "ready" handler property will be set to a function that will
// finish the connect process when the attach data or error is received.
connect: {
status: "initialized",
handler: null
},
UI,
settings,
conference,

View File

@ -5,6 +5,42 @@ import LoginDialog from './modules/UI/authentication/LoginDialog';
const ConnectionEvents = JitsiMeetJS.events.connection;
const ConnectionErrors = JitsiMeetJS.errors.connection;
/**
* Checks if we have data to use attach instead of connect. If we have the data
* executes attach otherwise check if we have to wait for the data. If we have
* to wait for the attach data we are setting handler to APP.connect.handler
* which is going to be called when the attach data is received otherwise
* executes connect.
*
* @param {string} [id] user id
* @param {string} [password] password
* @param {string} [roomName] the name of the conference.
*/
function checkForAttachParametersAndConnect(id, password, connection) {
if(window.XMPPAttachInfo){
APP.connect.status = "connecting";
// When connection optimization is not deployed or enabled the default
// value will be window.XMPPAttachInfo.status = "error"
// If the connection optimization is deployed and enabled and there is
// a failure the value will be window.XMPPAttachInfo.status = "error"
if(window.XMPPAttachInfo.status === "error") {
connection.connect({id, password});
return;
}
var attachOptions = window.XMPPAttachInfo.data;
if(attachOptions) {
connection.attach(attachOptions);
} else {
connection.connect({id, password});
}
} else {
APP.connect.status = "ready";
APP.connect.handler = checkForAttachParametersAndConnect.bind(null,
id, password, connection);
}
}
/**
* Try to open connection using provided credentials.
* @param {string} [id]
@ -18,7 +54,8 @@ function connect(id, password, roomName) {
let connectionConfig = config;
connectionConfig.bosh += '?room=' + roomName;
let connection = new JitsiMeetJS.JitsiConnection(null, null, config);
let connection
= new JitsiMeetJS.JitsiConnection(null, config.token, config);
return new Promise(function (resolve, reject) {
connection.addEventListener(
@ -50,7 +87,7 @@ function connect(id, password, roomName) {
reject(err);
}
connection.connect({id, password});
checkForAttachParametersAndConnect(id, password, connection);
});
}

View File

@ -0,0 +1,80 @@
/* global config, getRoomName, getConfigParamsFromUrl */
/* global createConnectionExternally */
/**
* Implements extrnal connect using createConnectionExtenally function defined
* in external_connect.js for Jitsi Meet. Parses the room name and token from
* the url and executes createConnectionExtenally.
*
* NOTE: If you are using lib-jitsi-meet without Jitsi Meet you should use this
* file as reference only because the implementation is Jitsi Meet specific.
*
* NOTE: For optimal results this file should be included right after
* exrnal_connect.js.
*/
/**
* Gets the token from the URL.
*/
function buildToken(){
var params = getConfigParamsFromUrl();
return params["config.token"] || config.token;
}
/**
* Executes createConnectionExternally function.
*/
(function () {
// FIXME: Add implementation for changing that config from the url for
// consistency
var url = config.externalConnectUrl;
/**
* Check if connect from connection.js was executed and executes the handler
* that is going to finish the connect work.
*/
function checkForConnectHandlerAndConnect() {
if(window.APP && window.APP.connect.status === "ready") {
window.APP.connect.handler();
}
}
function error_callback(error){
if(error) //error=undefined if external connect is disabled.
console.warn(error);
// Sets that global variable to be used later by connect method in
// connection.js
window.XMPPAttachInfo = {
status: "error"
};
checkForConnectHandlerAndConnect();
}
if(!url || !window.createConnectionExternally) {
error_callback();
return;
}
var room_name = getRoomName();
if(!room_name) {
error_callback();
return;
}
url += "?room=" + room_name;
var token = buildToken();
if(token)
url += "&token=" + token;
createConnectionExternally(url, function(connectionInfo) {
// Sets that global variable to be used later by connect method in
// connection.js
window.XMPPAttachInfo = {
status: "success",
data: connectionInfo
};
checkForConnectHandlerAndConnect();
}, error_callback);
})();

View File

@ -9,3 +9,4 @@ sounds /usr/share/jitsi-meet/
fonts /usr/share/jitsi-meet/
images /usr/share/jitsi-meet/
lang /usr/share/jitsi-meet/
connection_optimization /usr/share/jitsi-meet/

View File

@ -1,6 +1,14 @@
<html itemscope itemtype="http://schema.org/Product" prefix="og: http://ogp.me/ns#" xmlns="http://www.w3.org/1999/html">
<head>
<!--#include virtual="title.html" -->
<script>console.log("(TIME) index.html loaded:\t", window.performance.now());</script>
<script src="config.js?v=15"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="utils.js?v=1"></script>
<!--#include virtual="connection_optimization/connection_optimization.html" -->
<script src="connection_optimization/do_external_connect.js?v=1"></script>
<script src="interface_config.js?v=6"></script>
<script src="libs/lib-jitsi-meet.min.js?v=139"></script>
<script src="libs/app.bundle.min.js?v=139"></script>
<link rel="icon" type="image/png" href="/images/favicon.ico?v=1"/>
<meta property="og:title" content="Jitsi Meet"/>
<meta property="og:image" content="/images/jitsilogo.png?v=1"/>
@ -10,11 +18,6 @@
<meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
<meta itemprop="image" content="/images/jitsilogo.png?v=1"/>
<link rel="stylesheet" href="css/all.css"/>
<script>console.log("(TIME) index.html loaded:\t", window.performance.now());</script>
<script src="config.js?v=15"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="interface_config.js?v=6"></script>
<script src="libs/lib-jitsi-meet.min.js?v=139"></script>
<script src="libs/app.bundle.min.js?v=139"></script>
<!--#include virtual="plugin.head.html" -->
</head>
<body>

View File

@ -1,18 +1,6 @@
/* global $, $iq, config, interfaceConfig */
/* global $, $iq, config, interfaceConfig, getConfigParamsFromUrl */
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();

52
utils.js Normal file
View File

@ -0,0 +1,52 @@
/* global config */
/**
* Defines some utility methods that are used before the other JS files are
* loaded.
*/
/**
* Builds and returns the room name.
*/
function getRoomName () {
var path = window.location.pathname;
var roomName;
// 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
roomName = config.getroomnode(path);
} else {
/* fall back to default strategy
* this is making assumptions about how the URL->room mapping happens.
* It currently assumes deployment at root, with a rewrite like the
* following one (for nginx):
location ~ ^/([a-zA-Z0-9]+)$ {
rewrite ^/(.*)$ / break;
}
*/
if (path.length > 1) {
roomName = path.substr(1).toLowerCase();
}
}
return roomName;
}
/**
* Parses the hash parameters from the URL and returns them as a JS object.
*/
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;
}