Merge branch 'develop' of github.com:havfo/multiparty-meeting into develop

auto_join_3.3
Håvar Aambø Fosstveit 2020-04-07 19:47:47 +02:00
commit 7510a5da27
15 changed files with 363 additions and 23 deletions

View File

@ -1,20 +1,32 @@
# Changelog # Changelog
## 3.2.1
* Fix: permananent top bar by default
* Fix: `httpOnly` mode https redirect
* Add some extra checks for video stream and track
* Add Italian translation
* Add Czech translation
* Add new server option `trustProxy` for load balancing http only use case
* Add HAproxy load balance example
* Add LTI LMS integration documentation
* Fix spacing of leave button
* Fix for sharing same file multiple times
## 3.2 ## 3.2
* Add munin plugin * Add munin plugin
* Add muted=true search param to disble audio by deffault * Add `muted=true` search param to disable audio by default
* Modify webtorrent tracker * Modify webtorrent tracker
* Add key shortcut `space` for audio mute * Add key shortcut `space` for audio mute
* Add key shortcut `v` for video mute * Add key shortcut `v` for video mute
* Add user configurable LastN * Add user configurable LastN
* Add option to sticky top bar (sticky by default) * Add option to permananent top bar (permanent by default)
* update mediasoup server * Update mediasoup server
* Add simulcast options to app config (disabled by default) * Add `simulcast` options to app config (disabled by default)
* Add stats option to get counts of rooms and peers * Add `stats` option to get counts of rooms and peers
* Add httpOnly option for loadbalancer backend setups * Add `httpOnly` option for loadbalancer backend setups
* LTI integration for LMS systems like moodle * LTI integration for LMS systems like moodle
* Add muted=false search parameter
* Add translations (12+1 languages) * Add translations (12+1 languages)
* Add support IPv6 * Add support IPv6
* Many other fixes and refactorings * Many other fixes and refactorings
@ -33,10 +45,10 @@
* Updated to mediasoup v3 * Updated to mediasoup v3
* Replace lib "passport-datporten" with "openid-client" (a general OIDC certified client) * Replace lib "passport-datporten" with "openid-client" (a general OIDC certified client)
- OpenID Connect discovery * OpenID Connect discovery
- Auth code flow * Auth code flow
* Add spdy http2 support. * Add spdy http2 support.
- Notice it does not supports node 11.x * Notice it does not supports node 11.x
* Updated to Material UI v4 * Updated to Material UI v4
## 2.0 ## 2.0

109
HAproxy.md 100644
View File

@ -0,0 +1,109 @@
# Howto deploy a (room based) load balanced cluster
This example will show how to setup an HA proxy to provide load balancing between several
multiparty-meeting servers.
## IP and DNS
In this basic example we use the following names and ips:
### Backend
* `mm1.example.com` <=> `192.0.2.1`
* `mm2.example.com` <=> `192.0.2.2`
* `mm3.example.com` <=> `192.0.2.3`
### Redis
* `redis.example.com` <=> `192.0.2.4`
### Load balancer HAproxy
* `meet.example.com` <=> `192.0.2.5`
## Deploy multiple multiparty-meeting servers
This is most easily done using Ansible (see below), but can be done
in any way you choose (manual, Docker, Ansible).
Read more here: [mm-ansible](https://github.com/misi/mm-ansible)
[![asciicast](https://asciinema.org/a/311365.svg)](https://asciinema.org/a/311365)
## Setup Redis for central HTTP session store
### Use one Redis for all multiparty-meeting servers
* Deploy a Redis cluster for all instances.
* We will use in our actual example `192.0.2.4` as redis HA cluster ip. It is out of scope howto deploy it.
OR
* For testing you can use Redis from one the multiparty-meeting servers. e.g. If you plan only for testing on your first multiparty-meeting server.
* Configure Redis `redis.conf` to not only bind to your loopback but also to your global ip address too:
``` plaintext
bind 192.0.2.1
```
This example sets this to `192.0.2.1`, change this according to your local installation.
* Change your firewall config to allow incoming Redis. Example (depends on the type of firewall):
``` plaintext
chain INPUT {
policy DROP;
saddr mm2.example.com proto tcp dport 6379 ACCEPT;
saddr mm3.example.com proto tcp dport 6379 ACCEPT;
}
```
* **Set a password, or if you don't (like in this basic example) take care to set strict firewall rules**
## Configure multiparty-meeting servers
### App config
mm/configs/app/config.js
``` js
multipartyServer : 'meet.example.com',
```
### Server config
mm/configs/server/config.js
``` js
redisOptions : { host: '192.0.2.4'},
listeningPort: 80,
httpOnly: true,
trustProxy : ['192.0.2.5'],
```
## Deploy HA proxy
* Configure cerificate / letsencrypt for `meet.example.com`
* In this example we put a complete chain and private key in /root/certificate.pem.
* Install and setup haproxy
`apt install haproxy`
* Add to /etc/haproxy/haproxy.cfg config
``` plaintext
backend multipartymeeting
balance url_param roomId
hash-type consistent
server mm1 192.0.2.1:80 check maxconn 20 verify none
server mm2 192.0.2.2:80 check maxconn 20 verify none
server mm3 192.0.2.3:80 check maxconn 20 verify none
frontend meet.example.com
bind 192.0.2.5:80
bind 192.0.2.5:443 ssl crt /root/certificate.pem
http-request redirect scheme https unless { ssl_fc }
reqadd X-Forwarded-Proto:\ https
default_backend multipartymeeting
```

61
LTI/LTI.md 100644
View File

@ -0,0 +1,61 @@
# Learning Tools Interoperability (LTI)
## LTI
Read more about IMS Global defined interface for tools like our VideoConference system integration with Learning Managment Systems(LMS) (e.g. moodle).
See: [IMS Global Learning Tool Interoperability](https://www.imsglobal.org/activity/learning-tools-interoperability)
We implemented LTI interface version 1.0/1.1
### Server config auth section LTI settings
Set in server configuration a random key and secret
``` json
auth :
{
lti :
{
consumerKey : 'key',
consumerSecret : 'secret'
},
}
```
### Configure your LMS system with secret and key settings above
#### Auth tool URL
Set tool URL to your server with path /auth/lti
``` url
https://mm.example.com/auth/lti
```
#### In moodle find external tool plugin setting and external tool action
See: [moodle external tool settings](https://docs.moodle.org/38/en/External_tool_settings)
#### Add and activity
![Add external tool](lti1.png)
#### Setup Activity
##### Activity setup basic form
Open fully the settings **Click on show more!!**
![Add external tool config](lti2.png)
##### Empty full form
![Opened external tool config](lti3.png)
##### Filled out form
![Filled out external tool config](lti4.png)
## moodle plugin
Alternativly you can use multipartymeeting moodle plugin:
[https://github.com/misi/moodle-mod_multipartymeeting](https://github.com/misi/moodle-mod_multipartymeeting)

BIN
LTI/lti1.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
LTI/lti2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
LTI/lti3.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
LTI/lti4.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

View File

@ -21,7 +21,6 @@ If you want the automatic approach, you can find a docker image [here](https://h
If you want the ansible approach, you can find ansible role [here](https://github.com/misi/mm-ansible/). If you want the ansible approach, you can find ansible role [here](https://github.com/misi/mm-ansible/).
[![asciicast](https://asciinema.org/a/311365.svg)](https://asciinema.org/a/311365) [![asciicast](https://asciinema.org/a/311365.svg)](https://asciinema.org/a/311365)
## Manual installation ## Manual installation
* Prerequisites: * Prerequisites:
Currently multiparty-meeting will only run on nodejs v10.* Currently multiparty-meeting will only run on nodejs v10.*
@ -106,6 +105,12 @@ $ systemctl enable multiparty-meeting
* 4443/tcp (default `npm start` port for developing with live browser reload, not needed in production enviroments - adjustable in app/package.json) * 4443/tcp (default `npm start` port for developing with live browser reload, not needed in production enviroments - adjustable in app/package.json)
* 40000-49999/udp/tcp (media ports - adjustable in `server/config.js`) * 40000-49999/udp/tcp (media ports - adjustable in `server/config.js`)
## Load balanced installation
To deploy this as a load balanced cluster, have a look at [HAproxy](HAproxy.md).
## Learning management integration
To integrate with an LMS (e.g. Moodle), have a look at [LTI](LTI/LTI.md).
## TURN configuration ## TURN configuration
* You need an addtional [TURN](https://github.com/coturn/coturn)-server for clients located behind restrictive firewalls! Add your server and credentials to `app/config.js` * You need an addtional [TURN](https://github.com/coturn/coturn)-server for clients located behind restrictive firewalls! Add your server and credentials to `app/config.js`

View File

@ -78,8 +78,8 @@ const styles = (theme) =>
}, },
actionButton : actionButton :
{ {
margin : theme.spacing(1), margin : theme.spacing(1, 0),
padding : 0 padding : theme.spacing(0, 1)
} }
}); });

View File

@ -34,7 +34,9 @@ import messagesPortuguese from './translations/pt';
import messagesChinese from './translations/cn'; import messagesChinese from './translations/cn';
import messagesSpanish from './translations/es'; import messagesSpanish from './translations/es';
import messagesCroatian from './translations/hr'; import messagesCroatian from './translations/hr';
import messagesCzech from './translations/cz'; import messagesCzech from './translations/cs';
import messagesItalian from './translations/it';
import messagesUkrainian from './translations/uk';
import './index.css'; import './index.css';
@ -57,7 +59,9 @@ const messages =
'zh' : messagesChinese, 'zh' : messagesChinese,
'es' : messagesSpanish, 'es' : messagesSpanish,
'hr' : messagesCroatian, 'hr' : messagesCroatian,
'cz' : messagesCzech 'cs' : messagesCzech,
'it' : messagesItalian,
'uk' : messagesUkrainian
}; };
const locale = navigator.language.split(/[-_]/)[0]; // language without region code const locale = navigator.language.split(/[-_]/)[0]; // language without region code

View File

@ -6,7 +6,7 @@
"room.chooseRoom": "Wybór konferencji", "room.chooseRoom": "Wybór konferencji",
"room.cookieConsent": "Ta strona internetowa wykorzystuje pliki cookie w celu zwiększenia wygody użytkowania.", "room.cookieConsent": "Ta strona internetowa wykorzystuje pliki cookie w celu zwiększenia wygody użytkowania.",
"room.consentUnderstand": "I understand", "room.consentUnderstand": "Rozumiem",
"room.joined": "Podłączono do konferencji", "room.joined": "Podłączono do konferencji",
"room.cantJoin": "Brak możliwości dołączenia do pokoju", "room.cantJoin": "Brak możliwości dołączenia do pokoju",
"room.youLocked": "Zakluczono pokój", "room.youLocked": "Zakluczono pokój",
@ -103,7 +103,7 @@
"settings.selectRoomLayout": "Ustawienia układu konferencji", "settings.selectRoomLayout": "Ustawienia układu konferencji",
"settings.advancedMode": "Tryb zaawansowany", "settings.advancedMode": "Tryb zaawansowany",
"settings.permanentTopBar": "Stały górny pasek", "settings.permanentTopBar": "Stały górny pasek",
"settings.lastn": "Liczba widocznych filmów", "settings.lastn": "Liczba widocznych uczestników (zdalnych)",
"filesharing.saveFileError": "Nie można zapisać pliku", "filesharing.saveFileError": "Nie można zapisać pliku",
"filesharing.startingFileShare": "Próba udostępnienia pliku", "filesharing.startingFileShare": "Próba udostępnienia pliku",

View File

@ -0,0 +1,140 @@
{
"socket.disconnected": "Ви відключені",
"socket.reconnecting": "Ви від'єдналися, намагаєтесь знову підключитися",
"socket.reconnected": "Ви знову підключилися",
"socket.requestError": "Помилка при запиті сервера",
"room.chooseRoom": "Виберіть назву кімнати, до якої хочете приєднатися",
"room.cookieConsent": "Цей веб-сайт використовує файли cookie для поліпшення роботи користувачів",
"room.consentUnderstand": "Я розумію",
"room.joined": "Ви приєдналися до кімнати",
"room.cantJoin": "Неможливо приєднатися до кімнати",
"room.youLocked": "Ви заблокували кімнату",
"room.cantLock": "Не вдається заблокувати кімнату",
"room.youUnLocked": "Ви розблокували кімнату",
"room.cantUnLock": "Не вдається розблокувати кімнату",
"room.locked": "Кімната зараз заблокована",
"room.unlocked": "Кімната зараз розблокована",
"room.newLobbyPeer": "Новий учасник увійшов у зал очікування",
"room.lobbyPeerLeft": "Учасник вийшов із зала очікування",
"room.lobbyPeerChangedDisplayName": "Учасник у залі очікування змінив ім'я на {displayName}",
"room.lobbyPeerChangedPicture": "Учасник залу очікування змінив зображення",
"room.setAccessCode": "Код доступу до кімнати оновлений",
"room.accessCodeOn": "Код доступу до кімнати зараз активований",
"room.accessCodeOff": "Код доступу до кімнати зараз відключений",
"room.peerChangedDisplayName": "{oldDisplayName} змінив ім'я на {displayName}",
"room.newPeer": "{displayName} приєднався до кімнати",
"room.newFile": "Новий файл є у доступі",
"room.toggleAdvancedMode": "Увімкнено розширений режим",
"room.setDemocratView": "Змінено макет на демократичний вигляд",
"room.setFilmStripView": "Змінено макет на вид фільму",
"room.loggedIn": "Ви ввійшли в систему",
"room.loggedOut": "Ви вийшли з системи",
"room.changedDisplayName": "Відображуване ім’я змінено на {displayName}",
"room.changeDisplayNameError": "Сталася помилка під час зміни вашого відображуваного імені",
"room.chatError": "Не вдається надіслати повідомлення в чаті",
"room.aboutToJoin": "Ви збираєтесь приєднатися до зустрічі",
"room.roomId": "Ідентифікатор кімнати: {roomName}",
"room.setYourName": "Встановіть своє ім'я для участі та виберіть, як ви хочете приєднатися:",
"room.audioOnly": "Тільки аудіо",
"room.audioVideo": "Аудіо та відео",
"room.youAreReady": "Добре, ви готові",
"room.emptyRequireLogin": "Кімната порожня! Ви можете увійти, щоб розпочати зустріч або чекати, поки хост приєднається",
"room.locketWait": "Кімната заблокована - дочекайтеся, поки хтось не впустить вас у ...",
"room.lobbyAdministration": "Адміністрація залу очікування",
"room.peersInLobby": "Учасники залу очікувань",
"room.lobbyEmpty": "Наразі у залі очікувань немає нікого",
"room.hiddenPeers": "{hiddenPeersCount, множина, один {учасник} інший {учасників}}",
"room.me": "Я",
"room.spotlights": "Учасники у центрі уваги",
"room.passive": "Пасивні учасники",
"room.videoPaused": "Це відео призупинено",
"tooltip.login": "Увійти",
"tooltip.logout": "Вихід",
"tooltip.admitFromLobby": "Вхід із залу очікувань",
"tooltip.lockRoom": "Заблокувати кімнату",
"tooltip.unLockRoom": "Розблокувати кімнату",
"tooltip.enterFullscreen": "Вивести повний екран",
"tooltip.leaveFullscreen": "Залишити повноекранний екран",
"tooltip.lobby": "Показати зал очікувань",
"tooltip.settings": "Показати налаштування",
"tooltip.participants": "Показати учасників",
"label.roomName": "Назва кімнати",
"label.chooseRoomButton": "Продовжити",
"label.yourName": "Ваше ім'я",
"label.newWindow": "Нове вікно",
"label.fullscreen": "Повний екран",
"label.openDrawer": "Відкрити ящик",
"label.leave": "Залишити",
"label.chatInput": "Введіть повідомлення чату ...",
"label.chat": "Чат",
"label.filesharing": "Обмін файлами",
"label.participants": "Учасники",
"label.shareFile": "Надіслати файл",
"label.fileSharingUnsupported": "Обмін файлами не підтримується",
"label.unknown": "Невідомо",
"label.democrat": "Демократичний вигляд",
"label.filmstrip": "У вигляді кінострічки",
"label.low": "Низький",
"label.medium": "Середній",
"label.high": "Високий (HD)",
"label.veryHigh": "Дуже високий (FHD)",
"label.ultra": "Ультра (UHD)",
"label.close": "Закрити",
"settings.settings": "Налаштування",
"settings.camera": "Камера",
"settings.selectCamera": "Вибрати відеопристрій",
"settings.cantSelectCamera": "Неможливо вибрати відеопристрій",
"settings.audio": "Аудіопристрій",
"settings.selectAudio": "Вибрати аудіопристрій",
"settings.cantSelectAudio": "Неможливо вибрати аудіопристрій",
"settings.resolution": "Виберіть роздільну здатність відео",
"settings.layout": "Розміщення кімнати",
"settings.selectRoomLayout": "Вибір розташування кімнати",
"settings.advancedMode": "Розширений режим",
"settings.permanentTopBar": "Постійний верхній рядок",
"settings.lastn": "Кількість видимих ​​відео",
"filesharing.saveFileError": "Неможливо зберегти файл",
"filesharing.startingFileShare": "Спроба поділитися файлом",
"filesharing.successfulFileShare": "Файл готовий для обміну",
"filesharing.unableToShare": "Неможливо поділитися файлом",
"filesharing.error": "Виникла помилка обміну файлами",
"filesharing.finished": "Завантаження файлу закінчено",
"filesharing.save": "Зберегти",
"filesharing.sharedFile": "{displayName} поділився файлом",
"filesharing.download": "Завантажити",
"filesharing.missingSeeds": "Якщо цей процес триває тривалий час, може не з’явиться хтось, хто роздає цей торрент. Спробуйте попросити когось перезавантажити потрібний файл.",
"devices.devicesChanged": "Ваші пристрої змінилися, налаштуйте ваші пристрої в діалоговому вікні налаштувань",
"device.audioUnsupported": "Аудіо не підтримується",
"device.activateAudio": "Активувати звук",
"device.muteAudio": "Вимкнути звук",
"device.unMuteAudio": "Увімкнути звук",
"device.videoUnsupported": "Відео не підтримується",
"device.startVideo": "Запустити відео",
"device.stopVideo": "Зупинити відео",
"device.screenSharingUnsupported": "Обмін екраном не підтримується",
"device.startScreenSharing": "Початок спільного використання екрана",
"device.stopScreenSharing": "Зупинити спільний доступ до екрана",
"devices.microphoneDisconnected": "Мікрофон відключений",
"devices.microphoneError": "Сталася помилка під час доступу до мікрофона",
"devices.microPhoneMute": "Вимкнено ваш мікрофон",
"devices.micophoneUnMute": "Не ввімкнено ваш мікрофон",
"devices.microphoneEnable": "Увімкнено мікрофон",
"devices.microphoneMuteError": "Не вдається вимкнути мікрофон",
"devices.microphoneUnMuteError": "Неможливо ввімкнути мікрофон",
"devices.screenSharingDisconnected": "Спільний доступ до екрана відключений",
"devices.screenSharingError": "Сталася помилка під час доступу до екрану",
"devices.cameraDisconnected": "Камера відключена",
"devices.cameraError": "Під час доступу до камери сталася помилка"
}

View File

@ -58,6 +58,9 @@ module.exports =
cert : `${__dirname}/../certs/mediasoup-demo.localhost.cert.pem`, cert : `${__dirname}/../certs/mediasoup-demo.localhost.cert.pem`,
key : `${__dirname}/../certs/mediasoup-demo.localhost.key.pem` key : `${__dirname}/../certs/mediasoup-demo.localhost.key.pem`
}, },
// listening Host or IP
// If ommitted listens on every IP. ("0.0.0.0" and "::")
//listeningHost: 'localhost',
// Listening port for https server. // Listening port for https server.
listeningPort : 443, listeningPort : 443,
// Any http request is redirected to https. // Any http request is redirected to https.

View File

@ -189,7 +189,7 @@ function setupLTI(ltiConfig)
const ltiStrategy = new LTIStrategy( const ltiStrategy = new LTIStrategy(
ltiConfig, ltiConfig,
function(req, lti, done) (req, lti, done) =>
{ {
// LTI launch parameters // LTI launch parameters
if (lti) if (lti)
@ -310,7 +310,7 @@ async function setupAuth()
// lti launch // lti launch
app.post('/auth/lti', app.post('/auth/lti',
passport.authenticate('lti', { failureRedirect: '/' }), passport.authenticate('lti', { failureRedirect: '/' }),
function(req, res) (req, res) =>
{ {
res.redirect(`/${req.user.room}`); res.redirect(`/${req.user.room}`);
} }
@ -333,7 +333,7 @@ async function setupAuth()
} }
req.logout(); req.logout();
res.send(logoutHelper()); req.session.destroy(() => res.send(logoutHelper()));
}); });
// callback // callback
@ -427,10 +427,16 @@ async function runHttpsServer()
// http // http
const redirectListener = http.createServer(app); const redirectListener = http.createServer(app);
if(config.listeningHost)
redirectListener.listen(config.listeningRedirectPort, config.listeningHost);
else
redirectListener.listen(config.listeningRedirectPort); redirectListener.listen(config.listeningRedirectPort);
} }
// https or http // https or http
if(config.listeningHost)
mainListener.listen(config.listeningPort, config.listeningHost);
else
mainListener.listen(config.listeningPort); mainListener.listen(config.listeningPort);
} }