diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/LogoutAndEndMeetingCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/LogoutAndEndMeetingCmdMsgHdlr.scala index 90a21bead6..c13562218f 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/LogoutAndEndMeetingCmdMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/LogoutAndEndMeetingCmdMsgHdlr.scala @@ -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) } } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MeetingActivityResponseCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MeetingActivityResponseCmdMsgHdlr.scala index a6f52251ce..ac22a7d39d 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MeetingActivityResponseCmdMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/MeetingActivityResponseCmdMsgHdlr.scala @@ -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) + + } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingInactivityTracker.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingInactivityTracker.scala index d0d59f0e2d..248ba33c02 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingInactivityTracker.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingInactivityTracker.scala @@ -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 -) diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingState2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingState2x.scala index f86cedfdd7..bb880efc73 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingState2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/domain/MeetingState2x.scala @@ -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" +} \ No newline at end of file diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala index 3e43a45ce9..746ac79428 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/HandlerHelpers.scala @@ -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) } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala index c83dc77699..3490373742 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala @@ -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) { diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingExpiryTrackerHelper.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingExpiryTrackerHelper.scala index 3aa361d986..994c23492e 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingExpiryTrackerHelper.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingExpiryTrackerHelper.scala @@ -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) } + } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingInactivityTrackerHelper.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingInactivityTrackerHelper.scala deleted file mode 100755 index eaa592636a..0000000000 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingInactivityTrackerHelper.scala +++ /dev/null @@ -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) - - } -} diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/meeting/EndMeetingSysCmdMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/meeting/EndMeetingSysCmdMsgHdlr.scala index 597f0e7ed8..1358e94059 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/meeting/EndMeetingSysCmdMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/meeting/EndMeetingSysCmdMsgHdlr.scala @@ -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) } } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/users/ValidateAuthTokenReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/users/ValidateAuthTokenReqMsgHdlr.scala index cae96d5cd4..00e4297a66 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/users/ValidateAuthTokenReqMsgHdlr.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/handlers/users/ValidateAuthTokenReqMsgHdlr.scala @@ -36,4 +36,5 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers { userId = msg.body.userId, authToken = msg.body.authToken, valid = false, waitForApproval = false, state) } } + } diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala index e817177c33..928ba490a3 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core2/message/senders/MsgBuilder.scala @@ -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) diff --git a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/MsgToClientGW.scala b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/MsgToClientGW.scala index bec29b9fa7..ab7e762470 100755 --- a/bbb-apps-common/src/main/scala/org/bigbluebutton/client/MsgToClientGW.scala +++ b/bbb-apps-common/src/main/scala/org/bigbluebutton/client/MsgToClientGW.scala @@ -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) } diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala index 755b0cd6f3..82f2aa47c2 100755 --- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala +++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/SystemMsgs.scala @@ -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) /** diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/messaging/ConnectionInvokerService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/messaging/ConnectionInvokerService.java index 86bc8b12ae..d15d351dd5 100755 --- a/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/messaging/ConnectionInvokerService.java +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/red5/client/messaging/ConnectionInvokerService.java @@ -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 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(); } }