Fix breakouts assignments when freeJoin is true

This commit is contained in:
Gustavo Trott 2021-12-02 11:05:42 -03:00
parent 56fedc8921
commit fe944c1bdb
8 changed files with 104 additions and 59 deletions

View File

@ -17,6 +17,27 @@ object BreakoutHdlrHelpers extends SystemConfiguration {
roomSequence: String,
breakoutId: String
) {
for {
(redirectToHtml5JoinURL, redirectJoinURL) <- getRedirectUrls(liveMeeting, userId, externalMeetingId, roomSequence)
} yield {
sendJoinURLMsg(
outGW,
liveMeeting.props.meetingProp.intId,
breakoutId,
externalMeetingId,
userId,
redirectJoinURL,
redirectToHtml5JoinURL
)
}
}
def getRedirectUrls(
liveMeeting: LiveMeeting,
userId: String,
externalMeetingId: String,
roomSequence: String
): Option[(String, String)] = {
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, userId)
apiCall = "join"
@ -31,15 +52,7 @@ object BreakoutHdlrHelpers extends SystemConfiguration {
redirectToHtml5JoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, redirectToHtml5BaseString,
BreakoutRoomsUtil.calculateChecksum(apiCall, redirectToHtml5BaseString, bbbWebSharedSecret))
} yield {
sendJoinURLMsg(
outGW,
liveMeeting.props.meetingProp.intId,
breakoutId,
externalMeetingId,
userId,
redirectJoinURL,
redirectToHtml5JoinURL
)
(redirectToHtml5JoinURL, redirectJoinURL)
}
}

View File

@ -25,7 +25,6 @@ trait BreakoutRoomCreatedMsgHdlr {
if (updatedModel.hasAllStarted()) {
updatedModel = updatedModel.copy(startedOn = Some(System.currentTimeMillis()))
updatedModel = sendBreakoutRoomsList(updatedModel)
updatedModel = sendBreakoutInvitations(updatedModel)
}
updatedModel
}
@ -36,25 +35,6 @@ trait BreakoutRoomCreatedMsgHdlr {
}
}
def sendBreakoutInvitations(breakoutModel: BreakoutModel): BreakoutModel = {
log.debug("Sending breakout invitations")
breakoutModel.rooms.values.foreach { room =>
log.debug("Sending invitations for room {} with num users {}", room.name, room.assignedUsers.toVector.length)
room.assignedUsers.foreach { user =>
BreakoutHdlrHelpers.sendJoinURL(
liveMeeting,
outGW,
user,
room.externalId,
room.sequence.toString(),
room.id
)
}
}
breakoutModel
}
def buildBreakoutRoomsListEvtMsg(meetingId: String, rooms: Vector[BreakoutRoomInfo], roomsReady: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(BreakoutRoomsListEvtMsg.NAME, routing)
@ -63,12 +43,16 @@ trait BreakoutRoomCreatedMsgHdlr {
val body = BreakoutRoomsListEvtMsgBody(meetingId, rooms, roomsReady)
val event = BreakoutRoomsListEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def sendBreakoutRoomsList(breakoutModel: BreakoutModel): BreakoutModel = {
val breakoutRooms = breakoutModel.rooms.values.toVector map { r =>
new BreakoutRoomInfo(r.name, r.externalId, r.id, r.sequence, r.shortName, r.isDefaultName, r.freeJoin)
val html5JoinUrls = for {
user <- r.assignedUsers
(redirectToHtml5JoinURL, redirectJoinURL) <- BreakoutHdlrHelpers.getRedirectUrls(liveMeeting, user, r.externalId, r.sequence.toString())
} yield (user -> redirectToHtml5JoinURL)
new BreakoutRoomInfo(r.name, r.externalId, r.id, r.sequence, r.shortName, r.isDefaultName, r.freeJoin, html5JoinUrls.toMap)
}
log.info("Sending breakout rooms list to {} with containing {} room(s)", liveMeeting.props.meetingProp.intId, breakoutRooms.length)
@ -95,7 +79,7 @@ trait BreakoutRoomCreatedMsgHdlr {
BbbCommonEnvCoreMsg(envelope, event)
}
val breakoutInfo = BreakoutRoomInfo(room.name, room.externalId, room.id, room.sequence, room.shortName, room.isDefaultName, room.freeJoin)
val breakoutInfo = BreakoutRoomInfo(room.name, room.externalId, room.id, room.sequence, room.shortName, room.isDefaultName, room.freeJoin, Map())
val event = build(liveMeeting.props.meetingProp.intId, breakoutInfo)
outGW.send(event)

View File

@ -28,7 +28,7 @@ trait BreakoutRoomsListMsgHdlr {
breakoutModel <- state.breakout
} yield {
val rooms = breakoutModel.rooms.values.toVector map { r =>
new BreakoutRoomInfo(r.name, r.externalId, r.id, r.sequence, r.shortName, r.isDefaultName, r.freeJoin)
new BreakoutRoomInfo(r.name, r.externalId, r.id, r.sequence, r.shortName, r.isDefaultName, r.freeJoin, Map())
}
val ready = breakoutModel.hasAllStarted()
broadcastEvent(rooms, ready)

View File

@ -101,8 +101,6 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender)
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case BreakoutRoomsListEvtMsg.NAME =>
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case BreakoutRoomJoinURLEvtMsg.NAME =>
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case BreakoutRoomsTimeRemainingUpdateEvtMsg.NAME =>
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case BreakoutRoomStartedEvtMsg.NAME =>

View File

@ -13,7 +13,7 @@ case class BreakoutRoomJoinURLEvtMsgBody(parentId: String, breakoutId: String, e
object BreakoutRoomsListEvtMsg { val NAME = "BreakoutRoomsListEvtMsg" }
case class BreakoutRoomsListEvtMsg(header: BbbClientMsgHeader, body: BreakoutRoomsListEvtMsgBody) extends BbbCoreMsg
case class BreakoutRoomsListEvtMsgBody(meetingId: String, rooms: Vector[BreakoutRoomInfo], roomsReady: Boolean)
case class BreakoutRoomInfo(name: String, externalId: String, breakoutId: String, sequence: Int, shortName: String, isDefaultName: Boolean, freeJoin: Boolean)
case class BreakoutRoomInfo(name: String, externalId: String, breakoutId: String, sequence: Int, shortName: String, isDefaultName: Boolean, freeJoin: Boolean, html5JoinUrls: Map[String, String])
object BreakoutRoomsListMsg { val NAME = "BreakoutRoomsListMsg" }
case class BreakoutRoomsListMsg(header: BbbClientMsgHeader, body: BreakoutRoomsListMsgBody) extends StandardMsg
@ -81,14 +81,6 @@ object RequestBreakoutJoinURLReqMsg { val NAME = "RequestBreakoutJoinURLReqMsg"
case class RequestBreakoutJoinURLReqMsg(header: BbbClientMsgHeader, body: RequestBreakoutJoinURLReqMsgBody) extends StandardMsg
case class RequestBreakoutJoinURLReqMsgBody(meetingId: String, breakoutId: String, userId: String)
/**
* Response sent to client for a join url for a user.
*/
object RequestBreakoutJoinURLRespMsg { val NAME = "RequestBreakoutJoinURLRespMsg" }
case class RequestBreakoutJoinURLRespMsg(header: BbbClientMsgHeader, body: RequestBreakoutJoinURLRespMsgBody) extends BbbCoreMsg
case class RequestBreakoutJoinURLRespMsgBody(parentId: String, breakoutId: String,
userId: String, redirectJoinURL: String, redirectToHtml5JoinURL: String)
object TransferUserToMeetingEvtMsg { val NAME = "TransferUserToMeetingEvtMsg" }
case class TransferUserToMeetingEvtMsg(header: BbbClientMsgHeader, body: TransferUserToMeetingEvtMsgBody) extends BbbCoreMsg
case class TransferUserToMeetingEvtMsgBody(fromVoiceConf: String, toVoiceConf: String, userId: String)

View File

@ -1,13 +1,12 @@
import RedisPubSub from '/imports/startup/server/redis';
import handleBreakoutJoinURL from './handlers/breakoutJoinURL';
import handleBreakoutStarted from './handlers/breakoutStarted';
import handleBreakoutRoomsList from './handlers/breakoutList';
import handleUpdateTimeRemaining from './handlers/updateTimeRemaining';
import handleBreakoutClosed from './handlers/breakoutClosed';
import joinedUsersChanged from './handlers/joinedUsersChanged';
RedisPubSub.on('BreakoutRoomStartedEvtMsg', handleBreakoutStarted);
RedisPubSub.on('BreakoutRoomsListEvtMsg', handleBreakoutRoomsList);
RedisPubSub.on('BreakoutRoomJoinURLEvtMsg', handleBreakoutJoinURL);
RedisPubSub.on('RequestBreakoutJoinURLRespMsg', handleBreakoutJoinURL);
RedisPubSub.on('BreakoutRoomsTimeRemainingUpdateEvtMsg', handleUpdateTimeRemaining);
RedisPubSub.on('BreakoutRoomEndedEvtMsg', handleBreakoutClosed);
RedisPubSub.on('UpdateBreakoutUsersEvtMsg', joinedUsersChanged);

View File

@ -0,0 +1,57 @@
import Breakouts from '/imports/api/breakouts';
import Logger from '/imports/startup/server/logger';
import { check } from 'meteor/check';
import flat from 'flat';
export default function handleBreakoutRoomsList({ body }, meetingId) {
// 0 seconds default breakout time, forces use of real expiration time
const DEFAULT_TIME_REMAINING = 0;
const {
meetingId: parentMeetingId,
rooms,
} = body;
// set firstly the last seq, then client will know when receive all
rooms.sort((a, b) => ((a.sequence < b.sequence) ? 1 : -1)).forEach((breakout) => {
const { breakoutId, html5JoinUrls, ...breakoutWithoutUrls } = breakout;
check(meetingId, String);
const selector = {
breakoutId,
};
const urls = {};
if (typeof html5JoinUrls === 'object' && Object.keys(html5JoinUrls).length > 0) {
Object.keys(html5JoinUrls).forEach((userId) => {
urls[`url_${userId}`] = {
redirectToHtml5JoinURL: html5JoinUrls[userId],
insertedTime: new Date().getTime(),
};
});
}
const modifier = {
$set: {
breakoutId,
joinedUsers: [],
timeRemaining: DEFAULT_TIME_REMAINING,
parentMeetingId,
...flat(breakoutWithoutUrls),
...urls,
},
};
try {
const { numberAffected } = Breakouts.upsert(selector, modifier);
if (numberAffected) {
Logger.info('Updated timeRemaining and externalMeetingId '
+ `for breakout id=${breakoutId}`);
}
} catch (err) {
Logger.error(`updating breakout: ${err}`);
}
});
}

View File

@ -66,25 +66,27 @@ class BreakoutRoomInvitation extends Component {
const hasBreakouts = breakouts.length > 0;
if (hasBreakouts && !breakoutUserIsIn && BreakoutService.checkInviteModerators()) {
// Have to check for freeJoin breakouts first because currentBreakoutUrlData will
// populate after a room has been joined
const freeJoinRooms = breakouts.filter((breakout) => breakout.freeJoin);
if (currentBreakoutUrlData) {
const breakoutRoom = getBreakoutByUrlData(currentBreakoutUrlData);
const freeJoinBreakout = breakouts.find((breakout) => breakout.freeJoin);
if (freeJoinBreakout) {
if (!didSendBreakoutInvite) {
this.inviteUserToBreakout(breakoutRoom || freeJoinBreakout);
this.setState({ didSendBreakoutInvite: true });
}
} else if (currentBreakoutUrlData) {
const currentInsertedTime = currentBreakoutUrlData.insertedTime;
const oldCurrentUrlData = oldProps.currentBreakoutUrlData || {};
const oldInsertedTime = oldCurrentUrlData.insertedTime;
if (currentInsertedTime !== oldInsertedTime) {
const breakoutId = Session.get('lastBreakoutOpened');
if (breakoutRoom.breakoutId !== breakoutId) {
const lastBreakoutId = Session.get('lastBreakoutOpened');
if (breakoutRoom.breakoutId !== lastBreakoutId) {
this.inviteUserToBreakout(breakoutRoom);
}
}
} else if (freeJoinRooms.length > 0 && !didSendBreakoutInvite) {
const maxSeq = Math.max(...freeJoinRooms.map(((room) => room.sequence)));
// Check if received all rooms and Pick a room randomly
if (maxSeq === freeJoinRooms.length) {
const randomRoom = freeJoinRooms[Math.floor(Math.random() * freeJoinRooms.length)];
this.inviteUserToBreakout(randomRoom);
this.setState({ didSendBreakoutInvite: true });
}
}
}