Merge pull request #12342 from gustavotrott/user-inactivity-fix

Fix: Eject user from meeting after inactivity warning timeout
This commit is contained in:
Anton Georgiev 2021-05-12 09:51:33 -04:00 committed by GitHub
commit b29d5884e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 33 deletions

View File

@ -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)

View File

@ -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,

View File

@ -64,6 +64,8 @@ class ActivityCheck extends Component {
const { responseDelay } = this.state;
return setInterval(() => {
if(responseDelay == 0) return;
const remainingTime = responseDelay - 1;
this.setState({