diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala index 88750d7dfd..79cae79e00 100755 --- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala +++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Users2x.scala @@ -68,7 +68,13 @@ object Users2x { } def updateLastUserActivity(users: Users2x, u: UserState): UserState = { - val newUserState = modify(u)(_.lastActivityTime).setTo(TimeUtil.timeNowInMs()) + val newUserState = modify(u)(_.lastActivityTime).setTo(System.currentTimeMillis()) + users.save(newUserState) + newUserState + } + + def updateLastInactivityInspect(users: Users2x, u: UserState): UserState = { + val newUserState = modify(u)(_.lastInactivityInspect).setTo(System.currentTimeMillis()) users.save(newUserState) newUserState } @@ -257,21 +263,22 @@ case class OldPresenter(userId: String, changedPresenterOn: Long) case class UserLeftFlag(left: Boolean, leftOn: Long) case class UserState( - intId: String, - extId: String, - name: String, - role: String, - guest: Boolean, - authed: Boolean, - guestStatus: String, - emoji: String, - locked: Boolean, - presenter: Boolean, - avatar: String, - roleChangedOn: Long = System.currentTimeMillis(), - lastActivityTime: Long = TimeUtil.timeNowInMs(), - clientType: String, - userLeftFlag: UserLeftFlag + intId: String, + extId: String, + name: String, + role: String, + guest: Boolean, + authed: Boolean, + guestStatus: String, + emoji: String, + locked: Boolean, + presenter: Boolean, + avatar: String, + roleChangedOn: Long = System.currentTimeMillis(), + lastActivityTime: Long = System.currentTimeMillis(), + lastInactivityInspect: Long = 0, + clientType: String, + userLeftFlag: UserLeftFlag ) case class UserIdAndName(id: String, name: String) 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 23e0ee18d5..480b0b3a6a 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 @@ -1,7 +1,6 @@ package org.bigbluebutton.core.running import java.io.{ PrintWriter, StringWriter } - import akka.actor._ import akka.actor.SupervisorStrategy.Resume import org.bigbluebutton.SystemConfiguration @@ -40,6 +39,7 @@ import org.bigbluebutton.core.apps.meeting.{ SyncGetMeetingInfoRespMsgHdlr, Vali import org.bigbluebutton.core.apps.users.ChangeLockSettingsInMeetingCmdMsgHdlr import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender } +import java.util.concurrent.TimeUnit import scala.concurrent.ExecutionContext.Implicits.global object MeetingActor { @@ -298,6 +298,14 @@ class MeetingActor( } } + private def updateUserLastInactivityInspect(userId: String) { + for { + user <- Users2x.findWithIntId(liveMeeting.users2x, userId) + } yield { + Users2x.updateLastInactivityInspect(liveMeeting.users2x, user) + } + } + private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = { msg.core match { case m: ClientToServerLatencyTracerMsg => handleClientToServerLatencyTracerMsg(m) @@ -610,7 +618,7 @@ class MeetingActor( var lastRecBreakSentOn = expiryTracker.startedOnInMs def setRecordingChapterBreak(): Unit = { - val now = TimeUtil.timeNowInMs() + val now = System.currentTimeMillis() val elapsedInMs = now - lastRecBreakSentOn val elapsedInMin = TimeUtil.millisToMinutes(elapsedInMs) @@ -723,34 +731,39 @@ class MeetingActor( } } - var lastUserInactivityInspectSentOn = TimeUtil.timeNowInMs() - var checkInactiveUsers = false + var lastUsersInactivityInspection = System.currentTimeMillis() def processUserInactivityAudit(): Unit = { - val now = TimeUtil.timeNowInMs() + + val now = System.currentTimeMillis() // Check if user is inactive. We only do the check is user inactivity // is not disabled (0). if ((expiryTracker.userInactivityInspectTimerInMs > 0) && - (now > lastUserInactivityInspectSentOn + expiryTracker.userInactivityInspectTimerInMs)) { - lastUserInactivityInspectSentOn = now - checkInactiveUsers = true - warnPotentiallyInactiveUsers() - } + (now > lastUsersInactivityInspection + expiryTracker.userInactivityInspectTimerInMs)) { + lastUsersInactivityInspection = now - if (checkInactiveUsers && now > lastUserInactivityInspectSentOn + expiryTracker.userActivitySignResponseDelayInMs) { - checkInactiveUsers = false + warnPotentiallyInactiveUsers() disconnectInactiveUsers() } + } def warnPotentiallyInactiveUsers(): Unit = { log.info("Checking for inactive users.") val users = Users2x.findAll(liveMeeting.users2x) users foreach { u => - val active = (lastUserInactivityInspectSentOn - expiryTracker.userInactivityThresholdInMs) < u.lastActivityTime + + if (u.lastInactivityInspect > u.lastActivityTime) return + + val active = (lastUsersInactivityInspection - expiryTracker.userInactivityThresholdInMs) < u.lastActivityTime if (!active) { - Sender.sendUserInactivityInspectMsg(liveMeeting.props.meetingProp.intId, u.intId, TimeUtil.minutesToSeconds(props.durationProps.userActivitySignResponseDelayInMinutes), outGW) + + log.info("User has been inactive for " + TimeUnit.MILLISECONDS.toMinutes(expiryTracker.userInactivityThresholdInMs) + " minutes. Sending inactivity warning. meetingId=" + props.meetingProp.intId + " userId=" + u.intId + " user=" + u) + + val secsToDisconnect = TimeUnit.MILLISECONDS.toSeconds(expiryTracker.userActivitySignResponseDelayInMs); + Sender.sendUserInactivityInspectMsg(liveMeeting.props.meetingProp.intId, u.intId, secsToDisconnect, outGW) + updateUserLastInactivityInspect(u.intId) } } } @@ -759,8 +772,14 @@ class MeetingActor( log.info("Check for users who haven't responded to user inactivity warning.") val users = Users2x.findAll(liveMeeting.users2x) users foreach { u => - val respondedOnTime = (lastUserInactivityInspectSentOn - expiryTracker.userInactivityThresholdInMs) < u.lastActivityTime && (lastUserInactivityInspectSentOn + expiryTracker.userActivitySignResponseDelayInMs) > u.lastActivityTime + + if (u.lastInactivityInspect == 0 || + u.lastActivityTime > u.lastInactivityInspect) return + + val respondedOnTime = (lastUsersInactivityInspection - expiryTracker.userActivitySignResponseDelayInMs) < u.lastInactivityInspect if (!respondedOnTime) { + log.info("User didn't response the inactivity warning within " + TimeUnit.MILLISECONDS.toSeconds(expiryTracker.userActivitySignResponseDelayInMs) + " seconds. Ejecting from meeting. meetingId=" + props.meetingProp.intId + " userId=" + u.intId + " user=" + u) + UsersApp.ejectUserFromMeeting( outGW, liveMeeting,