Cleanup of join logic, and making sure that lobbyPeers are sent to all peers if last peer with PROMOTE_PEER leaves and allowWhenRoleMissing contains PROMOTE_PEER, fixes #303
parent
c73ee5c26b
commit
a9e9a1c1fa
|
|
@ -1,4 +1,5 @@
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const AwaitQueue = require('awaitqueue');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const Logger = require('./Logger');
|
const Logger = require('./Logger');
|
||||||
const Lobby = require('./Lobby');
|
const Lobby = require('./Lobby');
|
||||||
|
|
@ -49,6 +50,8 @@ const roomPermissions =
|
||||||
...config.permissionsFromRoles
|
...config.permissionsFromRoles
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const roomAllowWhenRoleMissing = config.allowWhenRoleMissing || [];
|
||||||
|
|
||||||
const ROUTER_SCALE_SIZE = config.routerScaleSize || 40;
|
const ROUTER_SCALE_SIZE = config.routerScaleSize || 40;
|
||||||
|
|
||||||
class Room extends EventEmitter
|
class Room extends EventEmitter
|
||||||
|
|
@ -115,6 +118,9 @@ class Room extends EventEmitter
|
||||||
// Closed flag.
|
// Closed flag.
|
||||||
this._closed = false;
|
this._closed = false;
|
||||||
|
|
||||||
|
// Joining queue
|
||||||
|
this._queue = new AwaitQueue();
|
||||||
|
|
||||||
// Locked flag.
|
// Locked flag.
|
||||||
this._locked = false;
|
this._locked = false;
|
||||||
|
|
||||||
|
|
@ -166,6 +172,10 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
this._closed = true;
|
this._closed = true;
|
||||||
|
|
||||||
|
this._queue.close();
|
||||||
|
|
||||||
|
this._queue = null;
|
||||||
|
|
||||||
if (this._selfDestructTimeout)
|
if (this._selfDestructTimeout)
|
||||||
clearTimeout(this._selfDestructTimeout);
|
clearTimeout(this._selfDestructTimeout);
|
||||||
|
|
||||||
|
|
@ -288,7 +298,7 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
this._peerJoining(promotedPeer);
|
this._peerJoining(promotedPeer);
|
||||||
|
|
||||||
for (const peer of this._getPeersWithPermission(PROMOTE_PEER))
|
for (const peer of this._getAllowedPeers(PROMOTE_PEER))
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:promotedPeer', { peerId: id });
|
this._notification(peer.socket, 'lobby:promotedPeer', { peerId: id });
|
||||||
}
|
}
|
||||||
|
|
@ -319,7 +329,7 @@ class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
const { id, displayName } = changedPeer;
|
const { id, displayName } = changedPeer;
|
||||||
|
|
||||||
for (const peer of this._getPeersWithPermission(PROMOTE_PEER))
|
for (const peer of this._getAllowedPeers(PROMOTE_PEER))
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:changeDisplayName', { peerId: id, displayName });
|
this._notification(peer.socket, 'lobby:changeDisplayName', { peerId: id, displayName });
|
||||||
}
|
}
|
||||||
|
|
@ -329,7 +339,7 @@ class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
const { id, picture } = changedPeer;
|
const { id, picture } = changedPeer;
|
||||||
|
|
||||||
for (const peer of this._getPeersWithPermission(PROMOTE_PEER))
|
for (const peer of this._getAllowedPeers(PROMOTE_PEER))
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:changePicture', { peerId: id, picture });
|
this._notification(peer.socket, 'lobby:changePicture', { peerId: id, picture });
|
||||||
}
|
}
|
||||||
|
|
@ -341,7 +351,7 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
const { id } = closedPeer;
|
const { id } = closedPeer;
|
||||||
|
|
||||||
for (const peer of this._getPeersWithPermission(PROMOTE_PEER))
|
for (const peer of this._getAllowedPeers(PROMOTE_PEER))
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'lobby:peerClosed', { peerId: id });
|
this._notification(peer.socket, 'lobby:peerClosed', { peerId: id });
|
||||||
}
|
}
|
||||||
|
|
@ -447,114 +457,91 @@ class Room extends EventEmitter
|
||||||
{
|
{
|
||||||
this._lobby.parkPeer(parkPeer);
|
this._lobby.parkPeer(parkPeer);
|
||||||
|
|
||||||
for (const peer of this._getPeersWithPermission(PROMOTE_PEER))
|
for (const peer of this._getAllowedPeers(PROMOTE_PEER))
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'parkedPeer', { peerId: parkPeer.id });
|
this._notification(peer.socket, 'parkedPeer', { peerId: parkPeer.id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _peerJoining(peer, returning = false)
|
_peerJoining(peer, returning = false)
|
||||||
{
|
{
|
||||||
peer.socket.join(this._roomId);
|
this._queue.push(async () =>
|
||||||
|
|
||||||
// If we don't have this peer, add to end
|
|
||||||
!this._lastN.includes(peer.id) && this._lastN.push(peer.id);
|
|
||||||
|
|
||||||
this._peers[peer.id] = peer;
|
|
||||||
|
|
||||||
// Assign routerId
|
|
||||||
peer.routerId = await this._getRouterId();
|
|
||||||
|
|
||||||
this._handlePeer(peer);
|
|
||||||
|
|
||||||
if (returning)
|
|
||||||
{
|
{
|
||||||
this._notification(peer.socket, 'roomBack');
|
peer.socket.join(this._roomId);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const token = jwt.sign({ id: peer.id }, this._uuid, { noTimestamp: true });
|
|
||||||
|
|
||||||
peer.socket.handshake.session.token = token;
|
// If we don't have this peer, add to end
|
||||||
|
!this._lastN.includes(peer.id) && this._lastN.push(peer.id);
|
||||||
|
|
||||||
peer.socket.handshake.session.save();
|
this._peers[peer.id] = peer;
|
||||||
|
|
||||||
let turnServers;
|
// Assign routerId
|
||||||
|
peer.routerId = await this._getRouterId();
|
||||||
|
|
||||||
if ('turnAPIURI' in config)
|
this._handlePeer(peer);
|
||||||
|
|
||||||
|
if (returning)
|
||||||
{
|
{
|
||||||
try
|
this._notification(peer.socket, 'roomBack');
|
||||||
{
|
|
||||||
const { data } = await axios.get(
|
|
||||||
config.turnAPIURI,
|
|
||||||
{
|
|
||||||
params : {
|
|
||||||
...config.turnAPIparams,
|
|
||||||
'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 : {
|
||||||
|
...config.turnAPIparams,
|
||||||
|
'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 });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
logger.error('_peerJoining() [error:"%o"]', error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_handlePeer(peer)
|
_handlePeer(peer)
|
||||||
{
|
{
|
||||||
logger.debug('_handlePeer() [peer:"%s"]', peer.id);
|
logger.debug('_handlePeer() [peer:"%s"]', peer.id);
|
||||||
|
|
||||||
peer.socket.on('request', (request, cb) =>
|
|
||||||
{
|
|
||||||
logger.debug(
|
|
||||||
'Peer "request" event [method:"%s", peerId:"%s"]',
|
|
||||||
request.method, peer.id);
|
|
||||||
|
|
||||||
this._handleSocketRequest(peer, request, cb)
|
|
||||||
.catch((error) =>
|
|
||||||
{
|
|
||||||
logger.error('"request" failed [error:"%o"]', error);
|
|
||||||
|
|
||||||
cb(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
peer.on('close', () =>
|
peer.on('close', () =>
|
||||||
{
|
{
|
||||||
if (this._closed)
|
this._handlePeerClose(peer);
|
||||||
return;
|
|
||||||
|
|
||||||
// If the Peer was joined, notify all Peers.
|
|
||||||
if (peer.joined)
|
|
||||||
this._notification(peer.socket, 'peerClosed', { peerId: peer.id }, true);
|
|
||||||
|
|
||||||
// Remove from lastN
|
|
||||||
this._lastN = this._lastN.filter((id) => id !== peer.id);
|
|
||||||
|
|
||||||
delete this._peers[peer.id];
|
|
||||||
|
|
||||||
// If this is the last Peer in the room and
|
|
||||||
// lobby is empty, close the room after a while.
|
|
||||||
if (this.checkEmpty() && this._lobby.checkEmpty())
|
|
||||||
this.selfDestructCountdown();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
peer.on('displayNameChanged', ({ oldDisplayName }) =>
|
peer.on('displayNameChanged', ({ oldDisplayName }) =>
|
||||||
|
|
@ -620,6 +607,69 @@ class Room extends EventEmitter
|
||||||
role : oldRole
|
role : oldRole
|
||||||
}, true, true);
|
}, true, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
peer.socket.on('request', (request, cb) =>
|
||||||
|
{
|
||||||
|
logger.debug(
|
||||||
|
'Peer "request" event [method:"%s", peerId:"%s"]',
|
||||||
|
request.method, peer.id);
|
||||||
|
|
||||||
|
this._handleSocketRequest(peer, request, cb)
|
||||||
|
.catch((error) =>
|
||||||
|
{
|
||||||
|
logger.error('"request" failed [error:"%o"]', error);
|
||||||
|
|
||||||
|
cb(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Peer left before we were done joining
|
||||||
|
if (peer.closed)
|
||||||
|
this._handlePeerClose(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handlePeerClose(peer)
|
||||||
|
{
|
||||||
|
logger.debug('_handlePeerClose() [peer:"%s"]', peer.id);
|
||||||
|
|
||||||
|
if (this._closed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the Peer was joined, notify all Peers.
|
||||||
|
if (peer.joined)
|
||||||
|
this._notification(peer.socket, 'peerClosed', { peerId: peer.id }, true);
|
||||||
|
|
||||||
|
// Remove from lastN
|
||||||
|
this._lastN = this._lastN.filter((id) => id !== peer.id);
|
||||||
|
|
||||||
|
// Need this to know if this peer was the last with PROMOTE_PEER
|
||||||
|
const hasPromotePeer = peer.roles.some((role) =>
|
||||||
|
roomPermissions[PROMOTE_PEER].includes(role)
|
||||||
|
);
|
||||||
|
|
||||||
|
delete this._peers[peer.id];
|
||||||
|
|
||||||
|
// No peers left with PROMOTE_PEER, might need to give
|
||||||
|
// lobbyPeers to peers that are left.
|
||||||
|
if (
|
||||||
|
hasPromotePeer &&
|
||||||
|
!this._lobby.checkEmpty() &&
|
||||||
|
roomAllowWhenRoleMissing.includes(PROMOTE_PEER) &&
|
||||||
|
this._getPeersWithPermission(PROMOTE_PEER).length === 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const lobbyPeers = this._lobby.peerList();
|
||||||
|
|
||||||
|
for (const allowedPeer of this._getAllowedPeers(PROMOTE_PEER))
|
||||||
|
{
|
||||||
|
this._notification(allowedPeer.socket, 'parkedPeers', { lobbyPeers });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the last Peer in the room and
|
||||||
|
// lobby is empty, close the room after a while.
|
||||||
|
if (this.checkEmpty() && this._lobby.checkEmpty())
|
||||||
|
this.selfDestructCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _handleSocketRequest(peer, request, cb)
|
async _handleSocketRequest(peer, request, cb)
|
||||||
|
|
@ -656,13 +706,9 @@ class Room extends EventEmitter
|
||||||
// Tell the new Peer about already joined Peers.
|
// Tell the new Peer about already joined Peers.
|
||||||
// And also create Consumers for existing Producers.
|
// And also create Consumers for existing Producers.
|
||||||
|
|
||||||
const joinedPeers =
|
const joinedPeers = this._getJoinedPeers(peer);
|
||||||
[
|
|
||||||
...this._getJoinedPeers()
|
|
||||||
];
|
|
||||||
|
|
||||||
const peerInfos = joinedPeers
|
const peerInfos = joinedPeers
|
||||||
.filter((joinedPeer) => joinedPeer.id !== peer.id)
|
|
||||||
.map((joinedPeer) => (joinedPeer.peerInfo));
|
.map((joinedPeer) => (joinedPeer.peerInfo));
|
||||||
|
|
||||||
let lobbyPeers = [];
|
let lobbyPeers = [];
|
||||||
|
|
@ -678,7 +724,7 @@ class Room extends EventEmitter
|
||||||
authenticated : peer.authenticated,
|
authenticated : peer.authenticated,
|
||||||
roomPermissions : roomPermissions,
|
roomPermissions : roomPermissions,
|
||||||
userRoles : userRoles,
|
userRoles : userRoles,
|
||||||
allowWhenRoleMissing : config.allowWhenRoleMissing,
|
allowWhenRoleMissing : roomAllowWhenRoleMissing,
|
||||||
chatHistory : this._chatHistory,
|
chatHistory : this._chatHistory,
|
||||||
fileHistory : this._fileHistory,
|
fileHistory : this._fileHistory,
|
||||||
lastNHistory : this._lastN,
|
lastNHistory : this._lastN,
|
||||||
|
|
@ -1622,8 +1668,7 @@ class Room extends EventEmitter
|
||||||
|
|
||||||
// Allow if config is set, and no one is present
|
// Allow if config is set, and no one is present
|
||||||
if (
|
if (
|
||||||
'allowWhenRoleMissing' in config &&
|
roomAllowWhenRoleMissing.includes(permission) &&
|
||||||
config.allowWhenRoleMissing.includes(permission) &&
|
|
||||||
this._getPeersWithPermission(permission).length === 0
|
this._getPeersWithPermission(permission).length === 0
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1645,6 +1690,20 @@ class Room extends EventEmitter
|
||||||
.filter((peer) => peer.joined && peer !== excludePeer);
|
.filter((peer) => peer.joined && peer !== excludePeer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getAllowedPeers(permission = null, excludePeer = undefined, joined = true)
|
||||||
|
{
|
||||||
|
const peers = this._getPeersWithPermission(permission, excludePeer, joined);
|
||||||
|
|
||||||
|
if (peers.length > 0)
|
||||||
|
return peers;
|
||||||
|
|
||||||
|
// Allow if config is set, and no one is present
|
||||||
|
if (roomAllowWhenRoleMissing.includes(permission))
|
||||||
|
return Object.values(this._peers);
|
||||||
|
|
||||||
|
return peers;
|
||||||
|
}
|
||||||
|
|
||||||
_getPeersWithPermission(permission = null, excludePeer = undefined, joined = true)
|
_getPeersWithPermission(permission = null, excludePeer = undefined, joined = true)
|
||||||
{
|
{
|
||||||
return Object.values(this._peers)
|
return Object.values(this._peers)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue