- track meeting inactivity and expiry in akka-apps

This commit is contained in:
Richard Alam 2017-07-18 14:47:42 -07:00
parent 03ea339e21
commit a61030a95f
14 changed files with 162 additions and 253 deletions

View File

@ -2,7 +2,8 @@ package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.bus.{ IncomingEventBus }
import org.bigbluebutton.core.bus.IncomingEventBus
import org.bigbluebutton.core.domain.MeetingEndReason
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.LiveMeeting
@ -18,17 +19,7 @@ trait LogoutAndEndMeetingCmdMsgHdlr {
u <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
} yield {
if (u.role == Roles.MODERATOR_ROLE) {
endMeeting(outGW, liveMeeting)
if (liveMeeting.props.meetingProp.isBreakout) {
log.info(
"Informing parent meeting {} that a breakout room has been ended {}",
liveMeeting.props.breakoutProps.parentId, liveMeeting.props.meetingProp.intId
)
notifyParentThatBreakoutEnded(eventBus, liveMeeting)
}
destroyMeeting(eventBus, liveMeeting.props.meetingProp.intId)
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_AFTER_USER_LOGGED_OUT, eventBus, outGW, liveMeeting)
}
}
}

View File

@ -1,9 +1,10 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.domain.{ MeetingInactivityTracker, MeetingState2x }
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, MeetingInactivityTrackerHelper }
import org.bigbluebutton.core.running.{ LiveMeeting }
trait MeetingActivityResponseCmdMsgHdlr {
this: UsersApp =>
@ -12,11 +13,31 @@ trait MeetingActivityResponseCmdMsgHdlr {
val outGW: OutMessageGateway
def handleMeetingActivityResponseCmdMsg(
msg: MeetingActivityResponseCmdMsg,
state: MeetingState2x,
helper: MeetingInactivityTrackerHelper
msg: MeetingActivityResponseCmdMsg,
state: MeetingState2x
): MeetingState2x = {
helper.processMeetingActivityResponse(liveMeeting.props, outGW, msg)
processMeetingActivityResponse(liveMeeting.props, outGW, msg)
MeetingInactivityTracker.resetWarningSentAndTimestamp(state)
}
def processMeetingActivityResponse(
props: DefaultProps,
outGW: OutMessageGateway,
msg: MeetingActivityResponseCmdMsg
): Unit = {
def buildMeetingIsActiveEvtMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingIsActiveEvtMsg.NAME, routing)
val body = MeetingIsActiveEvtMsgBody(meetingId)
val header = BbbClientMsgHeader(MeetingIsActiveEvtMsg.NAME, meetingId, "not-used")
val event = MeetingIsActiveEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildMeetingIsActiveEvtMsg(props.meetingProp.intId)
outGW.send(event)
}
}

View File

@ -3,6 +3,14 @@ package org.bigbluebutton.core.domain
import com.softwaremill.quicklens._
import org.bigbluebutton.core.util.TimeUtil
case class MeetingInactivityTracker(
val maxInactivityTimeoutMinutes: Int,
val warningMinutesBeforeMax: Int,
lastActivityTimestamp: Long,
warningSent: Boolean,
warningSentOnTimestamp: Long
)
object MeetingInactivityTracker {
def warningHasBeenSent(state: MeetingState2x): Boolean = {
@ -28,7 +36,8 @@ object MeetingInactivityTracker {
def hasRecentActivity(state: MeetingState2x, nowInSeconds: Long): Boolean = {
nowInSeconds - state.inactivityTracker.lastActivityTimestamp <
TimeUtil.minutesToSeconds(state.inactivityTracker.maxInactivityTimeoutMinutes)
TimeUtil.minutesToSeconds(state.inactivityTracker.maxInactivityTimeoutMinutes) -
TimeUtil.minutesToSeconds(state.inactivityTracker.warningMinutesBeforeMax)
}
def isMeetingInactive(state: MeetingState2x, nowInSeconds: Long): Boolean = {
@ -43,12 +52,13 @@ object MeetingInactivityTracker {
}
}
case class MeetingInactivityTracker(
val maxInactivityTimeoutMinutes: Int,
val warningMinutesBeforeMax: Int,
lastActivityTimestamp: Long,
warningSent: Boolean,
warningSentOnTimestamp: Long
case class MeetingExpiryTracker(
startedOn: Long,
userHasJoined: Boolean,
lastUserLeftOn: Option[Long],
durationInMinutes: Int,
meetingExpireIfNoUserJoinedInMinutes: Int,
meetingExpireWhenLastUserLeftInMinutes: Int
)
object MeetingExpiryTracker {
@ -59,21 +69,38 @@ object MeetingExpiryTracker {
def setUserHasJoined(state: MeetingState2x): MeetingState2x = {
val tracker = state.expiryTracker.modify(_.userHasJoined).setTo(true)
.modify(_.lastUserLeftOn).setTo(None)
state.modify(_.expiryTracker).setTo(tracker)
}
def hasMeetingExpiredAfterLastUserLeft(state: MeetingState2x, timestampInSeconds: Long): Boolean = {
val expire = for {
lastUserLeftOn <- state.expiryTracker.lastUserLeftOn
} yield {
timestampInSeconds - lastUserLeftOn >
TimeUtil.minutesToSeconds(state.expiryTracker.meetingExpireWhenLastUserLeftInMinutes)
}
expire.getOrElse(false)
}
def setLastUserLeftOn(state: MeetingState2x, timestampInSeconds: Long): MeetingState2x = {
val tracker = state.expiryTracker.modify(_.lastUserLeftOn).setTo(timestampInSeconds)
val tracker = state.expiryTracker.modify(_.lastUserLeftOn).setTo(Some(timestampInSeconds))
state.modify(_.expiryTracker).setTo(tracker)
}
def hasMeetingExpiredNeverBeenJoined(state: MeetingState2x, nowInSeconds: Long): Boolean = {
nowInSeconds - state.expiryTracker.startedOn >
TimeUtil.minutesToSeconds(state.expiryTracker.meetingExpireIfNoUserJoinedInMinutes)
!state.expiryTracker.userHasJoined &&
(nowInSeconds - state.expiryTracker.startedOn >
TimeUtil.minutesToSeconds(state.expiryTracker.meetingExpireIfNoUserJoinedInMinutes))
}
def meetingOverDuration(state: MeetingState2x, nowInSeconds: Long): Boolean = {
nowInSeconds > state.expiryTracker.startedOn + TimeUtil.minutesToSeconds(state.expiryTracker.durationInMinutes)
if (state.expiryTracker.durationInMinutes == 0) {
false
} else {
nowInSeconds > state.expiryTracker.startedOn + TimeUtil.minutesToSeconds(state.expiryTracker.durationInMinutes)
}
}
def endMeetingTime(state: MeetingState2x): Int = {
@ -81,11 +108,3 @@ object MeetingExpiryTracker {
}
}
case class MeetingExpiryTracker(
startedOn: Long,
userHasJoined: Boolean,
lastUserLeftOn: Long,
durationInMinutes: Int,
meetingExpireIfNoUserJoinedInMinutes: Int,
meetingExpireWhenLastUserLeftInMinutes: Int
)

View File

@ -9,3 +9,11 @@ case class MeetingState2x(
expiryTracker: MeetingExpiryTracker
)
object MeetingEndReason {
val ENDED_FROM_API = "ENDED_FROM_API"
val ENDED_DUE_TO_INACTIVITY = "ENDED_DUE_TO_ACTIVITY"
val ENDED_WHEN_NOT_JOINED = "ENDED_WHEN_NOT_JOINED"
val ENDED_WHEN_LAST_USER_LEFT = "ENDED_WHEN_LAST_USER_LEFT"
val ENDED_AFTER_USER_LOGGED_OUT = "ENDED_AFTER_USER_LOGGED_OUT"
val ENDED_AFTER_EXCEEDING_DURATION = "ENDED_AFTER_USER_LOGGED_OUT"
}

View File

@ -1,12 +1,14 @@
package org.bigbluebutton.core.running
import org.bigbluebutton.SystemConfiguration
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api.{ BreakoutRoomEndedInternalMsg, DestroyMeetingInternalMsg, RecordingStatusChanged }
import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, IncomingEventBus }
import org.bigbluebutton.core.domain.{ MeetingExpiryTracker, MeetingState2x }
import org.bigbluebutton.core.{ OutMessageGateway }
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models._
import org.bigbluebutton.core.util.TimeUtil
import org.bigbluebutton.core2.MeetingStatus2x
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender, UserJoinedMeetingEvtMsgBuilder }
@ -178,11 +180,11 @@ trait HandlerHelpers extends SystemConfiguration {
outGW.send(event)
}
def endMeeting(outGW: OutMessageGateway, liveMeeting: LiveMeeting): Unit = {
def endMeeting(outGW: OutMessageGateway, liveMeeting: LiveMeeting, reason: String): Unit = {
def buildMeetingEndingEvtMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingEndingEvtMsg.NAME, routing)
val body = MeetingEndingEvtMsgBody(meetingId)
val body = MeetingEndingEvtMsgBody(meetingId, reason)
val header = BbbClientMsgHeader(MeetingEndingEvtMsg.NAME, meetingId, "not-used")
val event = MeetingEndingEvtMsg(header, body)
@ -215,9 +217,23 @@ trait HandlerHelpers extends SystemConfiguration {
}
def notifyParentThatBreakoutEnded(eventBus: IncomingEventBus, liveMeeting: LiveMeeting): Unit = {
eventBus.publish(BigBlueButtonEvent(
liveMeeting.props.breakoutProps.parentId,
new BreakoutRoomEndedInternalMsg(liveMeeting.props.meetingProp.intId)
))
if (liveMeeting.props.meetingProp.isBreakout) {
eventBus.publish(BigBlueButtonEvent(
liveMeeting.props.breakoutProps.parentId,
new BreakoutRoomEndedInternalMsg(liveMeeting.props.meetingProp.intId)
))
}
}
def ejectAllUsersFromVoiceConf(outGW: OutMessageGateway, liveMeeting: LiveMeeting): Unit = {
val event = MsgBuilder.buildEjectAllFromVoiceConfMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf)
outGW.send(event)
}
def sendEndMeetingDueToExpiry(reason: String, eventBus: IncomingEventBus, outGW: OutMessageGateway, liveMeeting: LiveMeeting): Unit = {
endMeeting(outGW, liveMeeting, reason)
notifyParentThatBreakoutEnded(eventBus, liveMeeting)
ejectAllUsersFromVoiceConf(outGW, liveMeeting)
destroyMeeting(eventBus, liveMeeting.props.meetingProp.intId)
}
}

View File

@ -104,7 +104,6 @@ class MeetingActor(
val chatApp2x = new ChatApp2x(liveMeeting, outGW)
val usersApp = new UsersApp(liveMeeting, outGW, eventBus)
val inactivityTrackerHelper = new MeetingInactivityTrackerHelper(liveMeeting, outGW)
val expiryTrackerHelper = new MeetingExpiryTrackerHelper(liveMeeting, outGW)
val inactivityTracker = new MeetingInactivityTracker(
@ -118,7 +117,7 @@ class MeetingActor(
val expiryTracker = new MeetingExpiryTracker(
startedOn = TimeUtil.timeNowInSeconds(),
userHasJoined = false,
lastUserLeftOn = 0L,
lastUserLeftOn = None,
durationInMinutes = props.durationProps.duration,
meetingExpireIfNoUserJoinedInMinutes = props.durationProps.meetingExpireIfNoUserJoinedInMinutes,
meetingExpireWhenLastUserLeftInMinutes = props.durationProps.meetingExpireWhenLastUserLeftInMinutes
@ -161,19 +160,21 @@ class MeetingActor(
}
private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
// TODO: Update meeting activity status here
// updateActivityStatus(msg)
state = MeetingInactivityTracker.updateLastActivityTimestamp(state, TimeUtil.timeNowInSeconds())
msg.core match {
// Users
case m: ValidateAuthTokenReqMsg => state = usersApp.handleValidateAuthTokenReqMsg(m, state)
case m: UserJoinMeetingReqMsg => state = handleUserJoinMeetingReqMsg(m, state)
case m: UserLeaveReqMsg => state = handleUserLeaveReqMsg(m, state)
case m: ValidateAuthTokenReqMsg =>
state = usersApp.handleValidateAuthTokenReqMsg(m, state)
case m: UserJoinMeetingReqMsg =>
state = handleUserJoinMeetingReqMsg(m, state)
case m: UserLeaveReqMsg =>
state = handleUserLeaveReqMsg(m, state)
case m: UserBroadcastCamStartMsg => handleUserBroadcastCamStartMsg(m)
case m: UserBroadcastCamStopMsg => handleUserBroadcastCamStopMsg(m)
case m: UserJoinedVoiceConfEvtMsg => handleUserJoinedVoiceConfEvtMsg(m)
case m: MeetingActivityResponseCmdMsg =>
state = usersApp.handleMeetingActivityResponseCmdMsg(m, state, inactivityTrackerHelper)
state = usersApp.handleMeetingActivityResponseCmdMsg(m, state)
case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m)
case m: SetRecordingStatusCmdMsg => usersApp.handleSetRecordingStatusCmdMsg(m)
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
@ -326,45 +327,8 @@ class MeetingActor(
}
def handleMonitorNumberOfUsers(msg: MonitorNumberOfUsersInternalMsg) {
state = inactivityTrackerHelper.processMeetingInactivityAudit(
props = liveMeeting.props,
outGW,
eventBus,
state
)
state = expiryTrackerHelper.processMeetingInactivityAudit(liveMeeting.props, outGW, eventBus, state)
state = expiryTrackerHelper.processMeetingExpiryAudit(liveMeeting.props, state, eventBus)
monitorNumberOfWebUsers()
monitorNumberOfUsers()
}
def monitorNumberOfWebUsers() {
def buildEjectAllFromVoiceConfMsg(meetingId: String, voiceConf: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(EjectAllFromVoiceConfMsg.NAME, routing)
val body = EjectAllFromVoiceConfMsgBody(voiceConf)
val header = BbbCoreHeaderWithMeetingId(EjectAllFromVoiceConfMsg.NAME, meetingId)
val event = EjectAllFromVoiceConfMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
if (Users2x.numUsers(liveMeeting.users2x) == 0 &&
state.expiryTracker.lastUserLeftOn > 0) {
if (TimeUtil.timeNowInMinutes - state.expiryTracker.lastUserLeftOn > 2) {
log.info("Empty meeting. Ejecting all users from voice. meetingId={}", props.meetingProp.intId)
val event = buildEjectAllFromVoiceConfMsg(props.meetingProp.intId, props.voiceProp.voiceConf)
outGW.send(event)
}
}
}
def monitorNumberOfUsers() {
val hasUsers = Users2x.numUsers(liveMeeting.users2x) != 0
// TODO: We could use a better control over this message to send it just when it really matters :)
eventBus.publish(BigBlueButtonEvent(props.meetingProp.intId, UpdateMeetingExpireMonitor(props.meetingProp.intId, hasUsers)))
}
def handleExtendMeetingDuration(msg: ExtendMeetingDuration) {

View File

@ -3,9 +3,10 @@ package org.bigbluebutton.core.running
import akka.actor.ActorContext
import akka.event.Logging
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.bus.IncomingEventBus
import org.bigbluebutton.core.domain.{ MeetingExpiryTracker, MeetingState2x }
import org.bigbluebutton.core.domain.{ MeetingEndReason, MeetingExpiryTracker, MeetingInactivityTracker, MeetingState2x }
import org.bigbluebutton.core.util.TimeUtil
class MeetingExpiryTrackerHelper(
@ -15,45 +16,64 @@ class MeetingExpiryTrackerHelper(
val log = Logging(context.system, getClass)
def processNeverBeenJoinedExpiry(nowInSeconds: Long, props: DefaultProps, state: MeetingState2x,
eventBus: IncomingEventBus): MeetingState2x = {
if (MeetingExpiryTracker.hasMeetingExpiredNeverBeenJoined(state, nowInSeconds)) {
log.info("Ending meeting as it has never been joined.")
sendEndMeetingDueToExpiry(props, eventBus)
state
} else {
state
}
}
def processMeetingExpiryAudit(props: DefaultProps, state: MeetingState2x, eventBus: IncomingEventBus): MeetingState2x = {
val nowInSeconds = TimeUtil.timeNowInSeconds()
if (!state.expiryTracker.userHasJoined) {
processNeverBeenJoinedExpiry(nowInSeconds, props, state, eventBus)
} else {
if (props.durationProps.duration != 0 && MeetingExpiryTracker.meetingOverDuration(state, nowInSeconds)) {
log.info("Ending meeting as it has passed duration.")
sendEndMeetingDueToExpiry(props, eventBus)
if (MeetingExpiryTracker.hasMeetingExpiredNeverBeenJoined(state, nowInSeconds)) {
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_WHEN_NOT_JOINED, eventBus, outGW, liveMeeting)
} else if (MeetingExpiryTracker.meetingOverDuration(state, nowInSeconds)) {
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_AFTER_EXCEEDING_DURATION, eventBus, outGW, liveMeeting)
} else if (MeetingExpiryTracker.hasMeetingExpiredAfterLastUserLeft(state, nowInSeconds)) {
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_WHEN_LAST_USER_LEFT, eventBus, outGW, liveMeeting)
}
state
}
def processMeetingInactivityAudit(
props: DefaultProps,
outGW: OutMessageGateway,
eventBus: IncomingEventBus,
state: MeetingState2x
): MeetingState2x = {
val nowInSeconds = TimeUtil.timeNowInSeconds()
if (!MeetingInactivityTracker.hasRecentActivity(state, nowInSeconds)) {
if (MeetingInactivityTracker.isMeetingInactive(state, nowInSeconds)) {
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_DUE_TO_INACTIVITY, eventBus, outGW, liveMeeting)
state
} else {
state
if (!MeetingInactivityTracker.warningHasBeenSent(state)) {
warnOfMeetingInactivity(props, outGW, nowInSeconds, state)
MeetingInactivityTracker.setWarningSentAndTimestamp(state, nowInSeconds)
} else {
state
}
}
} else {
state
}
}
def sendEndMeetingDueToExpiry(props: DefaultProps, eventBus: IncomingEventBus): Unit = {
def warnOfMeetingInactivity(props: DefaultProps, outGW: OutMessageGateway,
nowInSeconds: Long, state: MeetingState2x): Unit = {
val timeLeftSeconds = MeetingInactivityTracker.timeLeftInSeconds(state, nowInSeconds)
sendMeetingInactivityWarning(props, outGW, timeLeftSeconds)
}
endMeeting(outGW, liveMeeting)
def sendMeetingInactivityWarning(props: DefaultProps, outGW: OutMessageGateway, timeLeftSeconds: Long): Unit = {
def build(meetingId: String, timeLeftInSec: Long): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingInactivityWarningEvtMsg.NAME, routing)
val body = MeetingInactivityWarningEvtMsgBody(timeLeftInSec)
val header = BbbClientMsgHeader(MeetingInactivityWarningEvtMsg.NAME, meetingId, "not-used")
val event = MeetingInactivityWarningEvtMsg(header, body)
if (liveMeeting.props.meetingProp.isBreakout) {
log.info(
"Informing parent meeting {} that a breakout room has been ended {}",
liveMeeting.props.breakoutProps.parentId, liveMeeting.props.meetingProp.intId
)
notifyParentThatBreakoutEnded(eventBus, liveMeeting)
BbbCommonEnvCoreMsg(envelope, event)
}
destroyMeeting(eventBus, liveMeeting.props.meetingProp.intId)
val event = build(props.meetingProp.intId, timeLeftSeconds)
outGW.send(event)
}
}

View File

@ -1,100 +0,0 @@
package org.bigbluebutton.core.running
import akka.actor.ActorContext
import akka.event.Logging
import org.bigbluebutton.core.domain.{ MeetingInactivityTracker, MeetingState2x }
import com.softwaremill.quicklens._
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.bus.IncomingEventBus
import org.bigbluebutton.core.util.TimeUtil
class MeetingInactivityTrackerHelper(
val liveMeeting: LiveMeeting,
val outGW: OutMessageGateway
)(implicit val context: ActorContext) extends HandlerHelpers {
val log = Logging(context.system, getClass)
def processMeetingInactivityAudit(
props: DefaultProps,
outGW: OutMessageGateway,
eventBus: IncomingEventBus,
state: MeetingState2x
): MeetingState2x = {
val nowInSeconds = TimeUtil.timeNowInSeconds()
if (!MeetingInactivityTracker.hasRecentActivity(state, nowInSeconds)) {
if (MeetingInactivityTracker.isMeetingInactive(state, nowInSeconds)) {
sendEndMeetingDueToInactivity(props, eventBus)
state
} else {
if (!MeetingInactivityTracker.warningHasBeenSent(state)) {
warnOfMeetingInactivity(props, outGW, nowInSeconds, state)
MeetingInactivityTracker.setWarningSentAndTimestamp(state, nowInSeconds)
} else {
state
}
}
} else {
state
}
}
def warnOfMeetingInactivity(props: DefaultProps, outGW: OutMessageGateway,
nowInSeconds: Long, state: MeetingState2x): Unit = {
val timeLeftSeconds = MeetingInactivityTracker.timeLeftInSeconds(state, nowInSeconds)
sendMeetingInactivityWarning(props, outGW, timeLeftSeconds)
}
def sendEndMeetingDueToInactivity(props: DefaultProps, eventBus: IncomingEventBus): Unit = {
endMeeting(outGW, liveMeeting)
if (liveMeeting.props.meetingProp.isBreakout) {
log.info(
"Informing parent meeting {} that a breakout room has been ended {}",
liveMeeting.props.breakoutProps.parentId, liveMeeting.props.meetingProp.intId
)
notifyParentThatBreakoutEnded(eventBus, liveMeeting)
}
destroyMeeting(eventBus, liveMeeting.props.meetingProp.intId)
}
def sendMeetingInactivityWarning(props: DefaultProps, outGW: OutMessageGateway, timeLeftSeconds: Long): Unit = {
def build(meetingId: String, timeLeftInSec: Long): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingInactivityWarningEvtMsg.NAME, routing)
val body = MeetingInactivityWarningEvtMsgBody(timeLeftInSec)
val header = BbbClientMsgHeader(MeetingInactivityWarningEvtMsg.NAME, meetingId, "not-used")
val event = MeetingInactivityWarningEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = build(props.meetingProp.intId, timeLeftSeconds)
outGW.send(event)
}
def processMeetingActivityResponse(
props: DefaultProps,
outGW: OutMessageGateway,
msg: MeetingActivityResponseCmdMsg
): Unit = {
def buildMeetingIsActiveEvtMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingIsActiveEvtMsg.NAME, routing)
val body = MeetingIsActiveEvtMsgBody(meetingId)
val header = BbbClientMsgHeader(MeetingIsActiveEvtMsg.NAME, meetingId, "not-used")
val event = MeetingIsActiveEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildMeetingIsActiveEvtMsg(props.meetingProp.intId)
outGW.send(event)
}
}

View File

@ -3,6 +3,7 @@ package org.bigbluebutton.core2.message.handlers.meeting
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.bus.IncomingEventBus
import org.bigbluebutton.core.domain.MeetingEndReason
import org.bigbluebutton.core.running.{ BaseMeetingActor, HandlerHelpers, LiveMeeting }
trait EndMeetingSysCmdMsgHdlr extends HandlerHelpers {
@ -13,17 +14,7 @@ trait EndMeetingSysCmdMsgHdlr extends HandlerHelpers {
val eventBus: IncomingEventBus
def handleEndMeeting(msg: EndMeetingSysCmdMsg) {
endMeeting(outGW, liveMeeting)
if (liveMeeting.props.meetingProp.isBreakout) {
log.info(
"Informing parent meeting {} that a breakout room has been ended {}",
liveMeeting.props.breakoutProps.parentId, liveMeeting.props.meetingProp.intId
)
notifyParentThatBreakoutEnded(eventBus, liveMeeting)
}
destroyMeeting(eventBus, liveMeeting.props.meetingProp.intId)
sendEndMeetingDueToExpiry(MeetingEndReason.ENDED_FROM_API, eventBus, outGW, liveMeeting)
}
}

View File

@ -36,4 +36,5 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers {
userId = msg.body.userId, authToken = msg.body.authToken, valid = false, waitForApproval = false, state)
}
}
}

View File

@ -227,26 +227,6 @@ object MsgBuilder {
BbbCommonEnvCoreMsg(envelope, event)
}
def buildMeetingEndingEvtMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingEndingEvtMsg.NAME, routing)
val body = MeetingEndingEvtMsgBody(meetingId)
val header = BbbClientMsgHeader(MeetingEndingEvtMsg.NAME, meetingId, "not-used")
val event = MeetingEndingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildMeetingEndedEvtMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(MeetingEndedEvtMsg.NAME, routing)
val body = MeetingEndedEvtMsgBody(meetingId)
val header = BbbCoreBaseHeader(MeetingEndedEvtMsg.NAME)
val event = MeetingEndedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildBreakoutRoomEndedEvtMsg(meetingId: String, userId: String, breakoutRoomId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(BreakoutRoomEndedEvtMsg.NAME, routing)

View File

@ -9,12 +9,10 @@ case class DisconnectAllConnections(scope: String) extends SystemMessage
class MsgToClientGW(val connInvokerService: IConnectionInvokerService) {
def broadcastToMeeting(msg: BroadcastToMeetingMsg): Unit = {
//println("**** MsgToClientGW broadcastToMeeting " + msg.json)
connInvokerService.sendMessage(msg)
}
def directToClient(msg: DirectToClientMsg): Unit = {
//println("**** MsgToClientGW directToClient " + msg.json)
connInvokerService.sendMessage(msg)
}

View File

@ -59,7 +59,7 @@ case class MeetingEndedEvtMsgBody(meetingId: String)
object MeetingEndingEvtMsg { val NAME = "MeetingEndingEvtMsg"}
case class MeetingEndingEvtMsg(header: BbbClientMsgHeader,
body: MeetingEndingEvtMsgBody) extends BbbCoreMsg
case class MeetingEndingEvtMsgBody(meetingId: String)
case class MeetingEndingEvtMsgBody(meetingId: String, reason: String)
/**

View File

@ -150,14 +150,14 @@ public class ConnectionInvokerService implements IConnectionInvokerService {
}
private void handleCloseMeetingAllConnectionsMsg(CloseMeetingAllConnectionsMsg msg) {
log.info("Disconnecting all clients for meeting {}", msg.meetingId);
IScope meetingScope = getScope(msg.meetingId);
if (meetingScope != null) {
Set<IConnection> conns = meetingScope.getClientConnections();
for (IConnection conn : conns) {
if (conn.isConnected()) {
String connId = (String) conn.getAttribute("INTERNAL_USER_ID");
log.info("Disconnecting client=[{}] from meeting=[{}]", connId, msg.meetingId);
conn.close();
}
}