- track meeting inactivity and expiry in akka-apps
This commit is contained in:
parent
03ea339e21
commit
a61030a95f
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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"
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,4 +36,5 @@ trait ValidateAuthTokenReqMsgHdlr extends HandlerHelpers {
|
||||
userId = msg.body.userId, authToken = msg.body.authToken, valid = false, waitForApproval = false, state)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user