Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/v3.0.x-release' into bbb-19580
Browse files Browse the repository at this point in the history
  • Loading branch information
KDSBrowne committed Feb 16, 2024
2 parents 1655af7 + 0974f17 commit e89168c
Show file tree
Hide file tree
Showing 123 changed files with 1,362 additions and 877 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ cache/*
artifacts/*
bbb-presentation-video.zip
bbb-presentation-video
bbb-graphql-actions-adapter-server/
12 changes: 6 additions & 6 deletions akka-bbb-apps/src/main/scala/org/bigbluebutton/Boot.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.bigbluebutton.core.bus._
import org.bigbluebutton.core.pubsub.senders.ReceivedJsonMsgHandlerActor
import org.bigbluebutton.core2.AnalyticsActor
import org.bigbluebutton.core2.FromAkkaAppsMsgSenderActor
import org.bigbluebutton.endpoint.redis.{AppsRedisSubscriberActor, ExportAnnotationsActor, GraphqlActionsActor, LearningDashboardActor, RedisRecorderActor}
import org.bigbluebutton.endpoint.redis.{AppsRedisSubscriberActor, ExportAnnotationsActor, GraphqlConnectionsActor, LearningDashboardActor, RedisRecorderActor}
import org.bigbluebutton.common2.bus.IncomingJsonMessageBus
import org.bigbluebutton.service.{HealthzService, MeetingInfoActor, MeetingInfoService}

Expand Down Expand Up @@ -67,9 +67,9 @@ object Boot extends App with SystemConfiguration {
"LearningDashboardActor"
)

val graphqlActionsActor = system.actorOf(
GraphqlActionsActor.props(system),
"GraphqlActionsActor"
val graphqlConnectionsActor = system.actorOf(
GraphqlConnectionsActor.props(system, eventBus, outGW),
"GraphqlConnectionsActor"
)

ClientSettings.loadClientSettingsFromFile()
Expand All @@ -89,8 +89,8 @@ object Boot extends App with SystemConfiguration {
outBus2.subscribe(learningDashboardActor, outBbbMsgMsgChannel)
bbbMsgBus.subscribe(learningDashboardActor, analyticsChannel)

eventBus.subscribe(graphqlActionsActor, meetingManagerChannel)
bbbMsgBus.subscribe(graphqlActionsActor, analyticsChannel)
eventBus.subscribe(graphqlConnectionsActor, meetingManagerChannel)
bbbMsgBus.subscribe(graphqlConnectionsActor, analyticsChannel)

val bbbActor = system.actorOf(BigBlueButtonActor.props(system, eventBus, bbbMsgBus, outGW, healthzService), "bigbluebutton-actor")
eventBus.subscribe(bbbActor, meetingManagerChannel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class BigBlueButtonActor(
case m: ValidateConnAuthTokenSysMsg => handleValidateConnAuthTokenSysMsg(m)
case _: UserGraphqlConnectionEstablishedSysMsg => //Ignore
case _: UserGraphqlConnectionClosedSysMsg => //Ignore
case _: CheckGraphqlMiddlewareAlivePongSysMsg => //Ignore
case _ => log.warning("Cannot handle " + msg.envelope.name)
}
}
Expand Down Expand Up @@ -190,7 +191,7 @@ class BigBlueButtonActor(
}

// MeetingDAO.delete(msg.meetingId)
MeetingDAO.setMeetingEnded(msg.meetingId)
// MeetingDAO.setMeetingEnded(msg.meetingId)
// Removing the meeting is enough, all other tables has "ON DELETE CASCADE"
// UserDAO.softDeleteAllFromMeeting(msg.meetingId)
// MeetingRecordingDAO.updateStopped(msg.meetingId, "")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.bigbluebutton.core.api

import org.bigbluebutton.core.apps.users.UserEstablishedGraphqlConnectionInternalMsgHdlr
import org.bigbluebutton.core.domain.{ BreakoutUser, BreakoutVoiceUser }
import spray.json.JsObject
case class InMessageHeader(name: String)
Expand Down Expand Up @@ -126,6 +127,18 @@ case class SetPresenterInDefaultPodInternalMsg(presenterId: String) extends InMe
*/
case class CaptureSharedNotesReqInternalMsg(breakoutId: String, filename: String) extends InMessage

/**
* Sent by GraphqlActionsActor to inform MeetingActor that user disconnected
* @param userId
*/
case class UserClosedAllGraphqlConnectionsInternalMsg(userId: String) extends InMessage

/**
* Sent by GraphqlActionsActor to inform MeetingActor that user came back from disconnection
* @param userId
*/
case class UserEstablishedGraphqlConnectionInternalMsg(userId: String) extends InMessage

// DeskShare
case class DeskShareStartedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
case class DeskShareStoppedRequest(conferenceName: String, callerId: String, callerIdName: String) extends InMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
def buildNewPresFileAvailable(annotatedFileURI: String, originalFileURI: String, convertedFileURI: String,
presId: String, fileStateType: String): NewPresFileAvailableMsg = {
val header = BbbClientMsgHeader(NewPresFileAvailableMsg.NAME, "not-used", "not-used")
val body = NewPresFileAvailableMsgBody(annotatedFileURI, originalFileURI, convertedFileURI, presId, fileStateType)
val body = NewPresFileAvailableMsgBody(annotatedFileURI, originalFileURI, convertedFileURI, presId, fileStateType, "")

NewPresFileAvailableMsg(header, body)
}
Expand Down Expand Up @@ -160,7 +160,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val pages: List[Int] = m.body.pages // Desired presentation pages for export
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else pages

val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
val exportJob: ExportJob = new ExportJob(jobId, JobTypes.DOWNLOAD, currentPres.get.name, "annotated_slides", presId, presLocation, allPages, pagesRange, meetingId, "");
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);

val isPresentationOriginalOrConverted = m.body.fileStateType == "Original" || m.body.fileStateType == "Converted"
Expand Down Expand Up @@ -226,7 +226,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
val currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres.get).get
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else List(currentPage.num)

val exportJob: ExportJob = ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
val exportJob: ExportJob = ExportJob(jobId, JobTypes.CAPTURE_PRESENTATION, filename, filename, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
val storeAnnotationPages: List[PresentationPageForExport] = getPresentationPagesForExport(pagesRange, pageCount, presId, currentPres, liveMeeting);

val annotationCount: Int = storeAnnotationPages.map(_.annotations.size).sum
Expand All @@ -252,11 +252,10 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {
liveMeeting.props.meetingProp.intId, m.body.presId
)

//TODO let frontend choose the name in favor of internationalization
if (m.body.fileStateType == "Annotated") {
val presentationDownloadInfo = Map(
"fileURI" -> m.body.annotatedFileURI,
"filename" -> "annotated_slides.pdf"
"filename" -> m.body.fileName
)
ChatMessageDAO.insertSystemMsg(liveMeeting.props.meetingProp.intId, GroupChatApp.MAIN_PUBLIC_CHAT, "", GroupChatMessageType.PRESENTATION, presentationDownloadInfo, "")
} else if (m.body.fileStateType == "Converted") {
Expand Down Expand Up @@ -295,7 +294,7 @@ trait MakePresentationDownloadReqMsgHdlr extends RightsManagementTrait {

bus.outGW.send(buildPresentationUploadTokenSysPubMsg(m.body.parentMeetingId, userId, presentationUploadToken, filename, presentationId))

val exportJob = new ExportJob(jobId, JobTypes.CAPTURE_NOTES, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
val exportJob = new ExportJob(jobId, JobTypes.CAPTURE_NOTES, filename, filename, m.body.padId, "", true, List(), m.body.parentMeetingId, presentationUploadToken)
val job = buildStoreExportJobInRedisSysMsg(exportJob, liveMeeting)

bus.outGW.send(job)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.bigbluebutton.core.apps.users

import org.bigbluebutton.core.api.UserEstablishedGraphqlConnectionInternalMsg
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.{ HandlerHelpers, LiveMeeting, MeetingActor, OutMsgRouter }

trait UserEstablishedGraphqlConnectionInternalMsgHdlr extends HandlerHelpers {
this: MeetingActor =>

val liveMeeting: LiveMeeting
val outGW: OutMsgRouter

def handleUserEstablishedGraphqlConnectionInternalMsg(msg: UserEstablishedGraphqlConnectionInternalMsg, state: MeetingState2x): MeetingState2x = {
log.info("Received user established a graphql connection. user {} meetingId={}", msg.userId, liveMeeting.props.meetingProp.intId)
Users2x.findWithIntId(liveMeeting.users2x, msg.userId) match {
case Some(reconnectingUser) =>
if (reconnectingUser.userLeftFlag.left) {
log.info("Resetting flag that user left meeting. user {}", msg.userId)
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.userId, leftFlag = false)
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.userId)
}
state
case None =>
state
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ trait UserJoinMeetingAfterReconnectReqMsgHdlr extends HandlerHelpers with UserJo
if (reconnectingUser.userLeftFlag.left) {
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
// User has reconnected. Just reset it's flag. ralam Oct 23, 2018
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, false)
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, leftFlag = false)
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId)
}
state
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {

private def resetUserLeftFlag(msg: UserJoinMeetingReqMsg) = {
log.info("Resetting flag that user left meeting. user {}", msg.body.userId)
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, false)
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, leftFlag = false)
Users2x.resetUserLeftFlag(liveMeeting.users2x, msg.body.userId)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.bigbluebutton.core.apps.users

import org.bigbluebutton.common2.msgs.UserLeaveReqMsg
import org.bigbluebutton.core.api.{ UserClosedAllGraphqlConnectionsInternalMsg }
import org.bigbluebutton.core.domain.MeetingState2x
import org.bigbluebutton.core.models.{ RegisteredUsers, Users2x }
import org.bigbluebutton.core.running.{ HandlerHelpers, MeetingActor, OutMsgRouter }
Expand All @@ -12,23 +13,33 @@ trait UserLeaveReqMsgHdlr extends HandlerHelpers {
val outGW: OutMsgRouter

def handleUserLeaveReqMsg(msg: UserLeaveReqMsg, state: MeetingState2x): MeetingState2x = {
Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId) match {
handleUserLeaveReq(msg.body.userId, msg.header.meetingId, msg.body.loggedOut, state)
}

def handleUserClosedAllGraphqlConnectionsInternalMsg(msg: UserClosedAllGraphqlConnectionsInternalMsg, state: MeetingState2x): MeetingState2x = {
log.info("Received user closed all graphql connections. user {} meetingId={}", msg.userId, liveMeeting.props.meetingProp.intId)

handleUserLeaveReq(msg.userId, liveMeeting.props.meetingProp.intId, loggedOut = false, state)
}

def handleUserLeaveReq(userId: String, meetingId: String, loggedOut: Boolean, state: MeetingState2x): MeetingState2x = {
Users2x.findWithIntId(liveMeeting.users2x, userId) match {
case Some(reconnectingUser) =>
log.info("Received user left meeting. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
log.info("Received user left meeting. user {} meetingId={}", userId, meetingId)
if (!reconnectingUser.userLeftFlag.left) {
log.info("Setting user left flag. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
log.info("Setting user left flag. user {} meetingId={}", userId, meetingId)
// Just flag that user has left as the user might be reconnecting.
// An audit will remove this user if it hasn't rejoined after a certain period of time.
// ralam oct 23, 2018
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, msg.body.userId, true)
sendUserLeftFlagUpdatedEvtMsg(outGW, liveMeeting, userId, leftFlag = true)

Users2x.setUserLeftFlag(liveMeeting.users2x, msg.body.userId)
Users2x.setUserLeftFlag(liveMeeting.users2x, userId)
}
if (msg.body.loggedOut) {
log.info("Setting user logged out flag. user {} meetingId={}", msg.body.userId, msg.header.meetingId)
if (loggedOut) {
log.info("Setting user logged out flag. user {} meetingId={}", userId, meetingId)

for {
ru <- RegisteredUsers.findWithUserId(msg.body.userId, liveMeeting.registeredUsers)
ru <- RegisteredUsers.findWithUserId(userId, liveMeeting.registeredUsers)
} yield {
RegisteredUsers.setUserLoggedOutFlag(liveMeeting.registeredUsers, ru)
Sender.sendForceUserGraphqlReconnectionSysMsg(liveMeeting.props.meetingProp.intId, ru.id, ru.sessionToken, "user_loggedout", outGW)
Expand All @@ -39,4 +50,5 @@ trait UserLeaveReqMsgHdlr extends HandlerHelpers {
state
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ case class MeetingDbModel(
createdTime: Long,
durationInSeconds: Int,
endedAt: Option[java.sql.Timestamp],
endedReasonCode: Option[String],
endedBy: Option[String],
)

class MeetingDbTableDef(tag: Tag) extends Table[MeetingDbModel](tag, None, "meeting") {
Expand All @@ -47,7 +49,9 @@ class MeetingDbTableDef(tag: Tag) extends Table[MeetingDbModel](tag, None, "meet
bannerColor,
createdTime,
durationInSeconds,
endedAt
endedAt,
endedReasonCode,
endedBy
) <> (MeetingDbModel.tupled, MeetingDbModel.unapply)
val meetingId = column[String]("meetingId", O.PrimaryKey)
val extId = column[String]("extId")
Expand All @@ -67,6 +71,8 @@ class MeetingDbTableDef(tag: Tag) extends Table[MeetingDbModel](tag, None, "meet
val createdTime = column[Long]("createdTime")
val durationInSeconds = column[Int]("durationInSeconds")
val endedAt = column[Option[java.sql.Timestamp]]("endedAt")
val endedReasonCode = column[Option[String]]("endedReasonCode")
val endedBy = column[Option[String]]("endedBy")
}

object MeetingDAO {
Expand Down Expand Up @@ -100,7 +106,9 @@ object MeetingDAO {
},
createdTime = meetingProps.durationProps.createdTime,
durationInSeconds = meetingProps.durationProps.duration * 60,
endedAt = None
endedAt = None,
endedReasonCode = None,
endedBy = None
)
)
).onComplete {
Expand Down Expand Up @@ -151,15 +159,24 @@ object MeetingDAO {
}
}

def setMeetingEnded(meetingId: String) = {
def setMeetingEnded(meetingId: String, endedReasonCode: String, endedBy: String) = {

UserDAO.softDeleteAllFromMeeting(meetingId)

DatabaseConnection.db.run(
TableQuery[MeetingDbTableDef]
.filter(_.meetingId === meetingId)
.map(a => (a.endedAt))
.update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
.map(a => (a.endedAt, a.endedReasonCode, a.endedBy))
.update(
(
Some(new java.sql.Timestamp(System.currentTimeMillis())),
Some(endedReasonCode),
endedBy match {
case "" => None
case c => Some(c)
}
)
)
).onComplete {
case Success(rowsAffected) => DatabaseConnection.logger.debug(s"$rowsAffected row(s) updated endedAt=now() on Meeting table!")
case Failure(e) => DatabaseConnection.logger.debug(s"Error updating endedAt=now() Meeting: $e")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,35 @@ import scala.util.{Failure, Success }
case class UserGraphqlConnectionDbModel (
graphqlConnectionId: Option[Int],
sessionToken: String,
middlewareUID: String,
middlewareConnectionId: String,
stablishedAt: java.sql.Timestamp,
establishedAt: java.sql.Timestamp,
closedAt: Option[java.sql.Timestamp],
)

class UserGraphqlConnectionDbTableDef(tag: Tag) extends Table[UserGraphqlConnectionDbModel](tag, None, "user_graphqlConnection") {
override def * = (
graphqlConnectionId, sessionToken, middlewareConnectionId, stablishedAt, closedAt
graphqlConnectionId, sessionToken, middlewareUID, middlewareConnectionId, establishedAt, closedAt
) <> (UserGraphqlConnectionDbModel.tupled, UserGraphqlConnectionDbModel.unapply)
val graphqlConnectionId = column[Option[Int]]("graphqlConnectionId", O.PrimaryKey, O.AutoInc)
val sessionToken = column[String]("sessionToken")
val middlewareUID = column[String]("middlewareUID")
val middlewareConnectionId = column[String]("middlewareConnectionId")
val stablishedAt = column[java.sql.Timestamp]("stablishedAt")
val establishedAt = column[java.sql.Timestamp]("establishedAt")
val closedAt = column[Option[java.sql.Timestamp]]("closedAt")
}


object UserGraphqlConnectionDAO {
def insert(sessionToken: String, middlewareConnectionId: String) = {
def insert(sessionToken: String, middlewareUID:String, middlewareConnectionId: String) = {
DatabaseConnection.db.run(
TableQuery[UserGraphqlConnectionDbTableDef].insertOrUpdate(
UserGraphqlConnectionDbModel(
graphqlConnectionId = None,
sessionToken = sessionToken,
middlewareUID = middlewareUID,
middlewareConnectionId = middlewareConnectionId,
stablishedAt = new java.sql.Timestamp(System.currentTimeMillis()),
establishedAt = new java.sql.Timestamp(System.currentTimeMillis()),
closedAt = None
)
)
Expand All @@ -46,11 +49,12 @@ object UserGraphqlConnectionDAO {
}
}

def updateClosed(sessionToken: String, middlewareConnectionId: String) = {
def updateClosed(sessionToken: String, middlewareUID: String, middlewareConnectionId: String) = {
DatabaseConnection.db.run(
TableQuery[UserGraphqlConnectionDbTableDef]
.filter(_.sessionToken === sessionToken)
.filter(_.middlewareConnectionId === middlewareConnectionId)
.filter(_.middlewareUID === middlewareUID)
.filter(_.closedAt.isEmpty)
.map(u => u.closedAt)
.update(Some(new java.sql.Timestamp(System.currentTimeMillis())))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ object Polls {
} yield {
val pageId = if (poll.id.contains("deskshare")) "deskshare" else page.id
val updatedShape = shape + ("whiteboardId" -> pageId)
val annotation = new AnnotationVO(poll.id, updatedShape, pageId, requesterId)
val annotation = new AnnotationVO(s"shape:poll-result-${poll.id}", updatedShape, pageId, requesterId)
annotation
}
}
Expand Down Expand Up @@ -253,12 +253,13 @@ object Polls {

private def pollResultToWhiteboardShape(result: SimplePollResultOutVO): scala.collection.immutable.Map[String, Object] = {
val shape = new scala.collection.mutable.HashMap[String, Object]()
shape += "numRespondents" -> new Integer(result.numRespondents)
shape += "numResponders" -> new Integer(result.numResponders)
shape += "numRespondents" -> Integer.valueOf(result.numRespondents)
shape += "numResponders" -> Integer.valueOf(result.numResponders)
shape += "questionType" -> result.questionType
shape += "questionText" -> result.questionText
shape += "id" -> result.id
shape += "questionText" -> result.questionText.getOrElse("")
shape += "id" -> s"shape:poll-result-${result.id}"
shape += "answers" -> result.answers
shape += "type" -> "geo"
shape.toMap
}

Expand Down

0 comments on commit e89168c

Please sign in to comment.