Merge branch 'feat-client-reconnect' into develop

auto_join_3.3
Håvar Aambø Fosstveit 2020-03-28 23:24:18 +01:00
commit 9da1afd4af
4 changed files with 154 additions and 45 deletions

View File

@ -1595,6 +1595,50 @@ export default class RoomClient
}) })
})); }));
if (this._screenSharingProducer)
{
this._screenSharingProducer.close();
store.dispatch(
producerActions.removeProducer(this._screenSharingProducer.id));
this._screenSharingProducer = null;
}
if (this._webcamProducer)
{
this._webcamProducer.close();
store.dispatch(
producerActions.removeProducer(this._webcamProducer.id));
this._webcamProducer = null;
}
if (this._micProducer)
{
this._micProducer.close();
store.dispatch(
producerActions.removeProducer(this._micProducer.id));
this._micProducer = null;
}
if (this._sendTransport)
{
this._sendTransport.close();
this._sendTransport = null;
}
if (this._recvTransport)
{
this._recvTransport.close();
this._recvTransport = null;
}
store.dispatch(roomActions.setRoomState('connecting')); store.dispatch(roomActions.setRoomState('connecting'));
}); });
@ -1796,6 +1840,13 @@ export default class RoomClient
break; break;
} }
case 'roomBack':
{
await this._joinRoom({ joinVideo });
break;
}
case 'lockRoom': case 'lockRoom':
{ {

View File

@ -2,6 +2,8 @@ const EventEmitter = require('events').EventEmitter;
const axios = require('axios'); const axios = require('axios');
const Logger = require('./Logger'); const Logger = require('./Logger');
const Lobby = require('./Lobby'); const Lobby = require('./Lobby');
const { v4: uuidv4 } = require('uuid');
const jwt = require('jsonwebtoken');
const userRoles = require('../userRoles'); const userRoles = require('../userRoles');
const config = require('../config/config'); const config = require('../config/config');
@ -46,6 +48,8 @@ class Room extends EventEmitter
super(); super();
this.setMaxListeners(Infinity); this.setMaxListeners(Infinity);
this._uuid = uuidv4();
// Room ID. // Room ID.
this._roomId = roomId; this._roomId = roomId;
@ -120,22 +124,41 @@ class Room extends EventEmitter
this.emit('close'); this.emit('close');
} }
handlePeer(peer) verifyPeer({ id, token })
{ {
logger.info('handlePeer() [peer:"%s", roles:"%s"]', peer.id, peer.roles); try
{
const decoded = jwt.verify(token, this._uuid);
// Allow reconnections, remove old peer logger.info('verifyPeer() [decoded:"%o"]', decoded);
return decoded.id === id;
}
catch (err)
{
logger.warn('verifyPeer() | invalid token');
}
return false;
}
handlePeer({ peer, returning })
{
logger.info('handlePeer() [peer:"%s", roles:"%s", returning:"%s"]', peer.id, peer.roles, returning);
// Should not happen
if (this._peers[peer.id]) if (this._peers[peer.id])
{ {
logger.warn( logger.warn(
'handleConnection() | there is already a peer with same peerId [peer:"%s"]', 'handleConnection() | there is already a peer with same peerId [peer:"%s"]',
peer.id); peer.id);
this._peers[peer.id].close();
} }
// Returning user
if (returning)
this._peerJoining(peer, true);
// Always let ADMIN in, even if locked // Always let ADMIN in, even if locked
if (peer.roles.includes(userRoles.ADMIN)) else if (peer.roles.includes(userRoles.ADMIN))
this._peerJoining(peer); this._peerJoining(peer);
else if (this._locked) else if (this._locked)
this._parkPeer(peer); this._parkPeer(peer);
@ -332,7 +355,7 @@ class Room extends EventEmitter
} }
} }
async _peerJoining(peer) async _peerJoining(peer, returning = false)
{ {
peer.socket.join(this._roomId); peer.socket.join(this._roomId);
@ -343,45 +366,58 @@ class Room extends EventEmitter
this._handlePeer(peer); this._handlePeer(peer);
let turnServers; if (returning)
if ('turnAPIURI' in config)
{ {
try this._notification(peer.socket, 'roomBack');
{
const { data } = await axios.get(
config.turnAPIURI,
{
params : {
'uri_schema' : 'turn',
'transport' : 'tcp',
'ip_ver' : 'ipv4',
'servercount' : '2',
'api_key' : config.turnAPIKey,
'ip' : peer.socket.request.connection.remoteAddress
}
});
turnServers = [ {
urls : data.uris,
username : data.username,
credential : data.password
} ];
}
catch (error)
{
if ('backupTurnServers' in config)
turnServers = config.backupTurnServers;
logger.error('_peerJoining() | error on REST turn [error:"%o"]', error);
}
} }
else if ('backupTurnServers' in config) else
{ {
turnServers = config.backupTurnServers; const token = jwt.sign({ id: peer.id }, this._uuid, { noTimestamp: true });
}
this._notification(peer.socket, 'roomReady', { turnServers }); peer.socket.handshake.session.token = token;
peer.socket.handshake.session.save();
let turnServers;
if ('turnAPIURI' in config)
{
try
{
const { data } = await axios.get(
config.turnAPIURI,
{
params : {
'uri_schema' : 'turn',
'transport' : 'tcp',
'ip_ver' : 'ipv4',
'servercount' : '2',
'api_key' : config.turnAPIKey,
'ip' : peer.socket.request.connection.remoteAddress
}
});
turnServers = [ {
urls : data.uris,
username : data.username,
credential : data.password
} ];
}
catch (error)
{
if ('backupTurnServers' in config)
turnServers = config.backupTurnServers;
logger.error('_peerJoining() | error on REST turn [error:"%o"]', error);
}
}
else if ('backupTurnServers' in config)
{
turnServers = config.backupTurnServers;
}
this._notification(peer.socket, 'roomReady', { turnServers });
}
} }
_handlePeer(peer) _handlePeer(peer)

View File

@ -25,6 +25,7 @@
"express-socket.io-session": "^1.3.5", "express-socket.io-session": "^1.3.5",
"helmet": "^3.21.2", "helmet": "^3.21.2",
"ims-lti": "^3.0.2", "ims-lti": "^3.0.2",
"jsonwebtoken": "^8.5.1",
"mediasoup": "^3.5.5", "mediasoup": "^3.5.5",
"openid-client": "^3.7.3", "openid-client": "^3.7.3",
"passport": "^0.4.0", "passport": "^0.4.0",
@ -32,6 +33,7 @@
"pidusage": "^2.0.17", "pidusage": "^2.0.17",
"redis": "^2.8.0", "redis": "^2.8.0",
"socket.io": "^2.3.0", "socket.io": "^2.3.0",
"spdy": "^4.0.1" "spdy": "^4.0.1",
"uuid": "^7.0.2"
} }
} }

View File

@ -464,8 +464,28 @@ async function runWebSocketServer()
queue.push(async () => queue.push(async () =>
{ {
const { token } = socket.handshake.session;
const room = await getOrCreateRoom({ roomId }); const room = await getOrCreateRoom({ roomId });
const peer = new Peer({ id: peerId, roomId, socket });
let peer = peers.get(peerId);
let returning = false;
if (peer && !token)
{ // Don't allow hijacking sessions
socket.disconnect(true);
return;
}
else if (token && room.verifyPeer({ id: peerId, token }))
{ // Returning user, remove if old peer exists
if (peer)
peer.close();
returning = true;
}
peer = new Peer({ id: peerId, roomId, socket });
peers.set(peerId, peer); peers.set(peerId, peer);
@ -495,7 +515,7 @@ async function runWebSocketServer()
} }
} }
room.handlePeer(peer); room.handlePeer({ peer, returning });
}) })
.catch((error) => .catch((error) =>
{ {