Add lightweight load-test webpage, disabled by default (#8514)
Co-authored-by: Hristo Terezov <hristo@jitsi.org> Co-authored-by: damencho <damencho@jitsi.org>
This commit is contained in:
parent
0138f23755
commit
12680c35ca
5
Makefile
5
Makefile
|
@ -16,9 +16,12 @@ WEBPACK_DEV_SERVER = ./node_modules/.bin/webpack-dev-server
|
|||
|
||||
all: compile deploy clean
|
||||
|
||||
compile:
|
||||
compile: compile-load-test
|
||||
$(WEBPACK) -p
|
||||
|
||||
compile-load-test:
|
||||
${NPM} install --prefix load-test && ${NPM} run build --prefix load-test
|
||||
|
||||
clean:
|
||||
rm -fr $(BUILD_DIR)
|
||||
|
||||
|
|
|
@ -15,3 +15,5 @@ resources/robots.txt /usr/share/jitsi-meet/
|
|||
resources/*.sh /usr/share/jitsi-meet/scripts/
|
||||
pwa-worker.js /usr/share/jitsi-meet/
|
||||
manifest.json /usr/share/jitsi-meet/
|
||||
load-test/*.html /usr/share/jitsi-meet/load-test/
|
||||
load-test/libs /usr/share/jitsi-meet/load-test/
|
||||
|
|
|
@ -100,6 +100,15 @@ server {
|
|||
tcp_nodelay on;
|
||||
}
|
||||
|
||||
# load test minimal client, uncomment when used
|
||||
#location ~ ^/_load-test/([^/?&:'"]+)$ {
|
||||
# rewrite ^/_load-test/(.*)$ /load-test/index.html break;
|
||||
#}
|
||||
#location ~ ^/_load-test/libs/(.*)$ {
|
||||
# add_header 'Access-Control-Allow-Origin' '*';
|
||||
# alias /usr/share/jitsi-meet/load-test/libs/$1;
|
||||
#}
|
||||
|
||||
location ~ ^/([^/?&:'"]+)$ {
|
||||
try_files $uri @root_path;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<script><!--#include virtual="/config.js" --></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
|
||||
<script src="../libs/lib-jitsi-meet.min.js?v=139"></script>
|
||||
<script src="libs/load-test-participant.min.js" ></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>Number of participants: <span id="participants">1</span></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,228 @@
|
|||
/* global $, config, JitsiMeetJS */
|
||||
import 'jquery';
|
||||
import { parseURLParams } from '../react/features/base/util/parseURLParams';
|
||||
import { parseURIString } from '../react/features/base/util/uri';
|
||||
|
||||
const params = parseURLParams(window.location, false, 'hash');
|
||||
const { isHuman = false } = params;
|
||||
const {
|
||||
localAudio = params['config.startWithAudioMuted'] !== true,
|
||||
localVideo = params['config.startWithVideoMuted'] !== true,
|
||||
remoteVideo = isHuman,
|
||||
remoteAudio = isHuman
|
||||
} = params;
|
||||
|
||||
const { room: roomName } = parseURIString(window.location.toString());
|
||||
|
||||
let connection = null;
|
||||
|
||||
let isJoined = false;
|
||||
|
||||
let room = null;
|
||||
|
||||
let numParticipants = 1;
|
||||
|
||||
let localTracks = [];
|
||||
const remoteTracks = {};
|
||||
|
||||
window.APP = {
|
||||
conference: {
|
||||
getStats() {
|
||||
return room.connectionQuality.getStats();
|
||||
},
|
||||
getConnectionState() {
|
||||
return room && room.getConnectionState();
|
||||
}
|
||||
},
|
||||
|
||||
get room() {
|
||||
return room;
|
||||
},
|
||||
get connection() {
|
||||
return connection;
|
||||
},
|
||||
get numParticipants() {
|
||||
return numParticipants;
|
||||
},
|
||||
get localTracks() {
|
||||
return localTracks;
|
||||
},
|
||||
get remoteTracks() {
|
||||
return remoteTracks;
|
||||
},
|
||||
get params() {
|
||||
return {
|
||||
roomName,
|
||||
localAudio,
|
||||
localVideo,
|
||||
remoteVideo,
|
||||
remoteAudio
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function setNumberOfParticipants() {
|
||||
$('#participants').text(numParticipants);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles local tracks.
|
||||
* @param tracks Array with JitsiTrack objects
|
||||
*/
|
||||
function onLocalTracks(tracks = []) {
|
||||
localTracks = tracks;
|
||||
for (let i = 0; i < localTracks.length; i++) {
|
||||
if (localTracks[i].getType() === 'video') {
|
||||
$('body').append(`<video autoplay='1' id='localVideo${i}' />`);
|
||||
localTracks[i].attach($(`#localVideo${i}`)[0]);
|
||||
} else {
|
||||
$('body').append(
|
||||
`<audio autoplay='1' muted='true' id='localAudio${i}' />`);
|
||||
localTracks[i].attach($(`#localAudio${i}`)[0]);
|
||||
}
|
||||
if (isJoined) {
|
||||
room.addTrack(localTracks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles remote tracks
|
||||
* @param track JitsiTrack object
|
||||
*/
|
||||
function onRemoteTrack(track) {
|
||||
if (track.isLocal()
|
||||
|| (track.getType() === 'video' && !remoteVideo) || (track.getType() === 'audio' && !remoteAudio)) {
|
||||
return;
|
||||
}
|
||||
const participant = track.getParticipantId();
|
||||
|
||||
if (!remoteTracks[participant]) {
|
||||
remoteTracks[participant] = [];
|
||||
}
|
||||
const idx = remoteTracks[participant].push(track);
|
||||
const id = participant + track.getType() + idx;
|
||||
|
||||
if (track.getType() === 'video') {
|
||||
$('body').append(`<video autoplay='1' id='${id}' />`);
|
||||
} else {
|
||||
$('body').append(`<audio autoplay='1' id='${id}' />`);
|
||||
}
|
||||
track.attach($(`#${id}`)[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* That function is executed when the conference is joined
|
||||
*/
|
||||
function onConferenceJoined() {
|
||||
isJoined = true;
|
||||
for (let i = 0; i < localTracks.length; i++) {
|
||||
room.addTrack(localTracks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
function onUserLeft(id) {
|
||||
numParticipants--;
|
||||
setNumberOfParticipants();
|
||||
if (!remoteTracks[id]) {
|
||||
return;
|
||||
}
|
||||
const tracks = remoteTracks[id];
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
const container = $(`#${id}${tracks[i].getType()}${i + 1}`)[0];
|
||||
|
||||
if (container) {
|
||||
tracks[i].detach(container);
|
||||
container.parentElement.removeChild(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* That function is called when connection is established successfully
|
||||
*/
|
||||
function onConnectionSuccess() {
|
||||
room = connection.initJitsiConference(roomName, config);
|
||||
room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
|
||||
room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
|
||||
room.on(JitsiMeetJS.events.conference.USER_JOINED, id => {
|
||||
numParticipants++;
|
||||
setNumberOfParticipants();
|
||||
remoteTracks[id] = [];
|
||||
});
|
||||
room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);
|
||||
room.join();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when the connection fail.
|
||||
*/
|
||||
function onConnectionFailed() {
|
||||
console.error('Connection Failed!');
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called when we disconnect.
|
||||
*/
|
||||
function disconnect() {
|
||||
console.log('disconnect!');
|
||||
connection.removeEventListener(
|
||||
JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED,
|
||||
onConnectionSuccess);
|
||||
connection.removeEventListener(
|
||||
JitsiMeetJS.events.connection.CONNECTION_FAILED,
|
||||
onConnectionFailed);
|
||||
connection.removeEventListener(
|
||||
JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED,
|
||||
disconnect);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function unload() {
|
||||
for (let i = 0; i < localTracks.length; i++) {
|
||||
localTracks[i].dispose();
|
||||
}
|
||||
room.leave();
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
$(window).bind('beforeunload', unload);
|
||||
$(window).bind('unload', unload);
|
||||
|
||||
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
|
||||
|
||||
JitsiMeetJS.init(config);
|
||||
|
||||
connection = new JitsiMeetJS.JitsiConnection(null, null, config);
|
||||
connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED, onConnectionSuccess);
|
||||
connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_FAILED, onConnectionFailed);
|
||||
connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED, disconnect);
|
||||
connection.connect();
|
||||
|
||||
const devices = [];
|
||||
|
||||
if (localVideo) {
|
||||
devices.push('video');
|
||||
}
|
||||
if (localAudio) {
|
||||
devices.push('audio');
|
||||
}
|
||||
if (devices.length > 0) {
|
||||
JitsiMeetJS.createLocalTracks({ devices })
|
||||
.then(onLocalTracks)
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "jitsi-meet-load-test",
|
||||
"version": "0.0.0",
|
||||
"description": "A load test participant",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jitsi/jitsi-meet"
|
||||
},
|
||||
"keywords": [
|
||||
"jingle",
|
||||
"webrtc",
|
||||
"xmpp",
|
||||
"browser"
|
||||
],
|
||||
"author": "",
|
||||
"readmeFilename": "../README.md",
|
||||
"dependencies": {
|
||||
"jquery": "3.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.5.5",
|
||||
"@babel/plugin-proposal-class-properties": "7.1.0",
|
||||
"@babel/plugin-proposal-export-default-from": "7.0.0",
|
||||
"@babel/plugin-proposal-export-namespace-from": "7.0.0",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "7.4.4",
|
||||
"@babel/plugin-proposal-optional-chaining": "7.2.0",
|
||||
"@babel/plugin-transform-flow-strip-types": "7.0.0",
|
||||
"@babel/preset-env": "7.1.0",
|
||||
"@babel/preset-flow": "7.0.0",
|
||||
"@babel/runtime": "7.5.5",
|
||||
"babel-eslint": "10.0.1",
|
||||
"babel-loader": "8.0.4",
|
||||
"eslint": "5.6.1",
|
||||
"eslint-config-jitsi": "github:jitsi/eslint-config-jitsi#1.0.1",
|
||||
"eslint-plugin-flowtype": "2.50.3",
|
||||
"eslint-plugin-import": "2.14.0",
|
||||
"eslint-plugin-jsdoc": "3.8.0",
|
||||
"expose-loader": "0.7.5",
|
||||
"flow-bin": "0.104.0",
|
||||
"imports-loader": "0.7.1",
|
||||
"string-replace-loader": "2.1.1",
|
||||
"style-loader": "0.19.0",
|
||||
"webpack": "4.27.1",
|
||||
"webpack-bundle-analyzer": "3.4.1",
|
||||
"webpack-cli": "3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"build": "webpack -p"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/* global __dirname */
|
||||
|
||||
const process = require('process');
|
||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
const analyzeBundle = process.argv.indexOf('--analyze-bundle') !== -1;
|
||||
const minimize
|
||||
= process.argv.indexOf('-p') !== -1
|
||||
|| process.argv.indexOf('--optimize-minimize') !== -1;
|
||||
|
||||
/**
|
||||
* Build a Performance configuration object for the given size.
|
||||
* See: https://webpack.js.org/configuration/performance/
|
||||
*/
|
||||
function getPerformanceHints(size) {
|
||||
return {
|
||||
hints: minimize ? 'error' : false,
|
||||
maxAssetSize: size,
|
||||
maxEntrypointSize: size
|
||||
};
|
||||
}
|
||||
|
||||
// The base Webpack configuration to bundle the JavaScript artifacts of
|
||||
// jitsi-meet such as app.bundle.js and external_api.js.
|
||||
const config = {
|
||||
devtool: 'source-map',
|
||||
mode: minimize ? 'production' : 'development',
|
||||
module: {
|
||||
rules: [ {
|
||||
// Transpile ES2015 (aka ES6) to ES5. Accept the JSX syntax by React
|
||||
// as well.
|
||||
|
||||
exclude: [
|
||||
new RegExp(`${__dirname}/node_modules/(?!js-utils)`)
|
||||
],
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
// XXX The require.resolve bellow solves failures to locate the
|
||||
// presets when lib-jitsi-meet, for example, is npm linked in
|
||||
// jitsi-meet.
|
||||
plugins: [
|
||||
require.resolve('@babel/plugin-transform-flow-strip-types'),
|
||||
require.resolve('@babel/plugin-proposal-class-properties'),
|
||||
require.resolve('@babel/plugin-proposal-export-default-from'),
|
||||
require.resolve('@babel/plugin-proposal-export-namespace-from'),
|
||||
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
|
||||
require.resolve('@babel/plugin-proposal-optional-chaining')
|
||||
],
|
||||
presets: [
|
||||
[
|
||||
require.resolve('@babel/preset-env'),
|
||||
|
||||
// Tell babel to avoid compiling imports into CommonJS
|
||||
// so that webpack may do tree shaking.
|
||||
{
|
||||
modules: false,
|
||||
|
||||
// Specify our target browsers so no transpiling is
|
||||
// done unnecessarily. For browsers not specified
|
||||
// here, the ES2015+ profile will be used.
|
||||
targets: {
|
||||
chrome: 58,
|
||||
electron: 2,
|
||||
firefox: 54,
|
||||
safari: 11
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
require.resolve('@babel/preset-flow'),
|
||||
require.resolve('@babel/preset-react')
|
||||
]
|
||||
},
|
||||
test: /\.jsx?$/
|
||||
}, {
|
||||
// Expose jquery as the globals $ and jQuery because it is expected
|
||||
// to be available in such a form by multiple jitsi-meet
|
||||
// dependencies including lib-jitsi-meet.
|
||||
|
||||
loader: 'expose-loader?$!expose-loader?jQuery',
|
||||
test: /\/node_modules\/jquery\/.*\.js$/
|
||||
} ]
|
||||
},
|
||||
node: {
|
||||
// Allow the use of the real filename of the module being executed. By
|
||||
// default Webpack does not leak path-related information and provides a
|
||||
// value that is a mock (/index.js).
|
||||
__filename: true
|
||||
},
|
||||
optimization: {
|
||||
concatenateModules: minimize,
|
||||
minimize
|
||||
},
|
||||
output: {
|
||||
filename: `[name]${minimize ? '.min' : ''}.js`,
|
||||
path: `${__dirname}/libs`,
|
||||
publicPath: 'load-test/libs/',
|
||||
sourceMapFilename: `[name].${minimize ? 'min' : 'js'}.map`
|
||||
},
|
||||
plugins: [
|
||||
analyzeBundle
|
||||
&& new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'disabled',
|
||||
generateStatsFile: true
|
||||
})
|
||||
].filter(Boolean),
|
||||
resolve: {
|
||||
alias: {
|
||||
jquery: `jquery/dist/jquery${minimize ? '.min' : ''}.js`
|
||||
},
|
||||
aliasFields: [
|
||||
'browser'
|
||||
],
|
||||
extensions: [
|
||||
'.web.js',
|
||||
|
||||
// Webpack defaults:
|
||||
'.js',
|
||||
'.json'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = [
|
||||
Object.assign({}, config, {
|
||||
entry: {
|
||||
'load-test-participant': './load-test-participant.js'
|
||||
},
|
||||
performance: getPerformanceHints(3 * 1024 * 1024)
|
||||
})
|
||||
];
|
||||
|
Loading…
Reference in New Issue