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 88750d7dfd053bfb36a8129ea252189bd24c7fe6..79cae79e0063729a9630caa013fea706354a6dcf 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 23e0ee18d57004dca31758e9faabfa9d5621eba6..a8e052e5e3945a0eb0132543598934bd11d9b279 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,37 @@ 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 (!active) { - Sender.sendUserInactivityInspectMsg(liveMeeting.props.meetingProp.intId, u.intId, TimeUtil.minutesToSeconds(props.durationProps.userActivitySignResponseDelayInMinutes), outGW) + val hasActivityAfterWarning = u.lastInactivityInspect < u.lastActivityTime + val hasActivityRecently = (lastUsersInactivityInspection - expiryTracker.userInactivityThresholdInMs) < u.lastActivityTime + + if (hasActivityAfterWarning && !hasActivityRecently) { + 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 +770,13 @@ 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 (!respondedOnTime) { + val hasInactivityWarningSent = u.lastInactivityInspect != 0 + val hasActivityAfterWarning = u.lastInactivityInspect < u.lastActivityTime + val respondedOnTime = (lastUsersInactivityInspection - expiryTracker.userActivitySignResponseDelayInMs) < u.lastInactivityInspect + + if (hasInactivityWarningSent && !hasActivityAfterWarning && !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, diff --git a/bigbluebutton-html5/imports/ui/components/activity-check/component.jsx b/bigbluebutton-html5/imports/ui/components/activity-check/component.jsx index 8e6b7a21deb526f7782ce61af7a7f9c741bf6c48..5f027d38011addc90eb725d6f287661005e99940 100644 --- a/bigbluebutton-html5/imports/ui/components/activity-check/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/activity-check/component.jsx @@ -64,6 +64,8 @@ class ActivityCheck extends Component { const { responseDelay } = this.state; return setInterval(() => { + if(responseDelay == 0) return; + const remainingTime = responseDelay - 1; this.setState({