Merge branch 'bbb-2x-mconf' of github.com:bigbluebutton/bigbluebutton into implement-bbb-web-msgs

This commit is contained in:
Anton Georgiev 2017-07-09 10:37:34 -04:00
commit 35b87ee069
212 changed files with 4069 additions and 5817 deletions

View File

@ -102,13 +102,6 @@ public interface IBigBlueButtonInGW {
boolean lock, boolean viewersOnly,
String layout);
// Chat
void getAllChatHistory(String meetingID, String requesterID, String replyTo);
void getChatHistory(String meetingID, String requesterID, String replyTo, String chatId);
void sendPublicMessage(String meetingID, String requesterID, Map<String, String> message);
void sendPrivateMessage(String meetingID, String requesterID, Map<String, String> message);
void clearPublicChatHistory(String meetingID, String requesterID);
// DeskShare
void deskShareStarted(String confId, String callerId, String callerIdName);
void deskShareStopped(String conferenceName, String callerId, String callerIdName);

View File

@ -1,49 +0,0 @@
package org.bigbluebutton.core.pubsub.receivers;
import org.bigbluebutton.common.messages.GetChatHistoryRequestMessage;
import org.bigbluebutton.common.messages.MessagingConstants;
import org.bigbluebutton.common.messages.SendPrivateChatMessage;
import org.bigbluebutton.common.messages.SendPublicChatMessage;
import org.bigbluebutton.common.messages.ClearPublicChatHistoryRequestMessage;
import com.google.gson.JsonParser;
import com.google.gson.JsonObject;
import org.bigbluebutton.core.api.IBigBlueButtonInGW;
public class ChatMessageReceiver implements MessageHandler{
private IBigBlueButtonInGW bbbGW;
public ChatMessageReceiver(IBigBlueButtonInGW bbbGW) {
this.bbbGW = bbbGW;
}
@Override
public void handleMessage(String pattern, String channel, String message) {
if (channel.equalsIgnoreCase(MessagingConstants.TO_CHAT_CHANNEL)) {
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser.parse(message);
if (obj.has("header") && obj.has("payload")) {
JsonObject header = (JsonObject) obj.get("header");
if (header.has("name")) {
String messageName = header.get("name").getAsString();
if (GetChatHistoryRequestMessage.GET_CHAT_HISTORY_REQUEST.equals(messageName)) {
GetChatHistoryRequestMessage msg = GetChatHistoryRequestMessage.fromJson(message);
// TODO: Add chatId to getChatHistory message
bbbGW.getChatHistory(msg.meetingId, msg.requesterId, msg.replyTo, "FIXME!");
} else if (SendPublicChatMessage.SEND_PUBLIC_CHAT_MESSAGE.equals(messageName)){
SendPublicChatMessage msg = SendPublicChatMessage.fromJson(message);
bbbGW.sendPublicMessage(msg.meetingId, msg.requesterId, msg.messageInfo);
} else if (SendPrivateChatMessage.SEND_PRIVATE_CHAT_MESSAGE.equals(messageName)){
SendPrivateChatMessage msg = SendPrivateChatMessage.fromJson(message);
bbbGW.sendPrivateMessage(msg.meetingId, msg.requesterId, msg.messageInfo);
} else if (ClearPublicChatHistoryRequestMessage.CLEAR_PUBLIC_CHAT_HISTORY_REQUEST.equals(messageName)){
ClearPublicChatHistoryRequestMessage msg = ClearPublicChatHistoryRequestMessage.fromJson(message);
bbbGW.clearPublicChatHistory(msg.meetingId, msg.requesterId);
}
}
}
}
}
}

View File

@ -31,9 +31,6 @@ public class RedisMessageReceiver {
}
private void setupReceivers() {
ChatMessageReceiver chatRx = new ChatMessageReceiver(bbbGW);
receivers.add(chatRx);
LockMessageReceiver lockRx = new LockMessageReceiver(bbbGW);
receivers.add(lockRx);

View File

@ -6,14 +6,17 @@ import akka.actor._
import akka.actor.ActorLogging
import akka.actor.SupervisorStrategy.Resume
import akka.util.Timeout
import scala.concurrent.duration._
import org.bigbluebutton.core.bus._
import org.bigbluebutton.core.api._
import org.bigbluebutton.SystemConfiguration
import java.util.concurrent.TimeUnit
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.running.RunningMeeting
import org.bigbluebutton.core2.RunningMeetings
import org.bigbluebutton.core2.message.senders.MsgBuilder
object BigBlueButtonActor extends SystemConfiguration {
def props(system: ActorSystem,
@ -57,10 +60,7 @@ class BigBlueButtonActor(val system: ActorSystem,
// 1x messages
case msg: DestroyMeeting => handleDestroyMeeting(msg)
case msg: KeepAliveMessage => handleKeepAliveMessage(msg)
case msg: PubSubPing => handlePubSubPingMessage(msg)
case msg: ValidateAuthToken => handleValidateAuthToken(msg)
case msg: GetAllMeetingsRequest => handleGetAllMeetingsRequest(msg)
case msg: UserJoinedVoiceConfMessage => handleUserJoinedVoiceConfMessage(msg)
case msg: UserLeftVoiceConfMessage => handleUserLeftVoiceConfMessage(msg)
case msg: UserLockedInVoiceConfMessage => handleUserLockedInVoiceConfMessage(msg)
@ -75,6 +75,7 @@ class BigBlueButtonActor(val system: ActorSystem,
case m: CreateMeetingReqMsg => handleCreateMeetingReqMsg(m)
case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m)
case m: GetAllMeetingsReqMsg => handleGetAllMeetingsReqMsg(m)
case m: PubSubPingSysReqMsg => handlePubSubPingSysReqMsg(m)
case _ => log.warning("Cannot handle " + msg.envelope.name)
}
}
@ -84,6 +85,7 @@ class BigBlueButtonActor(val system: ActorSystem,
for {
m <- RunningMeetings.findWithId(meetings, msg.header.meetingId)
} yield {
log.debug("FORWARDING Registere user message")
m.actorRef forward (msg)
}
}
@ -108,24 +110,10 @@ class BigBlueButtonActor(val system: ActorSystem,
RunningMeetings.add(meetings, m)
// Send old message format
outGW.send(new MeetingCreated(m.props.meetingProp.intId,
m.props.meetingProp.extId, m.props.breakoutProps.parentId,
m.props.recordProp.record, m.props.meetingProp.name,
m.props.voiceProp.voiceConf, m.props.durationProps.duration,
m.props.password.moderatorPass, m.props.password.viewerPass,
m.props.durationProps.createdTime, m.props.durationProps.createdDate,
m.props.meetingProp.isBreakout))
m.actorRef ! new InitializeMeeting(m.props.meetingProp.intId, m.props.recordProp.record)
// Send new 2x message
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(MeetingCreatedEvtMsg.NAME, routing)
val header = BbbCoreBaseHeader(MeetingCreatedEvtMsg.NAME)
val body = MeetingCreatedEvtBody(msg.body.props)
val event = MeetingCreatedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
val msgEvent = MsgBuilder.buildMeetingCreatedEvtMsg(m.props.meetingProp.intId, msg.body.props)
outGW.send(msgEvent)
}
case Some(m) => {
@ -209,12 +197,9 @@ class BigBlueButtonActor(val system: ActorSystem,
//}
}
private def handleKeepAliveMessage(msg: KeepAliveMessage): Unit = {
outGW.send(new KeepAliveMessageReply(msg.aliveID))
}
private def handlePubSubPingMessage(msg: PubSubPing): Unit = {
outGW.send(new PubSubPong(msg.system, msg.timestamp))
private def handlePubSubPingSysReqMsg(msg: PubSubPingSysReqMsg): Unit = {
val event = MsgBuilder.buildPubSubPongSysRespMsg(msg.body.system, msg.body.timestamp)
outGW.send(event)
}
private def handleDestroyMeeting(msg: DestroyMeeting) {
@ -233,16 +218,23 @@ class BigBlueButtonActor(val system: ActorSystem,
}
// Eject all users using the client.
outGW.send(new EndAndKickAll(msg.meetingID, m.props.recordProp.record))
val endAndKickAllEvt = MsgBuilder.buildEndAndKickAllSysMsg(msg.meetingID, "not-used")
outGW.send(endAndKickAllEvt)
// Eject all users from the voice conference
outGW.send(new EjectAllVoiceUsers(msg.meetingID, m.props.recordProp.record, m.props.voiceProp.voiceConf))
val ejectFromVoiceEvent = MsgBuilder.buildEjectAllFromVoiceConfMsg(msg.meetingID, m.props.voiceProp.voiceConf)
outGW.send(ejectFromVoiceEvent)
// Delay sending DisconnectAllUsers because of RTMPT connection being dropped before UserEject message arrives to the client
context.system.scheduler.scheduleOnce(Duration.create(2500, TimeUnit.MILLISECONDS)) {
// Disconnect all clients
outGW.send(new DisconnectAllUsers(msg.meetingID))
val disconnectEvnt = MsgBuilder.buildDisconnectAllClientsSysMsg(msg.meetingID)
outGW.send(disconnectEvnt)
log.info("Destroyed meetingId={}", msg.meetingID)
outGW.send(new MeetingDestroyed(msg.meetingID))
val destroyedEvent = MsgBuilder.buildMeetingDestroyedEvtMsg(msg.meetingID)
outGW.send(destroyedEvent)
/** Unsubscribe to meeting and voice events. **/
eventBus.unsubscribe(m.actorRef, m.props.meetingProp.intId)
@ -288,45 +280,4 @@ class BigBlueButtonActor(val system: ActorSystem,
}
*/
}
private def handleGetAllMeetingsRequest(msg: GetAllMeetingsRequest) {
val len = RunningMeetings.numMeetings(meetings)
var currPosition = len - 1
val resultArray: Array[MeetingInfo] = new Array[MeetingInfo](len)
RunningMeetings.meetings(meetings).foreach(m => {
val id = m.props.meetingProp.intId
val duration = m.props.durationProps.duration
val name = m.props.meetingProp.name
val recorded = m.props.recordProp.record
val voiceBridge = m.props.voiceProp.voiceConf
val info = new MeetingInfo(id, name, recorded, voiceBridge, duration)
resultArray(currPosition) = info
currPosition = currPosition - 1
val html5clientRequesterID = "nodeJSapp"
//send the users
eventBus.publish(BigBlueButtonEvent(id, new GetUsers(id, html5clientRequesterID)))
//send the presentation
eventBus.publish(BigBlueButtonEvent(id, new GetPresentationInfo(id, html5clientRequesterID, html5clientRequesterID)))
//send chat history
eventBus.publish(BigBlueButtonEvent(id, new GetAllChatHistoryRequest(id, html5clientRequesterID, html5clientRequesterID)))
//send lock settings
eventBus.publish(BigBlueButtonEvent(id, new GetLockSettings(id, html5clientRequesterID)))
//send desktop sharing info
eventBus.publish(BigBlueButtonEvent(id, new DeskShareGetDeskShareInfoRequest(id, html5clientRequesterID, html5clientRequesterID)))
// send captions
//eventBus.publish(BigBlueButtonEvent(id, new SendCaptionHistoryRequest(id, html5clientRequesterID)))
})
outGW.send(new GetAllMeetingsReply(resultArray))
}
}

View File

@ -227,7 +227,7 @@ class BigBlueButtonInGW(
}
def ejectUserFromMeeting(meetingId: String, userId: String, ejectedBy: String) {
eventBus.publish(BigBlueButtonEvent(meetingId, new EjectUserFromMeeting(meetingId, userId, ejectedBy)))
}
def logoutEndMeeting(meetingId: String, userId: String) {
@ -247,8 +247,7 @@ class BigBlueButtonInGW(
}
def setUserRole(meetingID: String, userID: String, role: String) {
val userRole = if (role == "MODERATOR") Roles.MODERATOR_ROLE else Roles.VIEWER_ROLE
eventBus.publish(BigBlueButtonEvent(meetingID, new ChangeUserRole(meetingID, userID, userRole)))
}
def getUsers(meetingID: String, requesterID: String) {
@ -412,33 +411,6 @@ class BigBlueButtonInGW(
}
/**
* *******************************************************************
* Message Interface for Chat
* *****************************************************************
*/
def getAllChatHistory(meetingID: String, requesterID: String, replyTo: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new GetAllChatHistoryRequest(meetingID, requesterID, replyTo)))
}
def getChatHistory(meetingID: String, requesterID: String, replyTo: String, chatId: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new GetChatHistoryRequest(meetingID, requesterID, replyTo, chatId)))
}
def sendPublicMessage(meetingID: String, requesterID: String, message: java.util.Map[String, String]) {
// Convert java Map to Scala Map, then convert Mutable map to immutable map
eventBus.publish(BigBlueButtonEvent(meetingID, new SendPublicMessageRequest(meetingID, requesterID, JavaConverters.mapAsScalaMap(message).toMap)))
}
def sendPrivateMessage(meetingID: String, requesterID: String, message: java.util.Map[String, String]) {
eventBus.publish(BigBlueButtonEvent(meetingID, new SendPrivateMessageRequest(meetingID, requesterID, JavaConverters.mapAsScalaMap(message).toMap)))
}
def clearPublicChatHistory(meetingID: String, requesterID: String) {
eventBus.publish(BigBlueButtonEvent(meetingID, new ClearPublicChatHistoryRequest(meetingID, requesterID)))
}
/**
* *******************************************************************
* Message Interface for Voice

View File

@ -8,7 +8,6 @@ import akka.actor.SupervisorStrategy.Resume
import java.io.{ PrintWriter, StringWriter }
import org.bigbluebutton.core.api._
import org.bigbluebutton.common.messages.MessagingConstants
import org.bigbluebutton.core.pubsub.senders.ChatMessageToJsonConverter
import org.bigbluebutton.common.messages.StartRecordingVoiceConfRequestMessage
import org.bigbluebutton.common.messages.StopRecordingVoiceConfRequestMessage
import org.bigbluebutton.core.pubsub.senders.MeetingMessageToJsonConverter
@ -55,10 +54,6 @@ class MessageSenderActor(val service: MessageSender)
val encoder = new ToJsonEncoder()
def receive = {
case msg: UserEjectedFromMeeting => handleUserEjectedFromMeeting(msg)
case msg: GetChatHistoryReply => handleGetChatHistoryReply(msg)
case msg: SendPublicMessageEvent => handleSendPublicMessageEvent(msg)
case msg: SendPrivateMessageEvent => handleSendPrivateMessageEvent(msg)
case msg: ClearPublicChatHistoryReply => handleClearPublicChatHistoryReply(msg)
case msg: MeetingCreated => handleMeetingCreated(msg)
case msg: VoiceRecordingStarted => handleVoiceRecordingStarted(msg)
case msg: VoiceRecordingStopped => handleVoiceRecordingStopped(msg)
@ -178,26 +173,6 @@ class MessageSenderActor(val service: MessageSender)
service.send(MessagingConstants.TO_VOICE_CONF_SYSTEM_CHAN, json)
}
private def handleGetChatHistoryReply(msg: GetChatHistoryReply) {
val json = ChatMessageToJsonConverter.getChatHistoryReplyToJson(msg)
service.send(MessagingConstants.FROM_CHAT_CHANNEL, json)
}
private def handleSendPublicMessageEvent(msg: SendPublicMessageEvent) {
val json = ChatMessageToJsonConverter.sendPublicMessageEventToJson(msg)
service.send(MessagingConstants.FROM_CHAT_CHANNEL, json)
}
private def handleSendPrivateMessageEvent(msg: SendPrivateMessageEvent) {
val json = ChatMessageToJsonConverter.sendPrivateMessageEventToJson(msg)
service.send(MessagingConstants.FROM_CHAT_CHANNEL, json)
}
private def handleClearPublicChatHistoryReply(msg: ClearPublicChatHistoryReply) {
val json = ChatMessageToJsonConverter.clearPublicChatHistoryReplyToJson(msg)
service.send(MessagingConstants.FROM_CHAT_CHANNEL, json)
}
private def handleStartRecordingVoiceConf(msg: StartRecordingVoiceConf) {
val m = new StartRecordingVoiceConfRequestMessage(msg.meetingID, msg.voiceConfId)
service.send(MessagingConstants.TO_VOICE_CONF_SYSTEM_CHAN, m.toJson())

View File

@ -16,7 +16,7 @@ class OutMessageGateway(outgoingEventBus: OutgoingEventBus,
outBus2: OutEventBus2,
recordBus: RecordingEventBus) extends SystemConfiguration {
def send(msg: IOutMessage) {
def send1(msg: IOutMessage) {
outgoingEventBus.publish(BigBlueButtonOutMessage(outMessageChannel, msg))
}

View File

@ -81,11 +81,11 @@ case class UserJoining(meetingID: String, userID: String, authToken: String) ext
case class UserLeaving(meetingID: String, userID: String, sessionId: String) extends InMessage
case class GetUsers(meetingID: String, requesterID: String) extends InMessage
case class UserEmojiStatus(meetingID: String, userId: String, emojiStatus: String) extends InMessage
case class EjectUserFromMeeting(meetingID: String, userId: String, ejectedBy: String) extends InMessage
case class UserShareWebcam(meetingID: String, userId: String, stream: String) extends InMessage
case class UserUnshareWebcam(meetingID: String, userId: String, stream: String) extends InMessage
case class ChangeUserStatus(meetingID: String, userID: String, status: String, value: Object) extends InMessage
case class ChangeUserRole(meetingID: String, userID: String, role: String) extends InMessage
case class AssignPresenter(meetingID: String, newPresenterID: String, newPresenterName: String, assignedBy: String) extends InMessage
case class SetRecordingStatus(meetingID: String, userId: String, recording: Boolean) extends InMessage
case class GetRecordingStatus(meetingID: String, userId: String) extends InMessage
@ -94,14 +94,9 @@ case class ActivityResponse(meetingID: String) extends InMessage
case class LogoutEndMeeting(meetingID: String, userID: String) extends InMessage
//////////////////////////////////////////////////////////////////////////////////
// Chat
// Global Audio
/////////////////////////////////////////////////////////////////////////////////
case class GetAllChatHistoryRequest(meetingID: String, requesterID: String, replyTo: String) extends InMessage
case class GetChatHistoryRequest(meetingID: String, requesterID: String, replyTo: String, chatId: String) extends InMessage
case class SendPublicMessageRequest(meetingID: String, requesterID: String, message: Map[String, String]) extends InMessage
case class SendPrivateMessageRequest(meetingID: String, requesterID: String, message: Map[String, String]) extends InMessage
case class ClearPublicChatHistoryRequest(meetingID: String, requesterID: String) extends InMessage
case class UserConnectedToGlobalAudio(meetingID: String, /** Not used. Just to satisfy trait **/ voiceConf: String,
userid: String, name: String) extends InMessage
case class UserDisconnectedFromGlobalAudio(meetingID: String, /** Not used. Just to satisfy trait **/ voiceConf: String,

View File

@ -41,7 +41,7 @@ case class BreakoutRoomEndedOutMessage(parentMeetingId: String, meetingId: Strin
// Permissions
case class PermissionsSettingInitialized(meetingID: String, permissions: Permissions, applyTo: Array[UserVO]) extends IOutMessage
case class NewPermissionsSetting(meetingID: String, setByUser: String, permissions: Permissions, applyTo: Array[UserVO]) extends IOutMessage
case class NewPermissionsSetting(meetingID: String, setByUser: String, permissions: Permissions, applyTo: Vector[UserState]) extends IOutMessage
case class UserLocked(meetingID: String, userId: String, lock: Boolean) extends IOutMessage
case class GetPermissionsSettingReply(meetingID: String, userId: String) extends IOutMessage
@ -80,15 +80,6 @@ case class StartRecordingVoiceConf(meetingID: String, recorded: Boolean, voiceCo
case class StopRecordingVoiceConf(meetingID: String, recorded: Boolean, voiceConfId: String, recordedStream: String) extends IOutMessage
case class StopRecording(meetingID: String, recorded: Boolean, requesterID: String) extends IOutMessage
// Chat
case class GetChatHistoryReply(meetingID: String, recorded: Boolean, requesterID: String,
replyTo: String, history: Array[Map[String, String]]) extends IOutMessage
case class SendPublicMessageEvent(meetingID: String, recorded: Boolean, requesterID: String,
message: Map[String, String]) extends IOutMessage
case class SendPrivateMessageEvent(meetingID: String, recorded: Boolean, requesterID: String,
message: Map[String, String]) extends IOutMessage
case class ClearPublicChatHistoryReply(meetingID: String, recorded: Boolean, requesterID: String) extends IOutMessage
// Layout
case class GetCurrentLayoutReply(meetingID: String, recorded: Boolean, requesterID: String, layoutID: String,
locked: Boolean, setByUserID: String) extends IOutMessage

View File

@ -1,254 +0,0 @@
package org.bigbluebutton.core.apps
import java.net.URLEncoder
import scala.collection.SortedSet
import scala.collection.mutable
import org.apache.commons.codec.digest.DigestUtils
import org.bigbluebutton.SystemConfiguration
import org.bigbluebutton.common2.msgs.{ BreakoutRoomInfo, BreakoutUserVO }
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.bus.BigBlueButtonEvent
import org.bigbluebutton.core.bus.IncomingEventBus
import org.bigbluebutton.core.models.BreakoutRooms
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait BreakoutRoomApp extends SystemConfiguration {
this: MeetingActor =>
val outGW: OutMessageGateway
val eventBus: IncomingEventBus
def handleBreakoutRoomsList(msg: BreakoutRoomsListMessage) {
val breakoutRooms = BreakoutRooms.getRooms(liveMeeting.breakoutRooms).toVector map { r =>
new BreakoutRoomInfo(r.name, r.externalMeetingId, r.id, r.sequence)
}
val roomsReady = liveMeeting.breakoutRooms.pendingRoomsNumber == 0 && breakoutRooms.length > 0
log.info("Sending breakout rooms list to {} with containing {} room(s)", props.meetingProp.intId, breakoutRooms.length)
outGW.send(new BreakoutRoomsListOutMessage(props.meetingProp.intId, breakoutRooms, roomsReady))
}
def handleCreateBreakoutRooms(msg: CreateBreakoutRooms) {
// If breakout rooms are being created we ignore the coming message
if (liveMeeting.breakoutRooms.pendingRoomsNumber > 0) {
log.warning("CreateBreakoutRooms event received while {} are pending to be created for meeting {}",
liveMeeting.breakoutRooms.pendingRoomsNumber, props.meetingProp.intId)
return
}
if (BreakoutRooms.getNumberOfRooms(liveMeeting.breakoutRooms) > 0) {
log.warning("CreateBreakoutRooms event received while {} breakout rooms running for meeting {}",
BreakoutRooms.getNumberOfRooms(liveMeeting.breakoutRooms), props.meetingProp.intId)
return
}
var i = 0
// in very rare cases the presentation conversion generates an error, what should we do?
// those cases where default.pdf is deleted from the whiteboard
val sourcePresentationId = if (!liveMeeting.presModel.getCurrentPresentation().isEmpty) liveMeeting.presModel.getCurrentPresentation().get.id else "blank"
val sourcePresentationSlide = if (!liveMeeting.presModel.getCurrentPage().isEmpty) liveMeeting.presModel.getCurrentPage().get.num else 0
liveMeeting.breakoutRooms.pendingRoomsNumber = msg.rooms.length;
for (room <- msg.rooms) {
i += 1
val breakoutMeetingId = BreakoutRoomsUtil.createMeetingIds(props.meetingProp.intId, i)
val voiceConfId = BreakoutRoomsUtil.createVoiceConfId(props.voiceProp.voiceConf, i)
for {
r <- BreakoutRooms.newBreakoutRoom(props.meetingProp.intId, breakoutMeetingId._1, breakoutMeetingId._2, room.name,
room.sequence, voiceConfId, room.users, liveMeeting.breakoutRooms)
} yield {
val p = new BreakoutRoomOutPayload(r.id, r.name, props.meetingProp.intId, r.sequence,
r.voiceConfId, msg.durationInMinutes, props.password.moderatorPass, props.password.viewerPass,
sourcePresentationId, sourcePresentationSlide, msg.record)
outGW.send(new CreateBreakoutRoom(props.meetingProp.intId, p))
}
}
MeetingStatus2x.breakoutRoomsdurationInMinutes(liveMeeting.status, msg.durationInMinutes)
MeetingStatus2x.breakoutRoomsStartedOn(liveMeeting.status, MeetingStatus2x.timeNowInSeconds)
}
def sendJoinURL(userId: String, externalMeetingId: String, roomSequence: String) {
log.debug("Sending breakout meeting {} Join URL for user: {}", externalMeetingId, userId)
for {
user <- Users1x.findWithId(userId, liveMeeting.users)
apiCall = "join"
params = BreakoutRoomsUtil.joinParams(user.name, userId + "-" + roomSequence, true,
externalMeetingId, props.password.moderatorPass)
// We generate a first url with redirect -> true
redirectBaseString = BreakoutRoomsUtil.createBaseString(params._1)
redirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, redirectBaseString,
BreakoutRoomsUtil.calculateChecksum(apiCall, redirectBaseString, bbbWebSharedSecret))
// We generate a second url with redirect -> false
noRedirectBaseString = BreakoutRoomsUtil.createBaseString(params._2)
noRedirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, noRedirectBaseString,
BreakoutRoomsUtil.calculateChecksum(apiCall, noRedirectBaseString, bbbWebSharedSecret))
} yield outGW.send(new BreakoutRoomJoinURLOutMessage(props.meetingProp.intId,
props.recordProp.record, externalMeetingId, userId, redirectJoinURL, noRedirectJoinURL))
}
def handleRequestBreakoutJoinURL(msg: RequestBreakoutJoinURLInMessage) {
for {
breakoutRoom <- BreakoutRooms.getRoomWithExternalId(liveMeeting.breakoutRooms, msg.breakoutMeetingId)
} yield sendJoinURL(msg.userId, msg.breakoutMeetingId, breakoutRoom.sequence.toString())
}
def handleBreakoutRoomCreated(msg: BreakoutRoomCreated) {
liveMeeting.breakoutRooms.pendingRoomsNumber -= 1
val room = BreakoutRooms.getBreakoutRoom(liveMeeting.breakoutRooms, msg.breakoutRoomId)
room foreach { room =>
sendBreakoutRoomStarted(room.parentRoomId, room.name, room.externalMeetingId, room.id, room.sequence, room.voiceConfId)
}
// We postpone sending invitation until all breakout rooms have been created
if (liveMeeting.breakoutRooms.pendingRoomsNumber == 0) {
log.info("All breakout rooms created for meetingId={}", props.meetingProp.intId)
BreakoutRooms.getRooms(liveMeeting.breakoutRooms).foreach { room =>
BreakoutRooms.getAssignedUsers(liveMeeting.breakoutRooms, room.id) foreach { users =>
users.foreach { u =>
log.debug("Sending Join URL for users");
sendJoinURL(u, room.externalMeetingId, room.sequence.toString())
}
}
}
handleBreakoutRoomsList(new BreakoutRoomsListMessage(props.meetingProp.intId))
}
}
def sendBreakoutRoomStarted(meetingId: String, breakoutName: String, externalMeetingId: String,
breakoutMeetingId: String, sequence: Int, voiceConfId: String) {
log.info("Sending breakout room started {} for parent meeting {} ", breakoutMeetingId, meetingId);
outGW.send(new BreakoutRoomStartedOutMessage(meetingId, props.recordProp.record, new BreakoutRoomInfo(breakoutName,
externalMeetingId, breakoutMeetingId, sequence)))
}
def handleBreakoutRoomEnded(msg: BreakoutRoomEnded) {
BreakoutRooms.removeRoom(liveMeeting.breakoutRooms, msg.breakoutRoomId)
outGW.send(new BreakoutRoomEndedOutMessage(msg.meetingId, msg.breakoutRoomId))
}
def handleBreakoutRoomUsersUpdate(msg: BreakoutRoomUsersUpdate) {
BreakoutRooms.updateBreakoutUsers(liveMeeting.breakoutRooms, msg.breakoutMeetingId, msg.users) foreach { room =>
outGW.send(new UpdateBreakoutUsersOutMessage(props.meetingProp.intId, props.recordProp.record, msg.breakoutMeetingId, room.users))
}
}
def handleSendBreakoutUsersUpdate(msg: SendBreakoutUsersUpdate) {
val users = Users1x.getUsers(liveMeeting.users)
val breakoutUsers = users map { u => new BreakoutUserVO(u.externalId, u.name) }
eventBus.publish(BigBlueButtonEvent(props.breakoutProps.parentId,
new BreakoutRoomUsersUpdate(props.breakoutProps.parentId, props.meetingProp.intId, breakoutUsers)))
}
def handleTransferUserToMeeting(msg: TransferUserToMeetingRequest) {
var targetVoiceBridge: String = msg.targetMeetingId
// If the current room is a parent room we fetch the voice bridge from the breakout room
if (!props.meetingProp.isBreakout) {
BreakoutRooms.getBreakoutRoom(liveMeeting.breakoutRooms, msg.targetMeetingId) match {
case Some(b) => {
targetVoiceBridge = b.voiceConfId;
}
case None => // do nothing
}
} // if it is a breakout room, the target voice bridge is the same after removing the last digit
else {
targetVoiceBridge = props.voiceProp.voiceConf.dropRight(1)
}
// We check the user from the mode
Users1x.findWithId(msg.userId, liveMeeting.users) match {
case Some(u) => {
if (u.voiceUser.joined) {
log.info("Transferring user userId=" + u.id + " from voiceBridge=" + props.voiceProp.voiceConf + " to targetVoiceConf=" + targetVoiceBridge)
outGW.send(new TransferUserToMeeting(props.voiceProp.voiceConf, targetVoiceBridge, u.voiceUser.userId))
}
}
case None => // do nothing
}
}
def handleEndAllBreakoutRooms(msg: EndAllBreakoutRooms) {
log.info("EndAllBreakoutRooms event received for meetingId={}", props.meetingProp.intId)
BreakoutRooms.getRooms(liveMeeting.breakoutRooms).foreach { room =>
outGW.send(new EndBreakoutRoom(room.id))
}
}
}
object BreakoutRoomsUtil {
def createMeetingIds(id: String, index: Int): (String, String) = {
val timeStamp = System.currentTimeMillis()
val externalHash = DigestUtils.sha1Hex(id.concat("-").concat(timeStamp.toString()).concat("-").concat(index.toString()))
val externalId = externalHash.concat("-").concat(timeStamp.toString())
val internalId = DigestUtils.sha1Hex(externalId).concat("-").concat(timeStamp.toString())
(internalId, externalId)
}
def createVoiceConfId(id: String, index: Int): String = {
id.concat(index.toString())
}
def createJoinURL(webAPI: String, apiCall: String, baseString: String, checksum: String): String = {
val apiURL = if (webAPI.endsWith("/")) webAPI else webAPI.concat("/")
apiURL.concat(apiCall).concat("?").concat(baseString).concat("&checksum=").concat(checksum)
}
//
//checksum() -- Return a checksum based on SHA-1 digest
//
def checksum(s: String): String = {
DigestUtils.sha1Hex(s);
}
def calculateChecksum(apiCall: String, baseString: String, sharedSecret: String): String = {
checksum(apiCall.concat(baseString).concat(sharedSecret))
}
def joinParams(username: String, userId: String, isBreakout: Boolean, breakoutMeetingId: String,
password: String): (mutable.Map[String, String], mutable.Map[String, String]) = {
val params = collection.mutable.HashMap(
"fullName" -> urlEncode(username),
"userID" -> urlEncode(userId),
"isBreakout" -> urlEncode(isBreakout.toString()),
"meetingID" -> urlEncode(breakoutMeetingId),
"password" -> urlEncode(password))
(params += "redirect" -> urlEncode("true"), mutable.Map[String, String]() ++= params += "redirect" -> urlEncode("false"))
}
def sortParams(params: mutable.Map[String, String]): SortedSet[String] = {
collection.immutable.SortedSet[String]() ++ params.keySet
}
//From the list of parameters we want to pass. Creates a base string with parameters
//sorted in alphabetical order for us to sign.
def createBaseString(params: mutable.Map[String, String]): String = {
val csbuf = new StringBuffer()
val keys = sortParams(params)
var first = true;
for (key <- keys) {
for (value <- params.get(key)) {
if (first) {
first = false;
} else {
csbuf.append("&");
}
csbuf.append(key);
csbuf.append("=");
csbuf.append(value);
}
}
return csbuf.toString();
}
def urlEncode(s: String): String = {
URLEncoder.encode(s, "UTF-8");
}
}

View File

@ -1,36 +0,0 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.{ OutMessageGateway }
trait ChatApp {
val props: DefaultProps
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleGetChatHistoryRequest(msg: GetChatHistoryRequest) {
val history = liveMeeting.chatModel.getChatHistory()
outGW.send(new GetChatHistoryReply(props.meetingProp.intId, props.recordProp.record, msg.requesterID, msg.replyTo, history))
}
def handleSendPublicMessageRequest(msg: SendPublicMessageRequest) {
liveMeeting.chatModel.addNewChatMessage(msg.message)
val pubMsg = msg.message
outGW.send(new SendPublicMessageEvent(props.meetingProp.intId, props.recordProp.record, msg.requesterID, pubMsg))
}
def handleSendPrivateMessageRequest(msg: SendPrivateMessageRequest) {
val privMsg = msg.message
outGW.send(new SendPrivateMessageEvent(props.meetingProp.intId, props.recordProp.record, msg.requesterID, privMsg))
}
def handleClearPublicChatHistoryRequest(msg: ClearPublicChatHistoryRequest) {
liveMeeting.chatModel.clearPublicChatHistory()
outGW.send(new ClearPublicChatHistoryReply(props.meetingProp.intId, props.recordProp.record, msg.requesterID))
}
}

View File

@ -1,29 +0,0 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.SendDirectChatMsgCmd
import org.bigbluebutton.core.models.DirectChats
import org.bigbluebutton.core.running.LiveMeeting
trait ChatAppHandlers {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleSendDirectChatMsgCmd(msg: SendDirectChatMsgCmd): Unit = {
def send(): Unit = {
}
val between = Set("foo", "bar")
for {
chat <- DirectChats.find(between, liveMeeting.chatModel.directChats)
} yield {
send()
}
}
def handleCreatePublicChatCmd(): Unit = {
}
}

View File

@ -1,35 +1,28 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.common2.msgs.ChatMessageVO
import org.bigbluebutton.core.models.{ DirectChats, PublicChats }
import scala.collection.mutable.ArrayBuffer
object ChatModel {
def getChatHistory(chatModel: ChatModel): Array[Map[String, String]] = {
chatModel.getChatHistory()
def getChatHistory(chatModel: ChatModel): Array[ChatMessageVO] = {
chatModel.messages.toArray
}
def addNewChatMessage(chatModel: ChatModel, msg: ChatMessageVO) {
chatModel.messages.append(msg)
}
def clearPublicChatHistory(chatModel: ChatModel) {
chatModel.messages.clear()
}
}
class ChatModel {
val directChats = new DirectChats
val publicChats = new PublicChats
//val directChats = new DirectChats
//val publicChats = new PublicChats
private val messages = new ArrayBuffer[Map[String, String]]()
def getChatHistory(): Array[Map[String, String]] = {
val history = new Array[Map[String, String]](messages.size)
messages.copyToArray(history)
history
}
def addNewChatMessage(msg: Map[String, String]) {
messages append msg
}
def clearPublicChatHistory() {
messages.clear();
}
private val messages = new ArrayBuffer[ChatMessageVO]()
}

View File

@ -1,19 +0,0 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.core.running.LiveMeeting
trait ChatModelTrait {
this: LiveMeeting =>
def getChatHistory(): Array[Map[String, String]] = {
ChatModel.getChatHistory(chatModel)
}
def addNewChatMessage(msg: Map[String, String]) = {
chatModel.addNewChatMessage(msg)
}
def clearPublicChatHistory(): Unit = {
chatModel.clearPublicChatHistory()
}
}

View File

@ -0,0 +1,115 @@
package org.bigbluebutton.core.apps
object DeskshareModel {
def resetDesktopSharingParams(status: DeskshareModel) = {
status.broadcastingRTMP = false
status.deskShareStarted = false
status.rtmpBroadcastingUrl = ""
status.desktopShareVideoWidth = 0
status.desktopShareVideoHeight = 0
}
def getDeskShareStarted(status: DeskshareModel): Boolean = {
return status.deskShareStarted
}
def setDeskShareStarted(status: DeskshareModel, b: Boolean) {
status.deskShareStarted = b
}
def setDesktopShareVideoWidth(status: DeskshareModel, videoWidth: Int) {
status.desktopShareVideoWidth = videoWidth
}
def setDesktopShareVideoHeight(status: DeskshareModel, videoHeight: Int) {
status.desktopShareVideoHeight = videoHeight
}
def getDesktopShareVideoWidth(status: DeskshareModel): Int = {
status.desktopShareVideoWidth
}
def getDesktopShareVideoHeight(status: DeskshareModel): Int = {
status.desktopShareVideoHeight
}
def broadcastingRTMPStarted(status: DeskshareModel) {
status.broadcastingRTMP = true
}
def isBroadcastingRTMP(status: DeskshareModel): Boolean = {
status.broadcastingRTMP
}
def broadcastingRTMPStopped(status: DeskshareModel) {
status.broadcastingRTMP = false
}
def setRTMPBroadcastingUrl(status: DeskshareModel, path: String) {
status.rtmpBroadcastingUrl = path
}
def getRTMPBroadcastingUrl(status: DeskshareModel): String = {
status.rtmpBroadcastingUrl
}
}
class DeskshareModel {
private var rtmpBroadcastingUrl: String = ""
private var deskShareStarted = false
private var desktopShareVideoWidth = 0
private var desktopShareVideoHeight = 0
private var broadcastingRTMP = false
private def resetDesktopSharingParams() = {
broadcastingRTMP = false
deskShareStarted = false
rtmpBroadcastingUrl = ""
desktopShareVideoWidth = 0
desktopShareVideoHeight = 0
}
private def getDeskShareStarted(): Boolean = {
return deskShareStarted
}
private def setDeskShareStarted(b: Boolean) {
deskShareStarted = b
}
private def setDesktopShareVideoWidth(videoWidth: Int) {
desktopShareVideoWidth = videoWidth
}
private def setDesktopShareVideoHeight(videoHeight: Int) {
desktopShareVideoHeight = videoHeight
}
private def getDesktopShareVideoWidth(): Int = {
desktopShareVideoWidth
}
private def getDesktopShareVideoHeight(): Int = {
desktopShareVideoHeight
}
private def broadcastingRTMPStarted() {
broadcastingRTMP = true
}
private def isBroadcastingRTMP(): Boolean = {
broadcastingRTMP
}
private def broadcastingRTMPStopped() {
broadcastingRTMP = false
}
private def setRTMPBroadcastingUrl(path: String) {
rtmpBroadcastingUrl = path
}
private def getRTMPBroadcastingUrl(): String = {
rtmpBroadcastingUrl
}
}

View File

@ -1,62 +0,0 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.models._
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait LayoutApp {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleGetCurrentLayoutRequest(msg: GetCurrentLayoutRequest) {
outGW.send(new GetCurrentLayoutReply(msg.meetingID, props.recordProp.record, msg.requesterID,
Layouts.getCurrentLayout(),
MeetingStatus2x.getPermissions(liveMeeting.status).lockedLayout,
Layouts.getLayoutSetter()))
}
def handleLockLayoutRequest(msg: LockLayoutRequest) {
Layouts.applyToViewersOnly(msg.viewersOnly)
liveMeeting.lockLayout(msg.lock)
//outGW.send(new LockLayoutEvent(msg.meetingID, props.recordProp.record, msg.setById, msg.lock, affectedUsers))
msg.layout foreach { l =>
Layouts.setCurrentLayout(l)
broadcastSyncLayout(msg.meetingID, msg.setById)
}
}
private def broadcastSyncLayout(meetingId: String, setById: String) {
//outGW.send(new BroadcastLayoutEvent(meetingId, props.recordProp.record, setById,
// Layouts.getCurrentLayout(),
// MeetingStatus2x.getPermissions(liveMeeting.status).lockedLayout,
// Layouts.getLayoutSetter(), affectedUsers))
}
def handleBroadcastLayoutRequest(msg: BroadcastLayoutRequest) {
Layouts.setCurrentLayout(msg.layout)
broadcastSyncLayout(msg.meetingID, msg.requesterID)
}
def handleLockLayout(lock: Boolean, setById: String) {
// outGW.send(new LockLayoutEvent(props.meetingProp.intId, props.recordProp.record, setById, lock, affectedUsers))
broadcastSyncLayout(props.meetingProp.intId, setById)
}
def affectedUsers(): Vector[String] = {
if (Layouts.doesLayoutApplyToViewersOnly()) {
val users = Users2x.findAll(liveMeeting.users2x) filter { u =>
(!u.presenter && u.role != Roles.MODERATOR_ROLE)
}
users.map(u => u.intId)
} else {
Users2x.findAll(liveMeeting.users2x).map(u => u.intId)
}
}
}

View File

@ -1,195 +0,0 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.core.api._
import scala.collection.mutable.ArrayBuffer
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.{ MeetingActor }
import com.google.gson.Gson
import java.util.ArrayList
import org.bigbluebutton.core.OutMessageGateway
trait PollApp {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleGetPollRequest(msg: GetPollRequest) {
}
def handleGetCurrentPollRequest(msg: GetCurrentPollRequest) {
val poll = for {
page <- liveMeeting.presModel.getCurrentPage()
curPoll <- PollModel.getRunningPollThatStartsWith(page.id, liveMeeting.pollModel)
} yield curPoll
poll match {
case Some(p) => {
if (p.started && p.stopped && p.showResult) {
outGW.send(new GetCurrentPollReplyMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, true, Some(p)))
} else {
outGW.send(new GetCurrentPollReplyMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, false, None))
}
}
case None => {
outGW.send(new GetCurrentPollReplyMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, false, None))
}
}
}
def handleRespondToPollRequest(msg: RespondToPollRequest) {
for {
poll <- PollModel.getSimplePollResult(msg.pollId, liveMeeting.pollModel)
} yield handleRespondToPoll(poll, msg)
}
def handleHidePollResultRequest(msg: HidePollResultRequest) {
for {
poll <- PollModel.getPoll(msg.pollId, liveMeeting.pollModel)
} yield {
PollModel.hidePollResult(msg.pollId, liveMeeting.pollModel)
outGW.send(new PollHideResultMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, msg.pollId))
}
}
def pollResultToWhiteboardShape(result: SimplePollResultOutVO, msg: ShowPollResultRequest): scala.collection.immutable.Map[String, Object] = {
val shape = new scala.collection.mutable.HashMap[String, Object]()
shape += "num_respondents" -> new Integer(result.numRespondents)
shape += "num_responders" -> new Integer(result.numResponders)
shape += "type" -> "poll_result"
shape += "id" -> result.id
shape += "status" -> "DRAW_END"
val answers = new ArrayBuffer[java.util.HashMap[String, Object]];
result.answers.foreach(ans => {
val amap = new java.util.HashMap[String, Object]()
amap.put("id", ans.id: java.lang.Integer)
amap.put("key", ans.key)
amap.put("num_votes", ans.numVotes: java.lang.Integer)
answers += amap
})
val gson = new Gson()
shape += "result" -> gson.toJson(answers.toArray)
// Hardcode poll result display location for now to display result
// in bottom-right corner.
val display = new ArrayList[Double]()
val shapeHeight = 6.66 * answers.size
display.add(66.0)
display.add(100 - shapeHeight)
display.add(34.0)
display.add(shapeHeight)
shape += "points" -> display
shape.toMap
}
def handleShowPollResultRequest(msg: ShowPollResultRequest) {
def send(poll: SimplePollResultOutVO, shape: scala.collection.immutable.Map[String, Object]): Unit = {
/*
for {
page <- liveMeeting.presModel.getCurrentPage()
pageId = if (poll.id.contains("deskshare")) "deskshare" else page.id
annotation = new AnnotationProps(poll.id, WhiteboardKeyUtil.DRAW_END_STATUS, WhiteboardKeyUtil.POLL_RESULT_TYPE, shape, page.id, msg.requesterId, -1)
} handleSendWhiteboardAnnotationRequest(new SendWhiteboardAnnotationRequest(props.meetingProp.intId, msg.requesterId, annotation))
*/
}
for {
poll <- PollModel.getSimplePollResult(msg.pollId, liveMeeting.pollModel)
shape = pollResultToWhiteboardShape(poll, msg)
} yield {
send(poll, shape)
PollModel.showPollResult(msg.pollId, liveMeeting.pollModel)
outGW.send(new PollShowResultMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, msg.pollId, poll))
}
}
def handleStopPollRequest(msg: StopPollRequest) {
for {
page <- liveMeeting.presModel.getCurrentPage()
curPoll <- PollModel.getRunningPollThatStartsWith(page.id, liveMeeting.pollModel)
} yield {
PollModel.stopPoll(curPoll.id, liveMeeting.pollModel)
outGW.send(new PollStoppedMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, curPoll.id))
}
}
def handleStartCustomPollRequest(msg: StartCustomPollRequest) {
log.debug("Received StartCustomPollRequest for pollType=[" + msg.pollType + "]")
def createPoll(pollId: String, numRespondents: Int): Option[Poll] = {
for {
poll <- PollFactory.createPoll(pollId, msg.pollType, numRespondents, Some(msg.answers))
} yield {
PollModel.addPoll(poll, liveMeeting.pollModel)
poll
}
}
for {
page <- liveMeeting.presModel.getCurrentPage()
pageId = if (msg.pollId.contains("deskshare")) "deskshare" else page.id;
pollId = pageId + "/" + System.currentTimeMillis()
numRespondents = Users1x.numUsers(liveMeeting.users) - 1 // subtract the presenter
poll <- createPoll(pollId, numRespondents)
simplePoll <- PollModel.getSimplePoll(pollId, liveMeeting.pollModel)
} yield {
PollModel.startPoll(poll.id, liveMeeting.pollModel)
outGW.send(new PollStartedMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, pollId, simplePoll))
}
}
def handleStartPollRequest(msg: StartPollRequest) {
log.debug("Received StartPollRequest for pollType=[" + msg.pollType + "]")
def createPoll(pollId: String, numRespondents: Int): Option[Poll] = {
for {
poll <- PollFactory.createPoll(pollId, msg.pollType, numRespondents, None)
} yield {
PollModel.addPoll(poll, liveMeeting.pollModel)
poll
}
}
for {
page <- liveMeeting.presModel.getCurrentPage()
pageId = if (msg.pollId.contains("deskshare")) "deskshare" else page.id
pollId = pageId + "/" + System.currentTimeMillis()
numRespondents = Users1x.numUsers(liveMeeting.users) - 1 // subtract the presenter
poll <- createPoll(pollId, numRespondents)
simplePoll <- PollModel.getSimplePoll(pollId, liveMeeting.pollModel)
} yield {
PollModel.startPoll(poll.id, liveMeeting.pollModel)
outGW.send(new PollStartedMessage(props.meetingProp.intId, props.recordProp.record, msg.requesterId, pollId, simplePoll))
}
}
private def handleRespondToPoll(poll: SimplePollResultOutVO, msg: RespondToPollRequest) {
/*
* Hardcode to zero as we are assuming the poll has only one question.
* Our data model supports multiple question polls but for this
* release, we only have a simple poll which has one question per poll.
* (ralam june 23, 2015)
*/
val questionId = 0
def storePollResult(responder: Responder): Option[SimplePollResultOutVO] = {
PollModel.respondToQuestion(poll.id, questionId, msg.answerId, responder, liveMeeting.pollModel)
for {
updatedPoll <- PollModel.getSimplePollResult(poll.id, liveMeeting.pollModel)
} yield updatedPoll
}
for {
user <- Users1x.findWithId(msg.requesterId, liveMeeting.users)
responder = new Responder(user.id, user.name)
updatedPoll <- storePollResult(responder)
curPres <- Users1x.getCurrentPresenter(liveMeeting.users)
} yield outGW.send(new UserRespondedToPollMessage(props.meetingProp.intId, props.recordProp.record, curPres.id, msg.pollId, updatedPoll))
}
}

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core.apps
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x

View File

@ -1,137 +0,0 @@
package org.bigbluebutton.core.apps
import org.bigbluebutton.common2.domain.UserVO
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models._
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
import org.bigbluebutton.core2.message.handlers.users.{ UserEmojiStatusHdlr, UserLeavingHdlr }
trait UsersApp extends UserLeavingHdlr with UserEmojiStatusHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def usersWhoAreNotPresenter(): Array[UserVO] = {
Users1x.usersWhoAreNotPresenter(liveMeeting.users).toArray
}
def makeSurePresenterIsAssigned(user: UserVO): Unit = {
if (user.presenter) {
/* The current presenter has left the meeting. Find a moderator and make
* him presenter. This way, if there is a moderator in the meeting, there
* will always be a presenter.
*/
val moderator = Users1x.findAModerator(liveMeeting.users)
moderator.foreach { mod =>
log.info("Presenter left meeting. meetingId=" + props.meetingProp.intId + " userId=" + user.id
+ ". Making user=[" + mod.id + "] presenter.")
assignNewPresenter(mod.id, mod.name, mod.id)
}
if (MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status)) {
// The presenter left during desktop sharing. Stop desktop sharing on FreeSWITCH
outGW.send(new DeskShareHangUp(props.meetingProp.intId, props.voiceProp.voiceConf))
// notify other clients to close their deskshare view
outGW.send(new DeskShareNotifyViewersRTMP(props.meetingProp.intId,
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status),
MeetingStatus2x.getDesktopShareVideoWidth(liveMeeting.status),
MeetingStatus2x.getDesktopShareVideoHeight(liveMeeting.status), false))
// reset meeting info
MeetingStatus2x.resetDesktopSharingParams(liveMeeting.status)
}
}
}
def getInitialLockStatus(role: String): Boolean = {
MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin && !role.equals(Roles.MODERATOR_ROLE)
}
def stopRecordingVoiceConference() {
if (Users1x.numUsersInVoiceConference(liveMeeting.users) == 0 &&
props.recordProp.record &&
MeetingStatus2x.isVoiceRecording(liveMeeting.status)) {
MeetingStatus2x.stopRecordingVoice(liveMeeting.status)
log.info("Send STOP RECORDING voice conf. meetingId=" + props.meetingProp.intId + " voice conf=" + props.voiceProp.voiceConf)
outGW.send(new StopRecordingVoiceConf(props.meetingProp.intId, props.recordProp.record,
props.voiceProp.voiceConf, MeetingStatus2x.getVoiceRecordingFilename(liveMeeting.status)))
}
}
def handleUserLeftVoiceConfMessage(msg: UserLeftVoiceConfMessage) {
log.info("Received user left voice conf. meetingId=" + props.meetingProp.intId + " voice conf=" + msg.voiceConfId
+ " userId=" + msg.voiceUserId)
for {
user <- Users1x.getUserWithVoiceUserId(msg.voiceUserId, liveMeeting.users)
nu = Users1x.resetVoiceUser(user, liveMeeting.users)
} yield {
log.info("User left voice conf. meetingId=" + props.meetingProp.intId + " userId=" + nu.id + " user=" + nu)
outGW.send(new UserLeftVoice(props.meetingProp.intId, props.recordProp.record, props.voiceProp.voiceConf, nu))
if (user.phoneUser) {
for {
userLeaving <- Users1x.userLeft(user.id, liveMeeting.users)
} yield {
outGW.send(new UserLeft(props.meetingProp.intId, props.recordProp.record, userLeaving))
}
}
}
stopRecordingVoiceConference()
}
def handleAssignPresenter(msg: AssignPresenter): Unit = {
assignNewPresenter(msg.newPresenterID, msg.newPresenterName, msg.assignedBy)
}
def assignNewPresenter(newPresenterID: String, newPresenterName: String, assignedBy: String) {
// Stop poll if one is running as presenter left.
handleStopPollRequest(StopPollRequest(props.meetingProp.intId, assignedBy))
def removePresenterRightsToCurrentPresenter(): Unit = {
for {
curPres <- Users1x.getCurrentPresenter(liveMeeting.users)
} yield {
Users1x.unbecomePresenter(curPres.id, liveMeeting.users)
outGW.send(new UserStatusChange(props.meetingProp.intId, props.recordProp.record, curPres.id, "presenter", false: java.lang.Boolean))
}
}
for {
newPres <- Users1x.findWithId(newPresenterID, liveMeeting.users)
} yield {
removePresenterRightsToCurrentPresenter()
Users1x.becomePresenter(newPres.id, liveMeeting.users)
MeetingStatus2x.setCurrentPresenterInfo(liveMeeting.status, new Presenter(newPresenterID, newPresenterName, assignedBy))
outGW.send(new PresenterAssigned(props.meetingProp.intId, props.recordProp.record, new Presenter(newPresenterID, newPresenterName, assignedBy)))
outGW.send(new UserStatusChange(props.meetingProp.intId, props.recordProp.record, newPresenterID, "presenter", true: java.lang.Boolean))
}
}
def handleRespondToGuest(msg: RespondToGuest) {
if (Users1x.isModerator(msg.requesterID, liveMeeting.users)) {
var usersToAnswer: Array[UserVO] = null;
if (msg.userId == null) {
usersToAnswer = Users1x.getUsers(liveMeeting.users).filter(u => u.waitingForAcceptance == true).toArray
} else {
usersToAnswer = Users1x.getUsers(liveMeeting.users).filter(u => u.waitingForAcceptance == true && u.id == msg.userId).toArray
}
usersToAnswer foreach { user =>
println("UsersApp - handleGuestAccessDenied for user [" + user.id + "]");
if (msg.response == true) {
val nu = Users1x.setWaitingForAcceptance(user, liveMeeting.users, false)
RegisteredUsers.updateRegUser(nu, liveMeeting.registeredUsers)
outGW.send(new UserJoined(props.meetingProp.intId, props.recordProp.record, nu))
} else {
outGW.send(new GuestAccessDenied(props.meetingProp.intId, props.recordProp.record, user.id))
}
}
}
}
}

View File

@ -1,17 +1,96 @@
package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.core.running.MeetingActor
import java.net.URLEncoder
import scala.collection.SortedSet
import scala.collection.mutable
import org.apache.commons.codec.digest.DigestUtils
trait BreakoutApp2x extends BreakoutRoomCreatedMsgHdlr
with BreakoutRoomEndedMsgHdlr
with BreakoutRoomsListMsgHdlr
with BreakoutRoomUsersUpdateMsgHdlr
with CreateBreakoutRoomsMsgHdlr
with CreateBreakoutRoomsCmdMsgHdlr
with EndAllBreakoutRoomsMsgHdlr
with RequestBreakoutJoinURLMsgHdlr
with RequestBreakoutJoinURLReqMsgHdlr
with SendBreakoutUsersUpdateMsgHdlr
with TransferUserToMeetingRequestHdlr {
this: MeetingActor =>
}
object BreakoutRoomsUtil {
def createMeetingIds(id: String, index: Int): (String, String) = {
val timeStamp = System.currentTimeMillis()
val externalHash = DigestUtils.sha1Hex(id.concat("-").concat(timeStamp.toString()).concat("-").concat(index.toString()))
val externalId = externalHash.concat("-").concat(timeStamp.toString())
val internalId = DigestUtils.sha1Hex(externalId).concat("-").concat(timeStamp.toString())
(internalId, externalId)
}
def createVoiceConfId(id: String, index: Int): String = {
id.concat(index.toString())
}
def createJoinURL(webAPI: String, apiCall: String, baseString: String, checksum: String): String = {
val apiURL = if (webAPI.endsWith("/")) webAPI else webAPI.concat("/")
apiURL.concat(apiCall).concat("?").concat(baseString).concat("&checksum=").concat(checksum)
}
//
//checksum() -- Return a checksum based on SHA-1 digest
//
def checksum(s: String): String = {
DigestUtils.sha1Hex(s);
}
def calculateChecksum(apiCall: String, baseString: String, sharedSecret: String): String = {
checksum(apiCall.concat(baseString).concat(sharedSecret))
}
def joinParams(username: String, userId: String, isBreakout: Boolean, breakoutMeetingId: String,
password: String): (mutable.Map[String, String], mutable.Map[String, String]) = {
val params = collection.mutable.HashMap(
"fullName" -> urlEncode(username),
"userID" -> urlEncode(userId),
"isBreakout" -> urlEncode(isBreakout.toString()),
"meetingID" -> urlEncode(breakoutMeetingId),
"password" -> urlEncode(password))
(params += "redirect" -> urlEncode("true"), mutable.Map[String, String]() ++= params += "redirect" -> urlEncode("false"))
}
def sortParams(params: mutable.Map[String, String]): SortedSet[String] = {
collection.immutable.SortedSet[String]() ++ params.keySet
}
//From the list of parameters we want to pass. Creates a base string with parameters
//sorted in alphabetical order for us to sign.
def createBaseString(params: mutable.Map[String, String]): String = {
val csbuf = new StringBuffer()
val keys = sortParams(params)
var first = true;
for (key <- keys) {
for (value <- params.get(key)) {
if (first) {
first = false;
} else {
csbuf.append("&");
}
csbuf.append(key);
csbuf.append("=");
csbuf.append(value);
}
}
return csbuf.toString();
}
def urlEncode(s: String): String = {
URLEncoder.encode(s, "UTF-8");
}
}

View File

@ -1,13 +1,15 @@
package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.SystemConfiguration
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.BreakoutRooms
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core.models.{ BreakoutRooms, Users2x }
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, MeetingActor }
trait BreakoutRoomCreatedMsgHdlr {
this: MeetingActor =>
trait BreakoutRoomCreatedMsgHdlr extends SystemConfiguration {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleBreakoutRoomCreatedMsg(msg: BreakoutRoomCreatedMsg): Unit = {
@ -20,18 +22,95 @@ trait BreakoutRoomCreatedMsgHdlr {
// We postpone sending invitation until all breakout rooms have been created
if (liveMeeting.breakoutRooms.pendingRoomsNumber == 0) {
log.info("All breakout rooms created for meetingId={}", props.meetingProp.intId)
log.info("All breakout rooms created for meetingId={}", liveMeeting.props.meetingProp.intId)
BreakoutRooms.getRooms(liveMeeting.breakoutRooms).foreach { room =>
BreakoutRooms.getAssignedUsers(liveMeeting.breakoutRooms, room.id) foreach { users =>
users.foreach { u =>
log.debug("Sending Join URL for users");
log.debug("Sending Join URL for users")
sendJoinURL(u, room.externalMeetingId, room.sequence.toString())
}
}
}
handleBreakoutRoomsListMsg(new BreakoutRoomsListMsg(new BbbClientMsgHeader(BreakoutRoomsListMsg.NAME,
msg.header.meetingId, msg.header.userId), new BreakoutRoomsListMsgBody(props.meetingProp.intId)))
sendBreakoutRoomsList()
}
}
def buildBreakoutRoomsListEvtMsg(meetingId: String, rooms: Vector[BreakoutRoomInfo], roomsReady: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(BreakoutRoomsListEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(BreakoutRoomsListEvtMsg.NAME, meetingId, "not-used")
val body = BreakoutRoomsListEvtMsgBody(meetingId, rooms, roomsReady)
val event = BreakoutRoomsListEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def sendBreakoutRoomsList(): Unit = {
val breakoutRooms = BreakoutRooms.getRooms(liveMeeting.breakoutRooms).toVector map { r =>
new BreakoutRoomInfo(r.name, r.externalMeetingId, r.id, r.sequence)
}
val roomsReady = liveMeeting.breakoutRooms.pendingRoomsNumber == 0 && breakoutRooms.length > 0
log.info("Sending breakout rooms list to {} with containing {} room(s)", liveMeeting.props.meetingProp.intId, breakoutRooms.length)
val msgEvent = buildBreakoutRoomsListEvtMsg(liveMeeting.props.meetingProp.intId, breakoutRooms, roomsReady)
outGW.send(msgEvent)
}
def sendBreakoutRoomStarted(meetingId: String, breakoutName: String, externalMeetingId: String,
breakoutMeetingId: String, sequence: Int, voiceConfId: String) {
log.info("Sending breakout room started {} for parent meeting {} ", breakoutMeetingId, meetingId)
def build(meetingId: String, breakout: BreakoutRoomInfo): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, "not-used")
val envelope = BbbCoreEnvelope(BreakoutRoomStartedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(BreakoutRoomStartedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, "not-used")
val body = BreakoutRoomStartedEvtMsgBody(meetingId, breakout)
val event = BreakoutRoomStartedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val breakoutInfo = BreakoutRoomInfo(breakoutName, externalMeetingId, meetingId, sequence)
val event = build(meetingId, breakoutInfo)
outGW.send(event)
}
def sendJoinURL(userId: String, externalMeetingId: String, roomSequence: String) {
log.debug("Sending breakout meeting {} Join URL for user: {}", externalMeetingId, userId)
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, userId)
apiCall = "join"
params = BreakoutRoomsUtil.joinParams(user.name, userId + "-" + roomSequence, true,
externalMeetingId, liveMeeting.props.password.moderatorPass)
// We generate a first url with redirect -> true
redirectBaseString = BreakoutRoomsUtil.createBaseString(params._1)
redirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, redirectBaseString,
BreakoutRoomsUtil.calculateChecksum(apiCall, redirectBaseString, bbbWebSharedSecret))
// We generate a second url with redirect -> false
noRedirectBaseString = BreakoutRoomsUtil.createBaseString(params._2)
noRedirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, noRedirectBaseString,
BreakoutRoomsUtil.calculateChecksum(apiCall, noRedirectBaseString, bbbWebSharedSecret))
} yield {
def build(meetingId: String, breakoutMeetingId: String,
userId: String, redirectJoinURL: String, noRedirectJoinURL: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(BreakoutRoomJoinURLEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(BreakoutRoomJoinURLEvtMsg.NAME, meetingId, "not-used")
val body = BreakoutRoomJoinURLEvtMsgBody(meetingId, breakoutMeetingId,
userId, redirectJoinURL, noRedirectJoinURL)
val event = BreakoutRoomJoinURLEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val msgEvent = build(liveMeeting.props.meetingProp.intId, externalMeetingId, userId,
redirectJoinURL, noRedirectJoinURL)
outGW.send(msgEvent)
}
}
}

View File

@ -19,7 +19,7 @@ trait BreakoutRoomUsersUpdateMsgHdlr {
val envelope = BbbCoreEnvelope(UpdateBreakoutUsersEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UpdateBreakoutUsersEvtMsg.NAME, props.meetingProp.intId, msg.header.userId)
val body = UpdateBreakoutUsersEvtMsgBody(props.meetingProp.intId, props.recordProp.record, msg.body.breakoutMeetingId, room.users)
val body = UpdateBreakoutUsersEvtMsgBody(props.meetingProp.intId, msg.body.breakoutMeetingId, room.users)
val event = UpdateBreakoutUsersEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)

View File

@ -0,0 +1,60 @@
package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.BreakoutRooms
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
trait CreateBreakoutRoomsCmdMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleCreateBreakoutRoomsCmdMsg(msg: CreateBreakoutRoomsCmdMsg): Unit = {
// If breakout rooms are being created we ignore the coming message
if (liveMeeting.breakoutRooms.pendingRoomsNumber > 0) {
log.warning("CreateBreakoutRooms event received while {} are pending to be created for meeting {}",
liveMeeting.breakoutRooms.pendingRoomsNumber, liveMeeting.props.meetingProp.intId)
} else if (BreakoutRooms.getNumberOfRooms(liveMeeting.breakoutRooms) > 0) {
log.warning("CreateBreakoutRooms event received while {} breakout rooms running for meeting {}",
BreakoutRooms.getNumberOfRooms(liveMeeting.breakoutRooms), liveMeeting.props.meetingProp.intId)
} else {
var i = 0
// in very rare cases the presentation conversion generates an error, what should we do?
// those cases where default.pdf is deleted from the whiteboard
val sourcePresentationId = if (!liveMeeting.presModel.getCurrentPresentation().isEmpty) liveMeeting.presModel.getCurrentPresentation().get.id else "blank"
val sourcePresentationSlide = if (!liveMeeting.presModel.getCurrentPage().isEmpty) liveMeeting.presModel.getCurrentPage().get.num else 0
liveMeeting.breakoutRooms.pendingRoomsNumber = msg.body.rooms.length
for (room <- msg.body.rooms) {
i += 1
val breakoutMeetingId = BreakoutRoomsUtil.createMeetingIds(liveMeeting.props.meetingProp.intId, i)
val voiceConfId = BreakoutRoomsUtil.createVoiceConfId(liveMeeting.props.voiceProp.voiceConf, i)
for {
r <- BreakoutRooms.newBreakoutRoom(liveMeeting.props.meetingProp.intId, breakoutMeetingId._1, breakoutMeetingId._2, room.name,
room.sequence, voiceConfId, room.users, liveMeeting.breakoutRooms)
} yield {
val roomDetail = new BreakoutRoomDetail(r.id, r.name, liveMeeting.props.meetingProp.intId, r.sequence,
r.voiceConfId, msg.body.durationInMinutes, liveMeeting.props.password.moderatorPass, liveMeeting.props.password.viewerPass,
sourcePresentationId, sourcePresentationSlide, msg.body.record)
def build(meetingId: String, breakout: BreakoutRoomDetail): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(CreateBreakoutRoomSysCmdMsg.NAME, routing)
val header = BbbCoreBaseHeader(CreateBreakoutRoomSysCmdMsg.NAME)
val body = CreateBreakoutRoomSysCmdMsgBody(meetingId, breakout)
val event = CreateBreakoutRoomSysCmdMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = build(liveMeeting.props.meetingProp.intId, roomDetail)
outGW.send(event)
}
}
}
}
}

View File

@ -1,51 +0,0 @@
package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ BreakoutRoomOutPayload, CreateBreakoutRoom }
import org.bigbluebutton.core.apps.BreakoutRoomsUtil
import org.bigbluebutton.core.models.BreakoutRooms
import org.bigbluebutton.core.running.MeetingActor
trait CreateBreakoutRoomsMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleCreateBreakoutRoomsMsg(msg: CreateBreakoutRoomsMsg): Unit = {
// If breakout rooms are being created we ignore the coming message
if (liveMeeting.breakoutRooms.pendingRoomsNumber > 0) {
log.warning("CreateBreakoutRooms event received while {} are pending to be created for meeting {}",
liveMeeting.breakoutRooms.pendingRoomsNumber, props.meetingProp.intId)
return
}
if (BreakoutRooms.getNumberOfRooms(liveMeeting.breakoutRooms) > 0) {
log.warning("CreateBreakoutRooms event received while {} breakout rooms running for meeting {}",
BreakoutRooms.getNumberOfRooms(liveMeeting.breakoutRooms), props.meetingProp.intId)
return
}
var i = 0
// in very rare cases the presentation conversion generates an error, what should we do?
// those cases where default.pdf is deleted from the whiteboard
val sourcePresentationId = if (!liveMeeting.presModel.getCurrentPresentation().isEmpty) liveMeeting.presModel.getCurrentPresentation().get.id else "blank"
val sourcePresentationSlide = if (!liveMeeting.presModel.getCurrentPage().isEmpty) liveMeeting.presModel.getCurrentPage().get.num else 0
liveMeeting.breakoutRooms.pendingRoomsNumber = msg.body.rooms.length;
for (room <- msg.body.rooms) {
i += 1
val breakoutMeetingId = BreakoutRoomsUtil.createMeetingIds(props.meetingProp.intId, i)
val voiceConfId = BreakoutRoomsUtil.createVoiceConfId(props.voiceProp.voiceConf, i)
for {
r <- BreakoutRooms.newBreakoutRoom(props.meetingProp.intId, breakoutMeetingId._1, breakoutMeetingId._2, room.name,
room.sequence, voiceConfId, room.users, liveMeeting.breakoutRooms)
} yield {
val p = new BreakoutRoomOutPayload(r.id, r.name, props.meetingProp.intId, r.sequence,
r.voiceConfId, msg.body.durationInMinutes, props.password.moderatorPass, props.password.viewerPass,
sourcePresentationId, sourcePresentationSlide, msg.body.record)
outGW.send(new CreateBreakoutRoom(props.meetingProp.intId, p))
}
}
}
}

View File

@ -2,18 +2,17 @@ package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.apps.BreakoutRoomsUtil
import org.bigbluebutton.core.models.{ BreakoutRooms, Users1x }
import org.bigbluebutton.core.models.{ BreakoutRooms, Users2x }
import org.bigbluebutton.core.running.MeetingActor
trait RequestBreakoutJoinURLMsgHdlr {
trait RequestBreakoutJoinURLReqMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleRequestBreakoutJoinURLMsg(msg: RequestBreakoutJoinURLMsg): Unit = {
def handleRequestBreakoutJoinURLReqMsg(msg: RequestBreakoutJoinURLReqMsg): Unit = {
def broadcastEvent(msg: RequestBreakoutJoinURLMsg): Unit = {
def broadcastEvent(msg: RequestBreakoutJoinURLReqMsg): Unit = {
for {
breakoutRoom <- BreakoutRooms.getRoomWithExternalId(liveMeeting.breakoutRooms, msg.body.breakoutMeetingId)
} yield sendJoinURL(msg.body.userId, msg.body.breakoutMeetingId, breakoutRoom.sequence.toString())
@ -22,7 +21,7 @@ trait RequestBreakoutJoinURLMsgHdlr {
def sendJoinURL(userId: String, externalMeetingId: String, roomSequence: String) {
log.debug("Sending breakout meeting {} Join URL for user: {}", externalMeetingId, userId)
for {
user <- Users1x.findWithId(userId, liveMeeting.users)
user <- Users2x.findWithIntId(liveMeeting.users2x, userId)
apiCall = "join"
params = BreakoutRoomsUtil.joinParams(user.name, userId + "-" + roomSequence, true,
externalMeetingId, props.password.moderatorPass)
@ -35,13 +34,13 @@ trait RequestBreakoutJoinURLMsgHdlr {
noRedirectJoinURL = BreakoutRoomsUtil.createJoinURL(bbbWebAPI, apiCall, noRedirectBaseString,
BreakoutRoomsUtil.calculateChecksum(apiCall, noRedirectBaseString, bbbWebSharedSecret))
} yield {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(BreakoutRoomJoinURLEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(BreakoutRoomJoinURLEvtMsg.NAME, props.meetingProp.intId, msg.header.userId)
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(RequestBreakoutJoinURLRespMsg.NAME, routing)
val header = BbbClientMsgHeader(RequestBreakoutJoinURLRespMsg.NAME, props.meetingProp.intId, msg.header.userId)
val body = BreakoutRoomJoinURLEvtMsgBody(props.meetingProp.intId,
props.recordProp.record, externalMeetingId, userId, redirectJoinURL, noRedirectJoinURL)
val event = BreakoutRoomJoinURLEvtMsg(header, body)
val body = RequestBreakoutJoinURLRespMsgBody(props.meetingProp.intId,
externalMeetingId, userId, redirectJoinURL, noRedirectJoinURL)
val event = RequestBreakoutJoinURLRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)

View File

@ -4,7 +4,7 @@ import org.bigbluebutton.common2.msgs.{ BreakoutUserVO, SendBreakoutUsersUpdateM
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.BreakoutRoomUsersUpdate
import org.bigbluebutton.core.bus.BigBlueButtonEvent
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.models.{ Users2x }
import org.bigbluebutton.core.running.MeetingActor
trait SendBreakoutUsersUpdateMsgHdlr {
@ -14,8 +14,8 @@ trait SendBreakoutUsersUpdateMsgHdlr {
def handleSendBreakoutUsersUpdateMsg(msg: SendBreakoutUsersUpdateMsg): Unit = {
val users = Users1x.getUsers(liveMeeting.users)
val breakoutUsers = users map { u => new BreakoutUserVO(u.externalId, u.name) }
val users = Users2x.findAll(liveMeeting.users2x)
val breakoutUsers = users map { u => new BreakoutUserVO(u.extId, u.name) }
eventBus.publish(BigBlueButtonEvent(props.breakoutProps.parentId,
new BreakoutRoomUsersUpdate(props.breakoutProps.parentId, props.meetingProp.intId, breakoutUsers)))
}

View File

@ -2,7 +2,7 @@ package org.bigbluebutton.core.apps.breakout
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.{ BreakoutRooms, Users1x }
import org.bigbluebutton.core.models.{ BreakoutRooms, Users2x, VoiceUser2x, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
trait TransferUserToMeetingRequestHdlr {
@ -27,22 +27,20 @@ trait TransferUserToMeetingRequestHdlr {
targetVoiceBridge = props.voiceProp.voiceConf.dropRight(1)
}
// We check the user from the mode
Users1x.findWithId(msg.body.userId, liveMeeting.users) match {
case Some(u) => {
if (u.voiceUser.joined) {
log.info("Transferring user userId=" + u.id + " from voiceBridge=" + props.voiceProp.voiceConf + " to targetVoiceConf=" + targetVoiceBridge)
VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId) match {
case Some(u) =>
log.info("Transferring user userId=" + u.intId + " from voiceBridge=" + props.voiceProp.voiceConf + " to targetVoiceConf=" + targetVoiceBridge)
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(TransferUserToMeetingEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(TransferUserToMeetingEvtMsg.NAME, props.meetingProp.intId, msg.header.userId)
val body = TransferUserToMeetingEvtMsgBody(props.voiceProp.voiceConf, targetVoiceBridge, u.voiceUser.userId)
val body = TransferUserToMeetingEvtMsgBody(props.voiceProp.voiceConf, targetVoiceBridge, u.voiceUserId)
val event = TransferUserToMeetingEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
}
case None => // do nothing
}
}

View File

@ -0,0 +1,18 @@
package org.bigbluebutton.core.apps.chat
import akka.actor.ActorContext
import akka.event.Logging
import org.bigbluebutton.common2.msgs.TranscriptVO
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.LiveMeeting
class ChatApp2x(val liveMeeting: LiveMeeting,
val outGW: OutMessageGateway)(implicit val context: ActorContext)
extends GetChatHistoryReqMsgHdlr
with SendPublicMessagePubMsgHdlr
with SendPrivateMessagePubMsgHdlr
with ClearPublicChatHistoryPubMsgHdlr {
val log = Logging(context.system, getClass)
}

View File

@ -0,0 +1,30 @@
package org.bigbluebutton.core.apps.chat
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.ChatModel
trait ClearPublicChatHistoryPubMsgHdlr {
this: ChatApp2x =>
val outGW: OutMessageGateway
def handleClearPublicChatHistoryPubMsg(msg: ClearPublicChatHistoryPubMsg): Unit = {
def broadcastEvent(msg: ClearPublicChatHistoryPubMsg): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(ClearPublicChatHistoryEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(ClearPublicChatHistoryEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = ClearPublicChatHistoryEvtMsgBody()
val event = ClearPublicChatHistoryEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
//record(event)
}
ChatModel.clearPublicChatHistory(liveMeeting.chatModel)
broadcastEvent(msg)
}
}

View File

@ -0,0 +1,27 @@
package org.bigbluebutton.core.apps.chat
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.ChatModel
trait GetChatHistoryReqMsgHdlr {
this: ChatApp2x =>
val outGW: OutMessageGateway
def handleGetChatHistoryReqMsg(msg: GetChatHistoryReqMsg): Unit = {
def broadcastEvent(msg: GetChatHistoryReqMsg, history: Array[ChatMessageVO]): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(GetChatHistoryRespMsg.NAME, routing)
val header = BbbClientMsgHeader(GetChatHistoryRespMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = GetChatHistoryRespMsgBody(history)
val event = GetChatHistoryRespMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
val history = ChatModel.getChatHistory(liveMeeting.chatModel)
broadcastEvent(msg, history)
}
}

View File

@ -0,0 +1,28 @@
package org.bigbluebutton.core.apps.chat
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.common2.msgs._
trait SendPrivateMessagePubMsgHdlr {
this: ChatApp2x =>
val outGW: OutMessageGateway
def handleSendPrivateMessagePubMsg(msg: SendPrivateMessagePubMsg): Unit = {
def broadcastEvent(message: ChatMessageVO, userId: String): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, userId)
val envelope = BbbCoreEnvelope(SendPrivateMessageEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(SendPrivateMessageEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
val body = SendPrivateMessageEvtMsgBody(message)
val event = SendPrivateMessageEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
//record(event)
}
broadcastEvent(msg.body.message, msg.body.message.fromUserId)
broadcastEvent(msg.body.message, msg.body.message.toUserId)
}
}

View File

@ -0,0 +1,29 @@
package org.bigbluebutton.core.apps.chat
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.ChatModel
trait SendPublicMessagePubMsgHdlr {
this: ChatApp2x =>
val outGW: OutMessageGateway
def handleSendPublicMessagePubMsg(msg: SendPublicMessagePubMsg): Unit = {
def broadcastEvent(msg: SendPublicMessagePubMsg, message: ChatMessageVO): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
val envelope = BbbCoreEnvelope(SendPublicMessageEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(SendPublicMessageEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
val body = SendPublicMessageEvtMsgBody(msg.body.message)
val event = SendPublicMessageEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
//record(event)
}
ChatModel.addNewChatMessage(liveMeeting.chatModel, msg.body.message)
broadcastEvent(msg, msg.body.message)
}
}

View File

@ -6,8 +6,7 @@ import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.LiveMeeting
class DeskshareApp2x(val liveMeeting: LiveMeeting,
val outGW: OutMessageGateway)(implicit val context: ActorContext)
extends EjectUserFromMeetingHdlr {
val outGW: OutMessageGateway)(implicit val context: ActorContext) {
val log = Logging(context.system, getClass)

View File

@ -1,28 +0,0 @@
package org.bigbluebutton.core.apps.deskshare
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.models.{ UserState, Users2x }
import org.bigbluebutton.core2.MeetingStatus2x
trait EjectUserFromMeetingHdlr {
this: DeskshareApp2x =>
def handle(msg: EjectUserFromMeeting, userToEject: UserState) {
if (userToEject.presenter) {
if (MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status)) {
// The presenter left during desktop sharing. Stop desktop sharing on FreeSWITCH
outGW.send(new DeskShareHangUp(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf))
// notify other clients to close their deskshare view
outGW.send(new DeskShareNotifyViewersRTMP(liveMeeting.props.meetingProp.intId,
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status),
MeetingStatus2x.getDesktopShareVideoWidth(liveMeeting.status),
MeetingStatus2x.getDesktopShareVideoHeight(liveMeeting.status), false))
// reset meeting info
MeetingStatus2x.resetDesktopSharingParams(liveMeeting.status)
}
}
}
}

View File

@ -12,7 +12,7 @@ trait GetCurrentLayoutReqMsgHdlr {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: GetCurrentLayoutReqMsg): Unit = {
def handleGetCurrentLayoutReqMsg(msg: GetCurrentLayoutReqMsg): Unit = {
def broadcastEvent(msg: GetCurrentLayoutReqMsg): Unit = {

View File

@ -1,34 +0,0 @@
package org.bigbluebutton.core.apps.presentation
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.models.{ UserState, Users2x }
trait EjectUserFromMeetingHdlr {
this: PresentationApp2x =>
def handle(msg: EjectUserFromMeeting, userToEject: UserState) {
if (userToEject.presenter) {
/* The current presenter has left the meeting. Find a moderator and make
* him presenter. This way, if there is a moderator in the meeting, there
* will always be a presenter.
*/
for {
moderator <- Users2x.findModerator(liveMeeting.users2x)
newPresenter <- Users2x.makePresenter(liveMeeting.users2x, moderator.intId)
} yield {
sendPresenterAssigned(newPresenter.intId, newPresenter.name, newPresenter.name)
sendUserStatusChange(newPresenter.intId)
}
}
}
def sendPresenterAssigned(intId: String, name: String, assignedBy: String): Unit = {
outGW.send(new PresenterAssigned(liveMeeting.props.meetingProp.intId, liveMeeting.props.recordProp.record,
new Presenter(intId, name, assignedBy)))
}
def sendUserStatusChange(intId: String): Unit = {
outGW.send(new UserStatusChange(liveMeeting.props.meetingProp.intId, liveMeeting.props.recordProp.record,
intId, "presenter", true: java.lang.Boolean))
}
}

View File

@ -10,8 +10,7 @@ import org.bigbluebutton.core.apps.Presentation
class PresentationApp2x(val liveMeeting: LiveMeeting,
val outGW: OutMessageGateway)(implicit val context: ActorContext)
extends EjectUserFromMeetingHdlr
with NewPresentationMsgHdlr
extends NewPresentationMsgHdlr
with SetCurrentPresentationPubMsgHdlr
with GetPresentationInfoReqMsgHdlr
with SetCurrentPagePubMsgHdlr

View File

@ -38,7 +38,7 @@ trait AssignPresenterReqMsgHdlr {
oldPres <- Users2x.findPresenter(this.liveMeeting.users2x)
newPres <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.newPresenterId)
} yield {
Users2x.unmakePresenter(this.liveMeeting.users2x, oldPres.intId)
Users2x.makeNotPresenter(this.liveMeeting.users2x, oldPres.intId)
Users2x.makePresenter(this.liveMeeting.users2x, newPres.intId)
broadcastPresenterChange(oldPres, newPres)
}

View File

@ -0,0 +1,30 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models.{ Roles, Users2x }
trait ChangeUserRoleCmdMsgHdlr {
this: UsersApp2x =>
def handleChangeUserRoleCmdMsg(msg: ChangeUserRoleCmdMsg) {
for {
uvo <- Users2x.changeRole(liveMeeting.users2x, msg.body.userId, msg.body.role)
} yield {
val userRole = if (uvo.role == Roles.MODERATOR_ROLE) "MODERATOR" else "VIEWER"
val event = buildUserRoleChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.userId,
msg.body.changedBy, userRole)
outGW.send(event)
}
}
def buildUserRoleChangedEvtMsg(meetingId: String, userId: String, changedBy: String, role: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(UserRoleChangedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserRoleChangedEvtMsg.NAME, meetingId, changedBy)
val body = UserRoleChangedEvtMsgBody(userId, role, changedBy)
val event = UserRoleChangedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
}

View File

@ -1,18 +0,0 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.core.api.{ ChangeUserRole, UserRoleChange }
import org.bigbluebutton.core.models.{ Roles, Users2x }
trait ChangeUserRoleHdlr {
this: UsersApp2x =>
def handle(msg: ChangeUserRole) {
for {
uvo <- Users2x.changeRole(liveMeeting.users2x, msg.userID, msg.role)
} yield {
val userRole = if (msg.role == Roles.MODERATOR_ROLE) "MODERATOR" else "VIEWER"
outGW.send(new UserRoleChange(liveMeeting.props.meetingProp.intId,
liveMeeting.props.recordProp.record, msg.userID, userRole))
}
}
}

View File

@ -1,36 +1,26 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.core.MessageRecorder
import org.bigbluebutton.core.api._
import org.bigbluebutton.common2.msgs.EjectUserFromMeetingCmdMsg
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models._
import org.bigbluebutton.core.util.Model1x2xConverter
import org.bigbluebutton.core2.message.senders.{ MsgSenders1x, Sender, UserLeftMeetingEvtMsgSender }
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
trait EjectUserFromMeetingHdlr extends MsgSenders1x {
this: UsersApp2x =>
trait EjectUserFromMeetingHdlr {
this: BaseMeetingActor =>
def handle(msg: EjectUserFromMeeting) {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleEjectUserFromMeetingCmdMsg(msg: EjectUserFromMeetingCmdMsg) {
for {
user <- Users2x.ejectFromMeeting(liveMeeting.users2x, msg.userId)
regUser <- RegisteredUsers.remove(msg.userId, liveMeeting.registeredUsers)
vu <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.userId)
user <- Users2x.ejectFromMeeting(liveMeeting.users2x, msg.body.userId)
regUser <- RegisteredUsers.remove(msg.body.userId, liveMeeting.registeredUsers)
vu <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
} yield {
sendEjectVoiceUser(msg.userId, msg.ejectedBy, vu.voiceUserId)
log.info("Ejecting user from meeting. meetingId=" + liveMeeting.props.meetingProp.intId + " userId=" + msg.userId)
log.info("Ejecting user from meeting. meetingId=" + liveMeeting.props.meetingProp.intId + " userId=" + msg.body.userId)
sendUserEjectedFromMeeting(msg.userId, msg.ejectedBy)
sendDisconnectUser(msg.userId)
val voiceUser = Model1x2xConverter.toVoiceUser(vu)
val userVO = Model1x2xConverter.toUserVO(user, voiceUser, Vector.empty)
sendUserLeft(userVO)
val event = UserLeftMeetingEvtMsgSender.build(liveMeeting.props.meetingProp.intId, user)
Sender.send(outGW, event)
MessageRecorder.record(outGW, liveMeeting.props.recordProp.record, event.core)
}
}
}

View File

@ -0,0 +1,30 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait GetRecordingStatusReqMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleGetRecordingStatusReqMsg(msg: GetRecordingStatusReqMsg) {
def buildGetRecordingStatusRespMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId)
val envelope = BbbCoreEnvelope(GetRecordingStatusRespMsg.NAME, routing)
val body = GetRecordingStatusRespMsgBody(recording, userId)
val header = BbbClientMsgHeader(GetRecordingStatusRespMsg.NAME, meetingId, userId)
val event = GetRecordingStatusRespMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildGetRecordingStatusRespMsg(liveMeeting.props.meetingProp.intId, msg.body.requestedBy,
MeetingStatus2x.isRecording(liveMeeting.status))
outGW.send(event)
}
}

View File

@ -0,0 +1,57 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ EndMeeting, LogoutEndMeeting }
import org.bigbluebutton.core.models.{ Roles, Users2x }
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait LogoutAndEndMeetingCmdMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleLogoutAndEndMeetingCmdMsg(msg: LogoutAndEndMeetingCmdMsg) {
for {
u <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
} yield {
if (u.role == Roles.MODERATOR_ROLE) {
endMeeting()
}
}
def endMeeting(): 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 header = BbbClientMsgHeader(MeetingEndingEvtMsg.NAME, meetingId, "not-used")
val event = MeetingEndingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val endingEvent = buildMeetingEndingEvtMsg(liveMeeting.props.meetingProp.intId)
// Broadcast users the meeting will end
outGW.send(endingEvent)
MeetingStatus2x.meetingHasEnded(liveMeeting.status)
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)
}
val endedEvnt = buildMeetingEndedEvtMsg(liveMeeting.props.meetingProp.intId)
outGW.send(endedEvnt)
}
}
}

View File

@ -0,0 +1,28 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
trait MeetingActivityResponseCmdMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleMeetingActivityResponseCmdMsg(msg: MeetingActivityResponseCmdMsg) {
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)
}
log.info("User endorsed that meeting {} is active", liveMeeting.props.meetingProp.intId)
val event = buildMeetingIsActiveEvtMsg(liveMeeting.props.meetingProp.intId)
outGW.send(event)
}
}

View File

@ -0,0 +1,42 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.RegisteredUsers
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait RegisterUserReqMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleRegisterUserReqMsg(msg: RegisterUserReqMsg): Unit = {
log.debug("****** RECEIVED RegisterUserReqMsg msg {}", msg)
if (MeetingStatus2x.hasMeetingEnded(liveMeeting.status)) {
// Check first if the meeting has ended and the user refreshed the client to re-connect.
log.info("Register user failed. Mmeeting has ended. meetingId=" + liveMeeting.props.meetingProp.intId +
" userId=" + msg.body.intUserId)
} else {
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
msg.body.name, msg.body.role, msg.body.authToken,
msg.body.avatarURL, msg.body.guest, msg.body.authed, msg.body.guest, liveMeeting.registeredUsers)
log.info("Register user success. meetingId=" + liveMeeting.props.meetingProp.intId
+ " userId=" + msg.body.extUserId + " user=" + regUser)
val event = buildUserRegisteredRespMsg(liveMeeting.props.meetingProp.intId, regUser.id, regUser.name, regUser.role)
outGW.send(event)
}
def buildUserRegisteredRespMsg(meetingId: String, userId: String, name: String, role: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(UserRegisteredRespMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(UserRegisteredRespMsg.NAME, meetingId)
val body = UserRegisteredRespMsgBody(meetingId, userId, name, role)
val event = UserRegisteredRespMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
}
}

View File

@ -0,0 +1,38 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait SetRecordingStatusCmdMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleSetRecordingStatusCmdMsg(msg: SetRecordingStatusCmdMsg) {
log.info("Change recording status. meetingId=" + liveMeeting.props.meetingProp.intId + " recording=" + msg.body.recording)
if (liveMeeting.props.recordProp.allowStartStopRecording &&
MeetingStatus2x.isRecording(liveMeeting.status) != msg.body.recording) {
if (msg.body.recording) {
MeetingStatus2x.recordingStarted(liveMeeting.status)
} else {
MeetingStatus2x.recordingStopped(liveMeeting.status)
}
val event = buildRecordingStatusChangedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.setBy, msg.body.recording)
outGW.send(event)
}
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
val event = RecordingStatusChangedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
}
}

View File

@ -3,10 +3,12 @@ package org.bigbluebutton.core.apps.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
trait SyncGetUsersMeetingRespMsgHdlr {
this: UsersApp2x =>
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleSyncGetUsersMeetingRespMsg(): Unit = {

View File

@ -1,16 +1,16 @@
package org.bigbluebutton.core2.message.handlers.users
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.MeetingActor
trait UserLeavingHdlr {
trait UserLeaveReqMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handle(msg: UserLeaveReqMsg): Unit = {
def handleUserLeaveReqMsg(msg: UserLeaveReqMsg): Unit = {
for {
u <- Users2x.remove(liveMeeting.users2x, msg.body.userId)
} yield {

View File

@ -1,17 +1,21 @@
package org.bigbluebutton.core.apps.users
import akka.actor.ActorContext
import akka.event.Logging
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.message.handlers.users.ValidateAuthTokenReqMsgHdlr
class UsersApp2x(val liveMeeting: LiveMeeting,
val outGW: OutMessageGateway)(implicit val context: ActorContext)
extends ChangeUserRoleHdlr
trait UsersApp2x
extends RegisterUserReqMsgHdlr
with ChangeUserRoleCmdMsgHdlr
with SyncGetUsersMeetingRespMsgHdlr
with ValidateAuthTokenReqMsgHdlr
with UserLeaveReqMsgHdlr
with LogoutAndEndMeetingCmdMsgHdlr
with MeetingActivityResponseCmdMsgHdlr
with SetRecordingStatusCmdMsgHdlr
with GetRecordingStatusReqMsgHdlr
with AssignPresenterReqMsgHdlr
with EjectUserFromMeetingHdlr {
val log = Logging(context.system, getClass)
this: MeetingActor =>
}

View File

@ -2,21 +2,26 @@ package org.bigbluebutton.core.apps.voice
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.StartRecordingVoiceConf
import org.bigbluebutton.core.models.{ VoiceUser2x, VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, MeetingActor }
import org.bigbluebutton.core2.MeetingStatus2x
trait UserJoinedVoiceConfEvtMsgHdlr {
this: MeetingActor =>
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleUserJoinedVoiceConfEvtMsg(msg: UserJoinedVoiceConfEvtMsg): Unit = {
log.warning("Received user joined voice conference " + msg)
def broadcastEvent(voiceUserState: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, voiceUserState.intId)
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, voiceUserState.intId)
val envelope = BbbCoreEnvelope(UserJoinedVoiceConfToClientEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserJoinedVoiceConfToClientEvtMsg.NAME, props.meetingProp.intId, voiceUserState.intId)
val header = BbbClientMsgHeader(UserJoinedVoiceConfToClientEvtMsg.NAME,
liveMeeting.props.meetingProp.intId, voiceUserState.intId)
val body = UserJoinedVoiceConfToClientEvtMsgBody(intId = voiceUserState.intId, voiceUserId = voiceUserState.voiceUserId,
callerName = voiceUserState.callerName, callerNum = voiceUserState.callerNum, muted = voiceUserState.muted,
@ -26,7 +31,6 @@ trait UserJoinedVoiceConfEvtMsgHdlr {
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
record(event)
}
val voiceUser = VoiceUser2x(msg.body.intId, msg.body.voiceUserId)
@ -37,5 +41,29 @@ trait UserJoinedVoiceConfEvtMsgHdlr {
VoiceUsers.add(liveMeeting.voiceUsers, voiceUserState)
broadcastEvent(voiceUserState)
startRecordingVoiceConference()
}
def startRecordingVoiceConference() {
if (VoiceUsers.findAll(liveMeeting.voiceUsers) == 1 &&
liveMeeting.props.recordProp.record &&
!MeetingStatus2x.isVoiceRecording(liveMeeting.status)) {
MeetingStatus2x.startRecordingVoice(liveMeeting.status)
log.info("Send START RECORDING voice conf. meetingId=" + liveMeeting.props.meetingProp.intId
+ " voice conf=" + liveMeeting.props.voiceProp.voiceConf)
val event = buildStartRecordingVoiceConfSysMsg(liveMeeting.props.meetingProp.intId, liveMeeting.props.voiceProp.voiceConf)
outGW.send(event)
}
}
def buildStartRecordingVoiceConfSysMsg(meetingId: String, voiceConf: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(StartRecordingVoiceConfSysMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(StartRecordingVoiceConfSysMsg.NAME, meetingId)
val body = StartRecordingVoiceConfSysMsgBody(voiceConf, meetingId)
val event = StartRecordingVoiceConfSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
}

View File

@ -3,29 +3,29 @@ package org.bigbluebutton.core.apps.voice
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, MeetingActor }
import org.bigbluebutton.core2.MeetingStatus2x
trait UserLeftVoiceConfEvtMsgHdlr {
this: MeetingActor =>
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: UserLeftVoiceConfEvtMsg): Unit = {
def handleUserLeftVoiceConfEvtMsg(msg: UserLeftVoiceConfEvtMsg): Unit = {
log.debug("Received UserLeftVoiceConfEvtMsg from FS {} ", msg.body.voiceUserId)
def broadcastEvent(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId,
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId,
vu.intId)
val envelope = BbbCoreEnvelope(UserLeftVoiceConfToClientEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserLeftVoiceConfToClientEvtMsg.NAME, props.meetingProp.intId, vu.intId)
val header = BbbClientMsgHeader(UserLeftVoiceConfToClientEvtMsg.NAME, liveMeeting.props.meetingProp.intId, vu.intId)
val body = UserLeftVoiceConfToClientEvtMsgBody(intId = vu.intId, voiceUserId = vu.intId)
val event = UserLeftVoiceConfToClientEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
record(event)
}
for {
@ -34,5 +34,30 @@ trait UserLeftVoiceConfEvtMsgHdlr {
VoiceUsers.removeWithIntId(liveMeeting.voiceUsers, user.intId)
broadcastEvent(user)
}
stopRecordingVoiceConference()
}
def stopRecordingVoiceConference() {
if (VoiceUsers.findAll(liveMeeting.voiceUsers).length == 0 &&
liveMeeting.props.recordProp.record &&
MeetingStatus2x.isVoiceRecording(liveMeeting.status)) {
MeetingStatus2x.stopRecordingVoice(liveMeeting.status)
log.info("Send STOP RECORDING voice conf. meetingId=" + liveMeeting.props.meetingProp.intId
+ " voice conf=" + liveMeeting.props.voiceProp.voiceConf)
val event = buildStopRecordingVoiceConfSysMsg(liveMeeting.props.meetingProp.intId,
liveMeeting.props.voiceProp.voiceConf, MeetingStatus2x.getVoiceRecordingFilename(liveMeeting.status))
outGW.send(event)
}
}
def buildStopRecordingVoiceConfSysMsg(meetingId: String, voiceConf: String, stream: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(StopRecordingVoiceConfSysMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(StopRecordingVoiceConfSysMsg.NAME, meetingId)
val body = StopRecordingVoiceConfSysMsgBody(voiceConf, meetingId, stream)
val event = StopRecordingVoiceConfSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
}

View File

@ -3,28 +3,29 @@ package org.bigbluebutton.core.apps.voice
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, MeetingActor }
trait UserMutedInVoiceConfEvtMsgHdlr {
this: MeetingActor =>
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: UserMutedInVoiceConfEvtMsg): Unit = {
def handleUserMutedInVoiceConfEvtMsg(msg: UserMutedInVoiceConfEvtMsg): Unit = {
def broadcastEvent(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId,
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId,
vu.intId)
val envelope = BbbCoreEnvelope(UserMutedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserMutedEvtMsg.NAME, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(UserMutedToClientEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserMutedToClientEvtMsg.NAME,
liveMeeting.props.meetingProp.intId, vu.intId)
val body = UserMutedEvtMsgBody(intId = vu.intId, voiceUserId = vu.intId, vu.muted)
val body = UserMutedToClientEvtMsgBody(intId = vu.intId, voiceUserId = vu.intId, vu.muted)
val event = UserMutedEvtMsg(header, body)
val event = UserMutedToClientEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
record(event)
}
for {

View File

@ -3,28 +3,29 @@ package org.bigbluebutton.core.apps.voice
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting, MeetingActor }
trait UserTalkingInVoiceConfEvtMsgHdlr {
this: MeetingActor =>
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: UserTalkingInVoiceConfEvtMsg): Unit = {
def handleUserTalkingInVoiceConfEvtMsg(msg: UserTalkingInVoiceConfEvtMsg): Unit = {
def broadcastEvent(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId,
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId,
vu.intId)
val envelope = BbbCoreEnvelope(UserTalkingEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserTalkingEvtMsg.NAME, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(UserTalkingToClientEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(UserTalkingToClientEvtMsg.NAME,
liveMeeting.props.meetingProp.intId, vu.intId)
val body = UserTalkingEvtMsgBody(intId = vu.intId, voiceUserId = vu.intId, vu.talking)
val body = UserTalkingToClientEvtMsgBody(intId = vu.intId, voiceUserId = vu.intId, vu.talking)
val event = UserTalkingEvtMsg(header, body)
val event = UserTalkingToClientEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
record(event)
}
for {

View File

@ -1,12 +1,14 @@
package org.bigbluebutton.core.apps.voice
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.message.handlers.RecordingStartedVoiceConfEvtMsgHdlr
trait VoiceApp2x extends UserJoinedVoiceConfEvtMsgHdlr
with UserJoinedVoiceConfMessageHdlr
with UserLeftVoiceConfEvtMsgHdlr
with UserMutedInVoiceConfEvtMsgHdlr
with UserTalkingInVoiceConfEvtMsgHdlr {
with UserTalkingInVoiceConfEvtMsgHdlr
with RecordingStartedVoiceConfEvtMsgHdlr {
this: MeetingActor =>
}

View File

@ -3,6 +3,11 @@ package org.bigbluebutton.core.models
import org.bigbluebutton.common2.msgs.{ BreakoutRoomVO, BreakoutUserVO }
object BreakoutRooms {
def breakoutRoomsStartedOn(status: BreakoutRooms) = status.breakoutRoomsStartedOn
def breakoutRoomsStartedOn(status: BreakoutRooms, startedOn: Long) = status.breakoutRoomsStartedOn = startedOn
def breakoutRoomsdurationInMinutes(status: BreakoutRooms) = status.breakoutRoomsdurationInMinutes
def breakoutRoomsdurationInMinutes(status: BreakoutRooms, duration: Int) = status.breakoutRoomsdurationInMinutes = duration
def newBreakoutRoom(parentRoomId: String, id: String, externalMeetingId: String, name: String, sequence: Integer, voiceConfId: String,
assignedUsers: Vector[String], breakoutRooms: BreakoutRooms): Option[BreakoutRoomVO] = {
@ -42,11 +47,13 @@ object BreakoutRooms {
}
def removeRoom(breakoutRooms: BreakoutRooms, id: String) {
breakoutRooms.remove(id);
breakoutRooms.remove(id)
}
}
class BreakoutRooms {
private var breakoutRoomsStartedOn: Long = 0
private var breakoutRoomsdurationInMinutes: Int = 0
private var rooms = new collection.immutable.HashMap[String, BreakoutRoomVO]

View File

@ -24,7 +24,7 @@ object Polls {
page <- lm.presModel.getCurrentPage()
pageId: String = if (pollId.contains("deskshare")) "deskshare" else page.id
stampedPollId: String = pageId + "/" + System.currentTimeMillis()
numRespondents: Int = Users1x.numUsers(lm.users) - 1 // subtract the presenter
numRespondents: Int = Users2x.numUsers(lm.users2x) - 1 // subtract the presenter
poll <- createPoll(stampedPollId, numRespondents)
simplePoll <- getSimplePoll(poll.id, lm.polls)
@ -129,7 +129,7 @@ object Polls {
page <- lm.presModel.getCurrentPage()
pageId: String = if (pollId.contains("deskshare")) "deskshare" else page.id
stampedPollId: String = pageId + "/" + System.currentTimeMillis()
numRespondents: Int = Users1x.numUsers(lm.users) - 1 // subtract the presenter
numRespondents: Int = Users2x.numUsers(lm.users2x) - 1 // subtract the presenter
poll <- createPoll(stampedPollId, numRespondents)
simplePoll <- getSimplePoll(stampedPollId, lm.polls)
} yield {

View File

@ -1,261 +0,0 @@
package org.bigbluebutton.core.models
import scala.collection.immutable.ListSet
import org.bigbluebutton.core.util.RandomStringGenerator
import com.softwaremill.quicklens.ModifyPimp
import com.softwaremill.quicklens.modify
import org.bigbluebutton.common2.domain.{ UserVO, VoiceUserVO }
object Users1x {
def newUser(userId: String, lockStatus: Boolean, ru: RegisteredUser, waitingForAcceptance: Boolean,
vu: VoiceUserVO, users: Users1x): Option[UserVO] = {
val uvo = new UserVO(userId, ru.externId, ru.name,
ru.role, ru.guest, ru.authed, waitingForAcceptance = waitingForAcceptance, emojiStatus = "none", presenter = false,
hasStream = false, locked = lockStatus,
webcamStreams = new ListSet[String](), phoneUser = false, vu,
listenOnly = vu.listenOnly, avatarURL = vu.avatarURL, joinedWeb = true)
users.save(uvo)
Some(uvo)
}
def findWithId(id: String, users: Users1x): Option[UserVO] = users.toVector.find(u => u.id == id)
def findWithExtId(id: String, users: Users1x): Option[UserVO] = users.toVector.find(u => u.externalId == id)
def findModerators(users: Users1x): Vector[UserVO] = users.toVector.filter(u => u.role == Roles.MODERATOR_ROLE)
def findPresenters(users: Users1x): Vector[UserVO] = users.toVector.filter(u => u.role == Roles.PRESENTER_ROLE)
def findViewers(users: Users1x): Vector[UserVO] = users.toVector.filter(u => u.role == Roles.VIEWER_ROLE)
def hasModerator(users: Users1x): Boolean = users.toVector.filter(u => u.role == Roles.MODERATOR_ROLE).length > 0
def hasPresenter(users: Users1x): Boolean = users.toVector.filter(u => u.role == Roles.PRESENTER_ROLE).length > 0
def hasNoPresenter(users: Users1x): Boolean = users.toVector.filter(u => u.role == Roles.PRESENTER_ROLE).length == 0
//def hasSessionId(sessionId: String, users: Users): Boolean = {
// users.toVector.find(u => usessionId)
// }
def hasUserWithId(id: String, users: Users1x): Boolean = {
findWithId(id, users) match {
case Some(u) => true
case None => false
}
}
def numUsers(users: Users1x): Int = users.toVector.size
def numWebUsers(users: Users1x): Int = users.toVector filter (u => u.phoneUser == false) size
def numUsersInVoiceConference(users: Users1x): Int = users.toVector filter (u => u.voiceUser.joined) size
def getUserWithExternalId(id: String, users: Users1x): Option[UserVO] = users.toVector find (u => u.externalId == id)
def getUserWithVoiceUserId(voiceUserId: String, users: Users1x): Option[UserVO] = users.toVector find (u => u.voiceUser.userId == voiceUserId)
def getUser(userID: String, users: Users1x): Option[UserVO] = users.toVector find (u => u.id == userID)
def numModerators(users: Users1x): Int = findModerators(users).length
def findAModerator(users: Users1x): Option[UserVO] = users.toVector find (u => u.role == Roles.MODERATOR_ROLE)
def getCurrentPresenter(users: Users1x): Option[UserVO] = users.toVector find (u => u.presenter == true)
def getUsers(users: Users1x): Vector[UserVO] = users.toVector
def userLeft(userId: String, users: Users1x): Option[UserVO] = {
users.remove(userId)
}
def unbecomePresenter(userID: String, users: Users1x) = {
for {
u <- Users1x.findWithId(userID, users)
user = modify(u)(_.presenter).setTo(false)
} yield users.save(user)
}
def becomePresenter(userID: String, users: Users1x) = {
for {
u <- Users1x.findWithId(userID, users)
user = modify(u)(_.presenter).setTo(true)
} yield users.save(user)
}
def isModerator(id: String, users: Users1x): Boolean = {
Users1x.findWithId(id, users) match {
case Some(user) => return user.role == Roles.MODERATOR_ROLE && !user.waitingForAcceptance
case None => return false
}
}
def generateWebUserId(users: Users1x): String = {
val webUserId = RandomStringGenerator.randomAlphanumericString(6)
if (!hasUserWithId(webUserId, users)) webUserId else generateWebUserId(users)
}
def usersWhoAreNotPresenter(users: Users1x): Vector[UserVO] = users.toVector filter (u => u.presenter == false)
def joinedVoiceListenOnly(userId: String, users: Users1x): Option[UserVO] = {
for {
u <- Users1x.findWithId(userId, users)
vu = u.modify(_.voiceUser.joined).setTo(false)
.modify(_.voiceUser.talking).setTo(false)
.modify(_.listenOnly).setTo(true)
} yield {
users.save(vu)
vu
}
}
def leftVoiceListenOnly(userId: String, users: Users1x): Option[UserVO] = {
for {
u <- Users1x.findWithId(userId, users)
vu = u.modify(_.voiceUser.joined).setTo(false)
.modify(_.voiceUser.talking).setTo(false)
.modify(_.listenOnly).setTo(false)
} yield {
users.save(vu)
vu
}
}
def lockUser(userId: String, lock: Boolean, users: Users1x): Option[UserVO] = {
for {
u <- findWithId(userId, users)
uvo = u.modify(_.locked).setTo(lock) // u.copy(locked = msg.lock)
} yield {
users.save(uvo)
uvo
}
}
def changeRole(userId: String, users: Users1x, role: String): Option[UserVO] = {
for {
u <- findWithId(userId, users)
uvo = u.modify(_.role).setTo(role)
} yield {
users.save(uvo)
uvo
}
}
def userSharedWebcam(userId: String, users: Users1x, streamId: String): Option[UserVO] = {
for {
u <- findWithId(userId, users)
streams = u.webcamStreams + streamId
uvo = u.modify(_.hasStream).setTo(true).modify(_.webcamStreams).setTo(streams)
} yield {
users.save(uvo)
uvo
}
}
def userUnsharedWebcam(userId: String, users: Users1x, streamId: String): Option[UserVO] = {
def findWebcamStream(streams: Set[String], stream: String): Option[String] = {
streams find (w => w == stream)
}
for {
u <- findWithId(userId, users)
streamName <- findWebcamStream(u.webcamStreams, streamId)
streams = u.webcamStreams - streamName
uvo = u.modify(_.hasStream).setTo(!streams.isEmpty).modify(_.webcamStreams).setTo(streams)
} yield {
users.save(uvo)
uvo
}
}
def setEmojiStatus(userId: String, users: Users1x, emoji: String): Option[UserVO] = {
for {
u <- findWithId(userId, users)
uvo = u.modify(_.emojiStatus).setTo(emoji)
} yield {
users.save(uvo)
uvo
}
}
def setWaitingForAcceptance(user: UserVO, users: Users1x, waitingForAcceptance: Boolean): UserVO = {
val nu = user.modify(_.waitingForAcceptance).setTo(waitingForAcceptance)
users.save(nu)
nu
}
def setUserTalking(user: UserVO, users: Users1x, talking: Boolean): UserVO = {
val nv = user.modify(_.voiceUser.talking).setTo(talking)
users.save(nv)
nv
}
def setUserMuted(user: UserVO, users: Users1x, muted: Boolean): UserVO = {
val talking: Boolean = if (muted) false else user.voiceUser.talking
val nv = user.modify(_.voiceUser.muted).setTo(muted).modify(_.voiceUser.talking).setTo(talking)
users.save(nv)
nv
}
def resetVoiceUser(user: UserVO, users: Users1x): UserVO = {
val vu = new VoiceUserVO(user.id, user.id, user.name, user.name,
joined = false, locked = false, muted = false, talking = false, user.avatarURL, listenOnly = false)
val nu = user.modify(_.voiceUser).setTo(vu)
.modify(_.phoneUser).setTo(false)
.modify(_.listenOnly).setTo(false)
users.save(nu)
nu
}
def switchUserToPhoneUser(user: UserVO, users: Users1x, voiceUserId: String, userId: String,
callerIdName: String, callerIdNum: String, muted: Boolean, talking: Boolean,
avatarURL: String, listenOnly: Boolean): UserVO = {
val vu = new VoiceUserVO(voiceUserId, userId, callerIdName,
callerIdNum, joined = true, locked = false,
muted, talking, avatarURL, listenOnly)
val nu = user.modify(_.voiceUser).setTo(vu)
.modify(_.listenOnly).setTo(listenOnly)
users.save(nu)
nu
}
def restoreMuteState(user: UserVO, users: Users1x, voiceUserId: String, userId: String,
callerIdName: String, callerIdNum: String, muted: Boolean, talking: Boolean,
avatarURL: String, listenOnly: Boolean): UserVO = {
val vu = new VoiceUserVO(voiceUserId, userId, callerIdName,
callerIdNum, joined = true, locked = false,
muted, talking, avatarURL, listenOnly)
val nu = user.modify(_.voiceUser).setTo(vu)
.modify(_.listenOnly).setTo(listenOnly)
users.save(nu)
nu
}
def makeUserPhoneUser(vu: VoiceUserVO, users: Users1x, webUserId: String, externUserId: String,
callerIdName: String, lockStatus: Boolean, listenOnly: Boolean, avatarURL: String): UserVO = {
val uvo = new UserVO(webUserId, externUserId, callerIdName,
Roles.VIEWER_ROLE, guest = false, authed = false, waitingForAcceptance = false, emojiStatus = "none", presenter = false,
hasStream = false, locked = lockStatus,
webcamStreams = new ListSet[String](),
phoneUser = !listenOnly, vu, listenOnly = listenOnly, avatarURL = avatarURL, joinedWeb = false)
users.save(uvo)
uvo
}
}
class Users1x {
private var users: collection.immutable.HashMap[String, UserVO] = new collection.immutable.HashMap[String, UserVO]
private def toVector: Vector[UserVO] = users.values.toVector
private def save(user: UserVO): UserVO = {
users += user.id -> user
user
}
private def remove(id: String): Option[UserVO] = {
val user = users.get(id)
user foreach (u => users -= id)
user
}
}
case class UserIdAndName(id: String, name: String)
/*
case class UserVO(id: String, externalId: String, name: String, role: String,
guest: Boolean, authed: Boolean, waitingForAcceptance: Boolean, emojiStatus: String,
presenter: Boolean, hasStream: Boolean, locked: Boolean, webcamStreams: Set[String],
phoneUser: Boolean, voiceUser: VoiceUser, listenOnly: Boolean, avatarURL: String,
joinedWeb: Boolean)
case class VoiceUser(userId: String, webUserId: String, callerName: String,
callerNum: String, joined: Boolean, locked: Boolean, muted: Boolean,
talking: Boolean, avatarURL: String, listenOnly: Boolean)
*/

View File

@ -55,7 +55,7 @@ object Users2x {
}
}
def unmakePresenter(users: Users2x, intId: String): Option[UserState] = {
def makeNotPresenter(users: Users2x, intId: String): Option[UserState] = {
for {
u <- findWithIntId(users, intId)
} yield {
@ -75,6 +75,16 @@ object Users2x {
}
}
def setUserLocked(users: Users2x, intId: String, locked: Boolean): Option[UserState] = {
for {
u <- findWithIntId(users, intId)
} yield {
val newUser = u.modify(_.locked).setTo(locked)
users.save(newUser)
newUser
}
}
def hasPresenter(users: Users2x): Boolean = {
findPresenter(users) match {
case Some(p) => true
@ -137,6 +147,8 @@ case class UserState(intId: String, extId: String, name: String, role: String,
guest: Boolean, authed: Boolean, waitingForAcceptance: Boolean, emoji: String, locked: Boolean,
presenter: Boolean, avatar: String)
case class UserIdAndName(id: String, name: String)
object CallingWith {
val WEBRTC = "webrtc"
val FLASH = "flash"

View File

@ -1,72 +0,0 @@
package org.bigbluebutton.core.pubsub.senders
import org.bigbluebutton.core.api._
import scala.collection.mutable.HashMap
import java.util.ArrayList
import org.bigbluebutton.core.messaging.Util
import org.bigbluebutton.common.messages.ChatKeyUtil
import scala.collection.JavaConverters
object ChatMessageToJsonConverter {
val UNKNOWN = "unknown"
private def chatMessageToMap(msg: Map[String, String]): HashMap[String, String] = {
val res = new HashMap[String, String]
res += "chat_type" -> msg.get(ChatKeyUtil.CHAT_TYPE).getOrElse(UNKNOWN)
res += "from_userid" -> msg.get(ChatKeyUtil.FROM_USERID).getOrElse(UNKNOWN)
res += "from_username" -> msg.get(ChatKeyUtil.FROM_USERNAME).getOrElse(UNKNOWN)
res += "from_color" -> msg.get(ChatKeyUtil.FROM_COLOR).getOrElse(UNKNOWN)
res += "from_time" -> msg.get(ChatKeyUtil.FROM_TIME).getOrElse(UNKNOWN)
res += "from_tz_offset" -> msg.get(ChatKeyUtil.FROM_TZ_OFFSET).getOrElse(UNKNOWN)
res += "to_userid" -> msg.get(ChatKeyUtil.TO_USERID).getOrElse(UNKNOWN)
res += "to_username" -> msg.get(ChatKeyUtil.TO_USERNAME).getOrElse(UNKNOWN)
res += "message" -> msg.get(ChatKeyUtil.MESSAGE).getOrElse(UNKNOWN)
res
}
def getChatHistoryReplyToJson(msg: GetChatHistoryReply): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.REQUESTER_ID, msg.requesterID)
val collection = new ArrayList[java.util.Map[String, String]]();
msg.history.foreach(p => {
collection.add(JavaConverters.mapAsJavaMap(ChatMessageToJsonConverter.chatMessageToMap(p)))
})
payload.put(Constants.CHAT_HISTORY, collection)
val header = Util.buildHeader(MessageNames.GET_CHAT_HISTORY_REPLY, Some(msg.replyTo))
Util.buildJson(header, payload)
}
def sendPublicMessageEventToJson(msg: SendPublicMessageEvent): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.MESSAGE, JavaConverters.mapAsJavaMap(ChatMessageToJsonConverter.chatMessageToMap(msg.message)))
val header = Util.buildHeader(MessageNames.SEND_PUBLIC_CHAT_MESSAGE, None)
Util.buildJson(header, payload)
}
def sendPrivateMessageEventToJson(msg: SendPrivateMessageEvent): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.MESSAGE, JavaConverters.mapAsJavaMap(ChatMessageToJsonConverter.chatMessageToMap(msg.message)))
val header = Util.buildHeader(MessageNames.SEND_PRIVATE_CHAT_MESSAGE, None)
Util.buildJson(header, payload)
}
def clearPublicChatHistoryReplyToJson(msg: ClearPublicChatHistoryReply): String = {
val payload = new java.util.HashMap[String, Any]()
payload.put(Constants.MEETING_ID, msg.meetingID)
payload.put(Constants.REQUESTER_ID, msg.requesterID)
val header = Util.buildHeader(MessageNames.CLEAR_PUBLIC_CHAT_HISTORY_REPLY, None)
Util.buildJson(header, payload)
}
}

View File

@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.JsonNode
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus._
import org.bigbluebutton.core2.ReceivedMessageRouter
import scala.reflect.runtime.universe._
object ReceivedJsonMsgHandlerActor {
@ -24,7 +23,7 @@ class ReceivedJsonMsgHandlerActor(
def receive = {
case msg: ReceivedJsonMessage =>
log.debug("handling {} - {}", msg.channel, msg.data)
//log.debug("handling {} - {}", msg.channel, msg.data)
handleReceivedJsonMessage(msg)
case _ => // do nothing
}
@ -44,8 +43,8 @@ class ReceivedJsonMsgHandlerActor(
}
def handle(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
if (SendCursorPositionPubMsg.NAME != envelope.name)
log.debug("Route envelope name " + envelope.name)
// if (SendCursorPositionPubMsg.NAME != envelope.name)
// log.debug("Route envelope name " + envelope.name)
envelope.name match {
case CreateMeetingReqMsg.NAME =>
@ -170,15 +169,15 @@ class ReceivedJsonMsgHandlerActor(
} yield {
send(m.header.meetingId, envelope, m)
}
case CreateBreakoutRoomsMsg.NAME =>
case CreateBreakoutRoomsCmdMsg.NAME =>
for {
m <- deserialize[CreateBreakoutRoomsMsg](jsonNode)
m <- deserialize[CreateBreakoutRoomsCmdMsg](jsonNode)
} yield {
send(m.header.meetingId, envelope, m)
}
case RequestBreakoutJoinURLMsg.NAME =>
case RequestBreakoutJoinURLReqMsg.NAME =>
for {
m <- deserialize[RequestBreakoutJoinURLMsg](jsonNode)
m <- deserialize[RequestBreakoutJoinURLReqMsg](jsonNode)
} yield {
send(m.header.meetingId, envelope, m)
}
@ -292,6 +291,14 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[CreateSharedNoteReqMsg](envelope, jsonNode)
case DestroySharedNoteReqMsg.NAME =>
routeGenericMsg[DestroySharedNoteReqMsg](envelope, jsonNode)
case GetChatHistoryReqMsg.NAME =>
routeGenericMsg[GetChatHistoryReqMsg](envelope, jsonNode)
case SendPublicMessagePubMsg.NAME =>
routeGenericMsg[SendPublicMessagePubMsg](envelope, jsonNode)
case SendPrivateMessagePubMsg.NAME =>
routeGenericMsg[SendPrivateMessagePubMsg](envelope, jsonNode)
case ClearPublicChatHistoryPubMsg.NAME =>
routeGenericMsg[ClearPublicChatHistoryPubMsg](envelope, jsonNode)
case _ =>
log.error("Cannot route envelope name " + envelope.name)
// do nothing

View File

@ -145,9 +145,9 @@ object UsersMessageToJsonConverter {
payload.put(Constants.PERMISSIONS, buildPermissionsHashMap(msg.permissions))
val users = new java.util.ArrayList[java.util.Map[String, Any]]
msg.applyTo.foreach(uvo => {
users.add(userToMap(uvo))
})
//msg.applyTo.foreach(uvo => {
// users.add(userToMap(uvo))
//})
payload.put("users", users)

View File

@ -5,15 +5,16 @@ import java.util.concurrent.TimeUnit
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.apps._
import org.bigbluebutton.core.domain.Meeting3x
import org.bigbluebutton.core.models._
import org.bigbluebutton.core2.MeetingStatus2x
class LiveMeeting(val props: DefaultProps,
val status: MeetingStatus2x,
val deskshareModel: DeskshareModel,
val chatModel: ChatModel,
val layoutModel: LayoutModel,
val layouts: Layouts,
val users: Users1x,
val registeredUsers: RegisteredUsers,
val polls: Polls, // 2x
val pollModel: PollModel, // 1.1x
@ -25,21 +26,14 @@ class LiveMeeting(val props: DefaultProps,
val webcams: Webcams,
val voiceUsers: VoiceUsers,
val users2x: Users2x,
val guestsWaiting: GuestsWaiting)
extends ChatModelTrait {
val guestsWaiting: GuestsWaiting) {
def hasMeetingEnded(): Boolean = {
MeetingStatus2x.hasMeetingEnded(status)
}
def webUserJoined() {
if (Users1x.numWebUsers(users) > 0) {
MeetingStatus2x.resetLastWebUserLeftOn(status)
}
}
def startCheckingIfWeNeedToEndVoiceConf() {
if (Users1x.numWebUsers(users) == 0 && !props.meetingProp.isBreakout) {
if (Users2x.numUsers(users2x) == 0 && !props.meetingProp.isBreakout) {
MeetingStatus2x.lastWebUserLeft(status)
}
}

View File

@ -9,23 +9,23 @@ import org.bigbluebutton.core._
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.apps._
import org.bigbluebutton.core.apps.caption.CaptionApp2x
import org.bigbluebutton.core.apps.chat.ChatApp2x
import org.bigbluebutton.core.apps.deskshare.DeskshareApp2x
import org.bigbluebutton.core.apps.presentation.PresentationApp2x
import org.bigbluebutton.core.apps.meeting._
import org.bigbluebutton.core.apps.users.UsersApp2x
import org.bigbluebutton.core.apps.sharednotes.SharedNotesApp2x
import org.bigbluebutton.core.bus._
import org.bigbluebutton.core.models.{ RegisteredUsers, Users1x }
import org.bigbluebutton.core.models._
import org.bigbluebutton.core2.MeetingStatus2x
import org.bigbluebutton.core2.message.handlers._
import org.bigbluebutton.core2.message.handlers.users._
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.breakout._
import org.bigbluebutton.core.apps.layout.LayoutApp2x
import org.bigbluebutton.core.apps.polls._
import org.bigbluebutton.core.apps.voice._
import scala.concurrent.duration._
import org.bigbluebutton.core.models.BreakoutRooms
import org.bigbluebutton.core2.testdata.FakeTestData
import org.bigbluebutton.core.apps.layout.LayoutApp2x
import org.bigbluebutton.core.apps.meeting.SyncGetMeetingInfoRespMsgHdlr
@ -39,42 +39,32 @@ object MeetingActor {
class MeetingActor(val props: DefaultProps,
val eventBus: IncomingEventBus,
val outGW: OutMessageGateway, val liveMeeting: LiveMeeting)
val outGW: OutMessageGateway,
val liveMeeting: LiveMeeting)
extends BaseMeetingActor
with GuestsApp
with LayoutApp2x
with VoiceApp2x
with PollApp2x
with BreakoutApp2x
with UsersApp2x
with UsersApp with PresentationApp
with ChatApp with WhiteboardApp with PollApp
with BreakoutRoomApp
with PresentationApp
with WhiteboardApp
with PermisssionCheck
with UserBroadcastCamStartMsgHdlr
with UserJoinMeetingReqMsgHdlr
with UserBroadcastCamStopMsgHdlr
with UserConnectedToGlobalAudioHdlr
with UserDisconnectedFromGlobalAudioHdlr
with MuteAllExceptPresenterRequestHdlr
with MuteMeetingRequestHdlr
with IsMeetingMutedRequestHdlr
with MuteUserRequestHdlr
with EjectUserFromVoiceRequestHdlr
with UserJoinedVoiceConfMessageHdlr
with ValidateAuthTokenReqMsgHdlr
with BreakoutRoomsListMsgHdlr
with CreateBreakoutRoomsMsgHdlr
with EndAllBreakoutRoomsMsgHdlr
with RequestBreakoutJoinURLMsgHdlr
with BreakoutRoomCreatedMsgHdlr
with BreakoutRoomEndedMsgHdlr
with BreakoutRoomUsersUpdateMsgHdlr
with SendBreakoutUsersUpdateMsgHdlr
with SyncGetMeetingInfoRespMsgHdlr
with TransferUserToMeetingRequestHdlr
with UserMutedInVoiceConfEvtMsgHdlr
with UserTalkingInVoiceConfEvtMsgHdlr {
with MuteAllExceptPresentersCmdMsgHdlr
with MuteMeetingCmdMsgHdlr
with IsMeetingMutedReqMsgHdlr
with MuteUserCmdMsgHdlr
with EjectUserFromVoiceCmdMsgHdlr
with EndMeetingSysCmdMsgHdlr
with SendTimeRemainingUpdateHdlr
with SyncGetMeetingInfoRespMsgHdlr {
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case e: Exception => {
@ -98,11 +88,11 @@ class MeetingActor(val props: DefaultProps,
eventBus.subscribe(actorMonitor, props.voiceProp.voiceConf)
eventBus.subscribe(actorMonitor, props.screenshareProps.screenshareConf)
val usersApp2x = new UsersApp2x(liveMeeting, outGW = outGW)
val presentationApp2x = new PresentationApp2x(liveMeeting, outGW = outGW)
val deskshareApp2x = new DeskshareApp2x(liveMeeting, outGW = outGW)
val captionApp2x = new CaptionApp2x(liveMeeting, outGW = outGW)
val sharedNotesApp2x = new SharedNotesApp2x(liveMeeting, outGW = outGW)
val chatApp2x = new ChatApp2x(liveMeeting, outGW = outGW)
/*******************************************************************/
//object FakeTestData extends FakeTestData
@ -113,54 +103,24 @@ class MeetingActor(val props: DefaultProps,
//=============================
// 2x messages
case msg: BbbCommonEnvCoreMsg => handleBbbCommonEnvCoreMsg(msg)
case msg: RegisterUserReqMsg => handleRegisterUserReqMsg(msg)
// Handling RegisterUserReqMsg as it is forwarded from BBBActor and
// its type is not BbbCommonEnvCoreMsg
case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m)
case m: GetAllMeetingsReqMsg => handleGetAllMeetingsReqMsg(m)
//======================================
//=======================================
// old messages
case msg: ActivityResponse => handleActivityResponse(msg)
case msg: MonitorNumberOfUsers => handleMonitorNumberOfUsers(msg)
//case msg: RegisterUser => handleRegisterUser(msg)
case msg: VoiceConfRecordingStartedMessage => handleVoiceConfRecordingStartedMessage(msg)
case msg: AssignPresenter => handleAssignPresenter(msg)
case msg: AllowUserToShareDesktop => handleAllowUserToShareDesktop(msg)
case msg: UserEmojiStatus => handleUserEmojiStatus(msg)
case msg: MuteMeetingRequest => handleMuteMeetingRequest(msg)
case msg: MuteAllExceptPresenterRequest => handleMuteAllExceptPresenterRequest(msg)
case msg: IsMeetingMutedRequest => handleIsMeetingMutedRequest(msg)
case msg: MuteUserRequest => handleMuteUserRequest(msg)
case msg: EjectUserFromVoiceRequest => handleEjectUserRequest(msg)
case msg: TransferUserToMeetingRequest => handleTransferUserToMeeting(msg)
case msg: GetChatHistoryRequest => handleGetChatHistoryRequest(msg)
case msg: SendPublicMessageRequest => handleSendPublicMessageRequest(msg)
case msg: SendPrivateMessageRequest => handleSendPrivateMessageRequest(msg)
case msg: UserConnectedToGlobalAudio => handleUserConnectedToGlobalAudio(msg)
case msg: UserDisconnectedFromGlobalAudio => handleUserDisconnectedFromGlobalAudio(msg)
case msg: InitializeMeeting => handleInitializeMeeting(msg)
case msg: SetRecordingStatus => handleSetRecordingStatus(msg)
case msg: GetRecordingStatus => handleGetRecordingStatus(msg)
case msg: GetPollRequest => handleGetPollRequest(msg)
case msg: LogoutEndMeeting => handleLogoutEndMeeting(msg)
case msg: ClearPublicChatHistoryRequest => handleClearPublicChatHistoryRequest(msg)
// Breakout rooms
case msg: BreakoutRoomsListMessage => handleBreakoutRoomsList(msg)
case msg: CreateBreakoutRooms => handleCreateBreakoutRooms(msg)
case msg: BreakoutRoomCreated => handleBreakoutRoomCreated(msg)
case msg: BreakoutRoomEnded => handleBreakoutRoomEnded(msg)
case msg: RequestBreakoutJoinURLInMessage => handleRequestBreakoutJoinURL(msg)
case msg: BreakoutRoomUsersUpdate => handleBreakoutRoomUsersUpdate(msg)
case msg: SendBreakoutUsersUpdate => handleSendBreakoutUsersUpdate(msg)
case msg: EndAllBreakoutRooms => handleEndAllBreakoutRooms(msg)
case msg: ExtendMeetingDuration => handleExtendMeetingDuration(msg)
case msg: SendTimeRemainingUpdate => handleSendTimeRemainingUpdate(msg)
case msg: EndMeeting => handleEndMeeting(msg)
case msg: DeskShareStartedRequest => handleDeskShareStartedRequest(msg)
case msg: DeskShareStoppedRequest => handleDeskShareStoppedRequest(msg)
@ -171,20 +131,26 @@ class MeetingActor(val props: DefaultProps,
// Guest
case msg: GetGuestPolicy => handleGetGuestPolicy(msg)
case msg: SetGuestPolicy => handleSetGuestPolicy(msg)
case msg: RespondToGuest => handleRespondToGuest(msg)
case _ => // do nothing
}
private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
msg.core match {
// Users
case m: ValidateAuthTokenReqMsg => handleValidateAuthTokenReqMsg(m)
case m: RegisterUserReqMsg => handleRegisterUserReqMsg(m)
case m: UserJoinMeetingReqMsg => handle(m)
case m: UserLeaveReqMsg => handle(m)
case m: UserJoinMeetingReqMsg => handleUserJoinMeetingReqMsg(m)
case m: UserLeaveReqMsg => handleUserLeaveReqMsg(m)
case m: UserBroadcastCamStartMsg => handleUserBroadcastCamStartMsg(m)
case m: UserBroadcastCamStopMsg => handleUserBroadcastCamStopMsg(m)
case m: UserJoinedVoiceConfEvtMsg => handleUserJoinedVoiceConfEvtMsg(m)
case m: MeetingActivityResponseCmdMsg => handleMeetingActivityResponseCmdMsg(m)
case m: LogoutAndEndMeetingCmdMsg => handleLogoutAndEndMeetingCmdMsg(m)
case m: SetRecordingStatusCmdMsg => handleSetRecordingStatusCmdMsg(m)
case m: GetRecordingStatusReqMsg => handleGetRecordingStatusReqMsg(m)
// Whiteboard
case m: SendCursorPositionPubMsg => handleSendCursorPositionPubMsg(m)
case m: ClearWhiteboardPubMsg => handleClearWhiteboardPubMsg(m)
case m: UndoWhiteboardPubMsg => handleUndoWhiteboardPubMsg(m)
@ -192,6 +158,8 @@ class MeetingActor(val props: DefaultProps,
case m: GetWhiteboardAccessReqMsg => handleGetWhiteboardAccessReqMsg(m)
case m: SendWhiteboardAnnotationPubMsg => handleSendWhiteboardAnnotationPubMsg(m)
case m: GetWhiteboardAnnotationsReqMsg => handleGetWhiteboardAnnotationsReqMsg(m)
// Poll
case m: StartPollReqMsg => handleStartPollReqMsg(m)
case m: StartCustomPollReqMsg => handleStartCustomPollReqMsg(m)
case m: StopPollReqMsg => handleStopPollReqMsg(m)
@ -199,21 +167,30 @@ class MeetingActor(val props: DefaultProps,
case m: HidePollResultReqMsg => handleHidePollResultReqMsg(m)
case m: GetCurrentPollReqMsg => handleGetCurrentPollReqMsg(m)
case m: RespondToPollReqMsg => handleRespondToPollReqMsg(m)
// Breakout
case m: BreakoutRoomsListMsg => handleBreakoutRoomsListMsg(m)
case m: CreateBreakoutRoomsMsg => handleCreateBreakoutRoomsMsg(m)
case m: CreateBreakoutRoomsCmdMsg => handleCreateBreakoutRoomsCmdMsg(m)
case m: EndAllBreakoutRoomsMsg => handleEndAllBreakoutRoomsMsg(m)
case m: RequestBreakoutJoinURLMsg => handleRequestBreakoutJoinURLMsg(m)
case m: RequestBreakoutJoinURLReqMsg => handleRequestBreakoutJoinURLReqMsg(m)
case m: BreakoutRoomCreatedMsg => handleBreakoutRoomCreatedMsg(m)
case m: BreakoutRoomEndedMsg => handleBreakoutRoomEndedMsg(m)
case m: BreakoutRoomUsersUpdateMsg => handleBreakoutRoomUsersUpdateMsg(m)
case m: SendBreakoutUsersUpdateMsg => handleSendBreakoutUsersUpdateMsg(m)
case m: TransferUserToMeetingRequestMsg => handleTransferUserToMeetingRequestMsg(m)
case m: UserLeftVoiceConfEvtMsg => handle(m)
case m: UserMutedInVoiceConfEvtMsg => handle(m)
case m: UserTalkingInVoiceConfEvtMsg => handle(m)
case m: GetCurrentLayoutReqMsg => handle(m)
// Voice
case m: UserLeftVoiceConfEvtMsg => handleUserLeftVoiceConfEvtMsg(m)
case m: UserMutedInVoiceConfEvtMsg => handleUserMutedInVoiceConfEvtMsg(m)
case m: UserTalkingInVoiceConfEvtMsg => handleUserTalkingInVoiceConfEvtMsg(m)
case m: RecordingStartedVoiceConfEvtMsg => handleRecordingStartedVoiceConfEvtMsg(m)
// Layout
case m: GetCurrentLayoutReqMsg => handleGetCurrentLayoutReqMsg(m)
case m: LockLayoutMsg => handleLockLayoutMsg(m)
case m: BroadcastLayoutMsg => handleBroadcastLayoutMsg(m)
// Presentation
case m: SetCurrentPresentationPubMsg => presentationApp2x.handleSetCurrentPresentationPubMsg(m)
case m: GetPresentationInfoReqMsg => presentationApp2x.handleGetPresentationInfoReqMsg(m)
case m: SetCurrentPagePubMsg => presentationApp2x.handleSetCurrentPagePubMsg(m)
@ -238,37 +215,27 @@ class MeetingActor(val props: DefaultProps,
case m: CreateSharedNoteReqMsg => sharedNotesApp2x.handleCreateSharedNoteReqMsg(m)
case m: DestroySharedNoteReqMsg => sharedNotesApp2x.handleDestroySharedNoteReqMsg(m)
//Guests
case m: GetGuestsWaitingApprovalReqMsg => handle(m)
case m: SetGuestPolicyMsg => handle(m)
case m: GuestsWaitingApprovedMsg => handle(m)
// Guests
case m: GetGuestsWaitingApprovalReqMsg => handleGetGuestsWaitingApprovalReqMsg(m)
case m: SetGuestPolicyMsg => handleSetGuestPolicyMsg(m)
case m: GuestsWaitingApprovedMsg => handleGuestsWaitingApprovedMsg(m)
// Chat
case m: GetChatHistoryReqMsg => chatApp2x.handleGetChatHistoryReqMsg(m)
case m: SendPublicMessagePubMsg => chatApp2x.handleSendPublicMessagePubMsg(m)
case m: SendPrivateMessagePubMsg => chatApp2x.handleSendPrivateMessagePubMsg(m)
case m: ClearPublicChatHistoryPubMsg => chatApp2x.handleClearPublicChatHistoryPubMsg(m)
case _ => log.warning("***** Cannot handle " + msg.envelope.name)
}
}
def handleRegisterUserReqMsg(msg: RegisterUserReqMsg): Unit = {
log.debug("****** RECEIVED RegisterUserReqMsg msg {}", msg)
if (MeetingStatus2x.hasMeetingEnded(liveMeeting.status)) {
// Check first if the meeting has ended and the user refreshed the client to re-connect.
log.info("Register user failed. Mmeeting has ended. meetingId=" + props.meetingProp.intId +
" userId=" + msg.body.intUserId)
} else {
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
msg.body.name, msg.body.role, msg.body.authToken,
msg.body.avatarURL, msg.body.guest, msg.body.authed, msg.body.guest, liveMeeting.registeredUsers)
log.info("Register user success. meetingId=" + props.meetingProp.intId + " userId=" + msg.body.extUserId + " user=" + regUser)
outGW.send(new UserRegistered(props.meetingProp.intId, props.recordProp.record, regUser))
}
}
def handleGetAllMeetingsReqMsg(msg: GetAllMeetingsReqMsg): Unit = {
// sync all meetings
handleSyncGetMeetingInfoRespMsg(liveMeeting.props)
// sync all users
usersApp2x.handleSyncGetUsersMeetingRespMsg()
handleSyncGetUsersMeetingRespMsg()
// sync all presentations
presentationApp2x.handleSyncGetPresentationInfoRespMsg()
@ -283,7 +250,7 @@ class MeetingActor(val props: DefaultProps,
handleStopPollReqMsg(msg.header.userId)
// switch user presenter status for old and new presenter
usersApp2x.handleAssignPresenterReqMsg(msg)
handleAssignPresenterReqMsg(msg)
// TODO stop current screen sharing session (initiated by the old presenter)
@ -291,18 +258,18 @@ class MeetingActor(val props: DefaultProps,
def handleDeskShareRTMPBroadcastStoppedRequest(msg: DeskShareRTMPBroadcastStoppedRequest): Unit = {
log.info("handleDeskShareRTMPBroadcastStoppedRequest: isBroadcastingRTMP=" +
MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status) + " URL:" +
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status))
DeskshareModel.isBroadcastingRTMP(liveMeeting.deskshareModel) + " URL:" +
DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel))
// only valid if currently broadcasting
if (MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status)) {
if (DeskshareModel.isBroadcastingRTMP(liveMeeting.deskshareModel)) {
log.info("STOP broadcast ALLOWED when isBroadcastingRTMP=true")
MeetingStatus2x.broadcastingRTMPStopped(liveMeeting.status)
DeskshareModel.broadcastingRTMPStopped(liveMeeting.deskshareModel)
// notify viewers that RTMP broadcast stopped
outGW.send(new DeskShareNotifyViewersRTMP(props.meetingProp.intId,
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status),
msg.videoWidth, msg.videoHeight, false))
//outGW.send(new DeskShareNotifyViewersRTMP(props.meetingProp.intId,
// DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel),
// msg.videoWidth, msg.videoHeight, false))
} else {
log.info("STOP broadcast NOT ALLOWED when isBroadcastingRTMP=false")
}
@ -311,15 +278,15 @@ class MeetingActor(val props: DefaultProps,
def handleDeskShareGetDeskShareInfoRequest(msg: DeskShareGetDeskShareInfoRequest): Unit = {
log.info("handleDeskShareGetDeskShareInfoRequest: " + msg.conferenceName + "isBroadcasting="
+ MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status) + " URL:" +
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status))
+ DeskshareModel.isBroadcastingRTMP(liveMeeting.deskshareModel) + " URL:" +
DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel))
if (MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status)) {
if (DeskshareModel.isBroadcastingRTMP(liveMeeting.deskshareModel)) {
// if the meeting has an ongoing WebRTC Deskshare session, send a notification
outGW.send(new DeskShareNotifyASingleViewer(props.meetingProp.intId, msg.requesterID,
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status),
MeetingStatus2x.getDesktopShareVideoWidth(liveMeeting.status),
MeetingStatus2x.getDesktopShareVideoHeight(liveMeeting.status), true))
//outGW.send(new DeskShareNotifyASingleViewer(props.meetingProp.intId, msg.requesterID,
// DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel),
// DeskshareModel.getDesktopShareVideoWidth(liveMeeting.deskshareModel),
// DeskshareModel.getDesktopShareVideoHeight(liveMeeting.deskshareModel), true))
}
}
@ -335,107 +302,61 @@ class MeetingActor(val props: DefaultProps,
// MeetingStatus2x.getGuestPolicy(liveMeeting.status).toString()))
}
def handleLogoutEndMeeting(msg: LogoutEndMeeting) {
if (Users1x.isModerator(msg.userID, liveMeeting.users)) {
handleEndMeeting(EndMeeting(props.meetingProp.intId))
}
}
def handleActivityResponse(msg: ActivityResponse) {
log.info("User endorsed that meeting {} is active", props.meetingProp.intId)
outGW.send(new MeetingIsActive(props.meetingProp.intId))
}
def handleEndMeeting(msg: EndMeeting) {
// Broadcast users the meeting will end
outGW.send(new MeetingEnding(msg.meetingId))
MeetingStatus2x.meetingHasEnded(liveMeeting.status)
outGW.send(new MeetingEnded(msg.meetingId, props.recordProp.record, props.meetingProp.intId))
}
def handleAllowUserToShareDesktop(msg: AllowUserToShareDesktop): Unit = {
Users1x.getCurrentPresenter(liveMeeting.users) match {
Users2x.findPresenter(liveMeeting.users2x) match {
case Some(curPres) => {
val allowed = msg.userID equals (curPres.id)
outGW.send(AllowUserToShareDesktopOut(msg.meetingID, msg.userID, allowed))
val allowed = msg.userID equals (curPres.intId)
// outGW.send(AllowUserToShareDesktopOut(msg.meetingID, msg.userID, allowed))
}
case None => // do nothing
}
}
def handleVoiceConfRecordingStartedMessage(msg: VoiceConfRecordingStartedMessage) {
if (msg.recording) {
MeetingStatus2x.setVoiceRecordingFilename(liveMeeting.status, msg.recordStream)
outGW.send(new VoiceRecordingStarted(props.meetingProp.intId, props.recordProp.record,
msg.recordStream, msg.timestamp, props.voiceProp.voiceConf))
} else {
MeetingStatus2x.setVoiceRecordingFilename(liveMeeting.status, "")
outGW.send(new VoiceRecordingStopped(props.meetingProp.intId, props.recordProp.record,
msg.recordStream, msg.timestamp, props.voiceProp.voiceConf))
}
}
def handleSetRecordingStatus(msg: SetRecordingStatus) {
log.info("Change recording status. meetingId=" + props.meetingProp.intId + " recording=" + msg.recording)
if (props.recordProp.allowStartStopRecording &&
MeetingStatus2x.isRecording(liveMeeting.status) != msg.recording) {
if (msg.recording) {
MeetingStatus2x.recordingStarted(liveMeeting.status)
} else {
MeetingStatus2x.recordingStopped(liveMeeting.status)
}
outGW.send(new RecordingStatusChanged(props.meetingProp.intId, props.recordProp.record, msg.userId, msg.recording))
}
}
// WebRTC Desktop Sharing
def handleDeskShareStartedRequest(msg: DeskShareStartedRequest): Unit = {
log.info("handleDeskShareStartedRequest: dsStarted=" + MeetingStatus2x.getDeskShareStarted(liveMeeting.status))
log.info("handleDeskShareStartedRequest: dsStarted=" + DeskshareModel.getDeskShareStarted(liveMeeting.deskshareModel))
if (!MeetingStatus2x.getDeskShareStarted(liveMeeting.status)) {
if (!DeskshareModel.getDeskShareStarted(liveMeeting.deskshareModel)) {
val timestamp = System.currentTimeMillis().toString
val streamPath = "rtmp://" + props.screenshareProps.red5ScreenshareIp + "/" + props.screenshareProps.red5ScreenshareApp +
"/" + props.meetingProp.intId + "/" + props.meetingProp.intId + "-" + timestamp
log.info("handleDeskShareStartedRequest: streamPath=" + streamPath)
// Tell FreeSwitch to broadcast to RTMP
outGW.send(new DeskShareStartRTMPBroadcast(msg.conferenceName, streamPath))
//outGW.send(new DeskShareStartRTMPBroadcast(msg.conferenceName, streamPath))
MeetingStatus2x.setDeskShareStarted(liveMeeting.status, true)
DeskshareModel.setDeskShareStarted(liveMeeting.deskshareModel, true)
}
}
def handleDeskShareStoppedRequest(msg: DeskShareStoppedRequest): Unit = {
log.info("handleDeskShareStoppedRequest: dsStarted=" +
MeetingStatus2x.getDeskShareStarted(liveMeeting.status) +
" URL:" + MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status))
DeskshareModel.getDeskShareStarted(liveMeeting.deskshareModel) +
" URL:" + DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel))
// Tell FreeSwitch to stop broadcasting to RTMP
outGW.send(new DeskShareStopRTMPBroadcast(msg.conferenceName,
MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status)))
//outGW.send(new DeskShareStopRTMPBroadcast(msg.conferenceName,
// DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel)))
MeetingStatus2x.setDeskShareStarted(liveMeeting.status, false)
DeskshareModel.setDeskShareStarted(liveMeeting.deskshareModel, false)
}
def handleDeskShareRTMPBroadcastStartedRequest(msg: DeskShareRTMPBroadcastStartedRequest): Unit = {
log.info("handleDeskShareRTMPBroadcastStartedRequest: isBroadcastingRTMP=" +
MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status) +
" URL:" + MeetingStatus2x.getRTMPBroadcastingUrl(liveMeeting.status))
DeskshareModel.isBroadcastingRTMP(liveMeeting.deskshareModel) +
" URL:" + DeskshareModel.getRTMPBroadcastingUrl(liveMeeting.deskshareModel))
// only valid if not broadcasting yet
if (!MeetingStatus2x.isBroadcastingRTMP(liveMeeting.status)) {
MeetingStatus2x.setRTMPBroadcastingUrl(liveMeeting.status, msg.streamname)
MeetingStatus2x.broadcastingRTMPStarted(liveMeeting.status)
MeetingStatus2x.setDesktopShareVideoWidth(liveMeeting.status, msg.videoWidth)
MeetingStatus2x.setDesktopShareVideoHeight(liveMeeting.status, msg.videoHeight)
if (!DeskshareModel.isBroadcastingRTMP(liveMeeting.deskshareModel)) {
DeskshareModel.setRTMPBroadcastingUrl(liveMeeting.deskshareModel, msg.streamname)
DeskshareModel.broadcastingRTMPStarted(liveMeeting.deskshareModel)
DeskshareModel.setDesktopShareVideoWidth(liveMeeting.deskshareModel, msg.videoWidth)
DeskshareModel.setDesktopShareVideoHeight(liveMeeting.deskshareModel, msg.videoHeight)
log.info("START broadcast ALLOWED when isBroadcastingRTMP=false")
// Notify viewers in the meeting that there's an rtmp stream to view
outGW.send(new DeskShareNotifyViewersRTMP(props.meetingProp.intId, msg.streamname, msg.videoWidth, msg.videoHeight, true))
//outGW.send(new DeskShareNotifyViewersRTMP(props.meetingProp.intId, msg.streamname, msg.videoWidth, msg.videoHeight, true))
} else {
log.info("START broadcast NOT ALLOWED when isBroadcastingRTMP=true")
}
@ -447,70 +368,81 @@ class MeetingActor(val props: DefaultProps,
}
def monitorNumberOfWebUsers() {
if (Users1x.numWebUsers(liveMeeting.users) == 0 &&
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 &&
MeetingStatus2x.lastWebUserLeftOn(liveMeeting.status) > 0) {
if (liveMeeting.timeNowInMinutes - MeetingStatus2x.lastWebUserLeftOn(liveMeeting.status) > 2) {
log.info("Empty meeting. Ejecting all users from voice. meetingId={}", props.meetingProp.intId)
outGW.send(new EjectAllVoiceUsers(props.meetingProp.intId, props.recordProp.record, props.voiceProp.voiceConf))
val event = buildEjectAllFromVoiceConfMsg(props.meetingProp.intId, props.voiceProp.voiceConf)
outGW.send(event)
}
}
}
def monitorNumberOfUsers() {
val hasUsers = Users1x.numUsers(liveMeeting.users) != 0
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 handleSendTimeRemainingUpdate(msg: SendTimeRemainingUpdate) {
if (props.durationProps.duration > 0) {
val endMeetingTime = MeetingStatus2x.startedOn(liveMeeting.status) + (props.durationProps.duration * 60)
val timeRemaining = endMeetingTime - liveMeeting.timeNowInSeconds
outGW.send(new MeetingTimeRemainingUpdate(props.meetingProp.intId, props.recordProp.record, timeRemaining.toInt))
}
if (!props.meetingProp.isBreakout && !BreakoutRooms.getRooms(liveMeeting.breakoutRooms).isEmpty) {
val endMeetingTime = MeetingStatus2x.breakoutRoomsStartedOn(liveMeeting.status) +
(MeetingStatus2x.breakoutRoomsdurationInMinutes(liveMeeting.status) * 60)
val timeRemaining = endMeetingTime - liveMeeting.timeNowInSeconds
outGW.send(new BreakoutRoomsTimeRemainingUpdateOutMessage(props.meetingProp.intId, props.recordProp.record, timeRemaining.toInt))
} else if (MeetingStatus2x.breakoutRoomsStartedOn(liveMeeting.status) != 0) {
MeetingStatus2x.breakoutRoomsdurationInMinutes(liveMeeting.status, 0)
MeetingStatus2x.breakoutRoomsStartedOn(liveMeeting.status, 0)
}
}
def handleExtendMeetingDuration(msg: ExtendMeetingDuration) {
}
def handleGetRecordingStatus(msg: GetRecordingStatus) {
outGW.send(new GetRecordingStatusReply(props.meetingProp.intId, props.recordProp.record,
msg.userId, MeetingStatus2x.isRecording(liveMeeting.status).booleanValue()))
}
def startRecordingIfAutoStart() {
if (props.recordProp.record && !MeetingStatus2x.isRecording(liveMeeting.status) &&
props.recordProp.autoStartRecording && Users1x.numWebUsers(liveMeeting.users) == 1) {
props.recordProp.autoStartRecording && Users2x.numUsers(liveMeeting.users2x) == 1) {
log.info("Auto start recording. meetingId={}", props.meetingProp.intId)
MeetingStatus2x.recordingStarted(liveMeeting.status)
outGW.send(new RecordingStatusChanged(props.meetingProp.intId, props.recordProp.record,
"system", MeetingStatus2x.isRecording(liveMeeting.status)))
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
val event = RecordingStatusChangedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildRecordingStatusChangedEvtMsg(liveMeeting.props.meetingProp.intId,
"system", MeetingStatus2x.isRecording(liveMeeting.status))
outGW.send(event)
}
}
def stopAutoStartedRecording() {
if (props.recordProp.record && MeetingStatus2x.isRecording(liveMeeting.status) &&
props.recordProp.autoStartRecording && Users1x.numWebUsers(liveMeeting.users) == 0) {
props.recordProp.autoStartRecording && Users2x.numUsers(liveMeeting.users2x) == 0) {
log.info("Last web user left. Auto stopping recording. meetingId={}", props.meetingProp.intId)
MeetingStatus2x.recordingStopped(liveMeeting.status)
outGW.send(new RecordingStatusChanged(props.meetingProp.intId, props.recordProp.record,
"system", MeetingStatus2x.isRecording(liveMeeting.status)))
}
def buildRecordingStatusChangedEvtMsg(meetingId: String, userId: String, recording: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(RecordingStatusChangedEvtMsg.NAME, routing)
val body = RecordingStatusChangedEvtMsgBody(recording, userId)
val header = BbbClientMsgHeader(RecordingStatusChangedEvtMsg.NAME, meetingId, userId)
val event = RecordingStatusChangedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def sendMeetingHasEnded(userId: String) {
outGW.send(new MeetingHasEnded(props.meetingProp.intId, userId))
outGW.send(new DisconnectUser(props.meetingProp.intId, userId))
val event = buildRecordingStatusChangedEvtMsg(liveMeeting.props.meetingProp.intId,
"system", MeetingStatus2x.isRecording(liveMeeting.status))
outGW.send(event)
}
}
def record(msg: BbbCoreMsg): Unit = {

View File

@ -11,7 +11,8 @@ import akka.actor.SupervisorStrategy.Resume
import scala.concurrent.duration._
import org.bigbluebutton.SystemConfiguration
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.core.{ OutMessageGateway }
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.bus.{ BigBlueButtonEvent, IncomingEventBus }
@ -76,20 +77,30 @@ class MeetingActorInternal(val props: DefaultProps,
private val InactivityDeadline = FiniteDuration(getInactivityDeadline(), "seconds")
private val InactivityTimeLeft = FiniteDuration(getInactivityTimeLeft(), "seconds")
private var inactivity = InactivityDeadline.fromNow
private var inactivityWarning: Deadline = null
private var inactivityWarning: Option[Deadline] = None
private val ExpireMeetingDuration = FiniteDuration(props.durationProps.duration, "minutes")
private val ExpireMeetingNeverJoined = FiniteDuration(getExpireNeverJoined(), "seconds")
private val ExpireMeetingLastUserLeft = FiniteDuration(getExpireLastUserLeft(), "seconds")
private var meetingExpire = ExpireMeetingNeverJoined.fromNow
private var meetingExpire: Option[Deadline] = Some(ExpireMeetingNeverJoined.fromNow)
// Zero minutes means the meeting has no duration control
private var meetingDuration: Deadline = if (ExpireMeetingDuration > (0 minutes)) ExpireMeetingDuration.fromNow else null
private var meetingDuration: Option[Deadline] = if (ExpireMeetingDuration > (0 minutes)) Some(ExpireMeetingDuration.fromNow) else None
context.system.scheduler.schedule(5 seconds, MonitorFrequency, self, "Monitor")
// Query to get voice conference users
outGW.send(new GetUsersInVoiceConference(props.meetingProp.intId, props.recordProp.record,
props.voiceProp.voiceConf))
def build(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(GetUsersInVoiceConfSysMsg.NAME, routing)
val body = GetUsersInVoiceConfSysMsgBody(props.voiceProp.voiceConf)
val header = BbbCoreHeaderWithMeetingId(GetUsersInVoiceConfSysMsg.NAME, meetingId)
val event = GetUsersInVoiceConfSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = build(props.meetingProp.intId)
outGW.send(event)
if (props.meetingProp.isBreakout) {
// This is a breakout room. Inform our parent meeting that we have been successfully created.
@ -130,66 +141,109 @@ class MeetingActorInternal(val props: DefaultProps,
}
private def handleMonitorActivity() {
if (inactivity.isOverdue() && inactivityWarning != null && inactivityWarning.isOverdue()) {
inactivityWarning match {
case Some(iw) =>
if (inactivity.isOverdue() && iw.isOverdue()) {
log.info("Closing meeting {} due to inactivity for {} seconds", props.meetingProp.intId, InactivityDeadline.toSeconds)
updateInactivityMonitors()
eventBus.publish(BigBlueButtonEvent(props.meetingProp.intId, EndMeeting(props.meetingProp.intId)))
// Or else make sure to send only one warning message
} else if (inactivity.isOverdue() && inactivityWarning == null) {
}
case None =>
if (inactivity.isOverdue()) {
log.info("Sending inactivity warning to meeting {}", props.meetingProp.intId)
outGW.send(new InactivityWarning(props.meetingProp.intId, InactivityTimeLeft.toSeconds))
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, InactivityTimeLeft.toSeconds)
outGW.send(event)
// We add 5 seconds so clients will have enough time to process the message
inactivityWarning = (InactivityTimeLeft + (5 seconds)).fromNow
inactivityWarning = Some((InactivityTimeLeft + (5 seconds)).fromNow)
}
}
}
private def handleMonitorExpiration() {
if (meetingExpire != null && meetingExpire.isOverdue()) {
for {
mExpire <- meetingExpire
} yield {
if (mExpire.isOverdue()) {
// User related meeting expiration methods
log.debug("Meeting {} expired. No users", props.meetingProp.intId)
meetingExpire = null
meetingExpire = None
eventBus.publish(BigBlueButtonEvent(props.meetingProp.intId, EndMeeting(props.meetingProp.intId)))
} else if (meetingDuration != null && meetingDuration.isOverdue()) {
}
}
for {
mDuration <- meetingDuration
} yield {
if (mDuration.isOverdue()) {
// Default meeting duration
meetingDuration = null
meetingDuration = None
log.debug("Meeting {} expired. Reached it's fixed duration of {}", props.meetingProp.intId, ExpireMeetingDuration.toString())
eventBus.publish(BigBlueButtonEvent(props.meetingProp.intId, EndMeeting(props.meetingProp.intId)))
}
}
}
private def handleUpdateMeetingExpireMonitor(msg: UpdateMeetingExpireMonitor) {
if (msg.hasUser) {
if (meetingExpire != null) {
// User joined. Forget about this expiration for now
meetingExpire match {
case Some(mExpire) =>
log.debug("Meeting has users. Stopping expiration for meeting {}", props.meetingProp.intId)
meetingExpire = null
}
} else {
if (meetingExpire == null) {
meetingExpire = None
case None =>
// User list is empty. Start this meeting expiration method
log.debug("Meeting has no users. Starting {} expiration for meeting {}", ExpireMeetingLastUserLeft.toString(), props.meetingProp.intId)
meetingExpire = ExpireMeetingLastUserLeft.fromNow
meetingExpire = Some(ExpireMeetingLastUserLeft.fromNow)
}
}
}
private def updateInactivityMonitors() {
inactivity = InactivityDeadline.fromNow
inactivityWarning = null
inactivityWarning = None
}
private def notifyActivity() {
if (inactivityWarning != null) {
outGW.send(new MeetingIsActive(props.meetingProp.intId))
for {
_ <- inactivityWarning
} yield {
val event = buildMeetingIsActiveEvtMsg(props.meetingProp.intId)
outGW.send(event)
}
updateInactivityMonitors()
}
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)
}
private def handleActivityResponse(msg: ActivityResponse) {
log.info("User endorsed that meeting {} is active", props.meetingProp.intId)
updateInactivityMonitors()
outGW.send(new MeetingIsActive(props.meetingProp.intId))
val event = buildMeetingIsActiveEvtMsg(props.meetingProp.intId)
outGW.send(event)
}
private def isMeetingActivity(msg: Object): Boolean = {

View File

@ -26,7 +26,6 @@ class RunningMeeting(val props: DefaultProps, val outGW: OutMessageGateway,
val breakoutRooms = new BreakoutRooms()
val captionModel = new CaptionModel()
val notesModel = new SharedNotesModel()
val users = new Users1x
val registeredUsers = new RegisteredUsers
val meetingStatux2x = new MeetingStatus2x
val webcams = new Webcams
@ -34,13 +33,14 @@ class RunningMeeting(val props: DefaultProps, val outGW: OutMessageGateway,
val users2x = new Users2x
val polls2x = new Polls
val guestsWaiting = new GuestsWaiting
val deskshareModel = new DeskshareModel
// meetingModel.setGuestPolicy(props.usersProp.guestPolicy)
// We extract the meeting handlers into this class so it is
// easy to test.
val liveMeeting = new LiveMeeting(props, meetingStatux2x, chatModel, layoutModel, layouts,
users, registeredUsers, polls2x, pollModel, wbModel, presModel, breakoutRooms, captionModel,
val liveMeeting = new LiveMeeting(props, meetingStatux2x, deskshareModel, chatModel, layoutModel, layouts,
registeredUsers, polls2x, pollModel, wbModel, presModel, breakoutRooms, captionModel,
notesModel, webcams, voiceUsers, users2x, guestsWaiting)
val actorRef = context.actorOf(MeetingActor.props(props, eventBus, outGW, liveMeeting), props.meetingProp.intId)

View File

@ -6,44 +6,6 @@ import org.bigbluebutton.core.MeetingExtensionProp
import org.bigbluebutton.core.api.{ Permissions, Presenter }
object MeetingStatus2x {
def setCurrentPresenterInfo(status: MeetingStatus2x, pres: Presenter) {
status.currentPresenter = pres
}
def getCurrentPresenterInfo(status: MeetingStatus2x): Presenter = {
status.currentPresenter
}
def addGlobalAudioConnection(status: MeetingStatus2x, userID: String): Boolean = {
status.globalAudioConnectionCounter.get(userID) match {
case Some(vc) => {
status.globalAudioConnectionCounter += userID -> (vc + 1)
false
}
case None => {
status.globalAudioConnectionCounter += userID -> 1
true
}
}
}
def removeGlobalAudioConnection(status: MeetingStatus2x, userID: String): Boolean = {
status.globalAudioConnectionCounter.get(userID) match {
case Some(vc) => {
if (vc == 1) {
status.globalAudioConnectionCounter -= userID
true
} else {
status.globalAudioConnectionCounter += userID -> (vc - 1)
false
}
}
case None => {
false
}
}
}
def startRecordingVoice(status: MeetingStatus2x): Boolean = {
status.recordingVoice = true
status.recordingVoice
@ -58,58 +20,6 @@ object MeetingStatus2x {
status.recordingVoice
}
def resetDesktopSharingParams(status: MeetingStatus2x) = {
status.broadcastingRTMP = false
status.deskShareStarted = false
status.rtmpBroadcastingUrl = ""
status.desktopShareVideoWidth = 0
status.desktopShareVideoHeight = 0
}
def getDeskShareStarted(status: MeetingStatus2x): Boolean = {
return status.deskShareStarted
}
def setDeskShareStarted(status: MeetingStatus2x, b: Boolean) {
status.deskShareStarted = b
}
def setDesktopShareVideoWidth(status: MeetingStatus2x, videoWidth: Int) {
status.desktopShareVideoWidth = videoWidth
}
def setDesktopShareVideoHeight(status: MeetingStatus2x, videoHeight: Int) {
status.desktopShareVideoHeight = videoHeight
}
def getDesktopShareVideoWidth(status: MeetingStatus2x): Int = {
status.desktopShareVideoWidth
}
def getDesktopShareVideoHeight(status: MeetingStatus2x): Int = {
status.desktopShareVideoHeight
}
def broadcastingRTMPStarted(status: MeetingStatus2x) {
status.broadcastingRTMP = true
}
def isBroadcastingRTMP(status: MeetingStatus2x): Boolean = {
status.broadcastingRTMP
}
def broadcastingRTMPStopped(status: MeetingStatus2x) {
status.broadcastingRTMP = false
}
def setRTMPBroadcastingUrl(status: MeetingStatus2x, path: String) {
status.rtmpBroadcastingUrl = path
}
def getRTMPBroadcastingUrl(status: MeetingStatus2x): String = {
status.rtmpBroadcastingUrl
}
def isExtensionAllowed(status: MeetingStatus2x): Boolean = status.extension.numExtensions < status.extension.maxExtensions
def incNumExtension(status: MeetingStatus2x): Int = {
if (status.extension.numExtensions < status.extension.maxExtensions) {
@ -149,27 +59,18 @@ object MeetingStatus2x {
def startedOn(status: MeetingStatus2x): Long = status.startedOn
def breakoutRoomsStartedOn(status: MeetingStatus2x) = status.breakoutRoomsStartedOn
def breakoutRoomsStartedOn(status: MeetingStatus2x, startedOn: Long) = status.breakoutRoomsStartedOn = startedOn
def breakoutRoomsdurationInMinutes(status: MeetingStatus2x) = status.breakoutRoomsdurationInMinutes
def breakoutRoomsdurationInMinutes(status: MeetingStatus2x, duration: Int) = status.breakoutRoomsdurationInMinutes = duration
def timeNowInMinutes(): Long = TimeUnit.NANOSECONDS.toMinutes(System.nanoTime())
def timeNowInSeconds(): Long = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime())
}
class MeetingStatus2x {
private var globalAudioConnectionCounter = new collection.immutable.HashMap[String, Integer]
private var recordingVoice = false
private var currentPresenter = new Presenter("system", "system", "system")
private var audioSettingsInited = false
private var permissionsInited = false
private var permissions = new Permissions()
private var recording = false
private var broadcastingRTMP = false
private var muted = false
private var meetingEnded = false
private var meetingMuted = false
@ -178,54 +79,10 @@ class MeetingStatus2x {
private var lastWebUserLeftOnTimestamp: Long = 0
private var voiceRecordingFilename: String = ""
private var rtmpBroadcastingUrl: String = ""
private var deskShareStarted = false
private var desktopShareVideoWidth = 0
private var desktopShareVideoHeight = 0
private var extension = new MeetingExtensionProp
private val startedOn = MeetingStatus2x.timeNowInSeconds;
private var breakoutRoomsStartedOn: Long = 0
private var breakoutRoomsdurationInMinutes: Int = 0
private def setCurrentPresenterInfo(pres: Presenter) {
currentPresenter = pres
}
private def getCurrentPresenterInfo(): Presenter = {
currentPresenter
}
private def addGlobalAudioConnection(userID: String): Boolean = {
globalAudioConnectionCounter.get(userID) match {
case Some(vc) => {
globalAudioConnectionCounter += userID -> (vc + 1)
false
}
case None => {
globalAudioConnectionCounter += userID -> 1
true
}
}
}
private def removeGlobalAudioConnection(userID: String): Boolean = {
globalAudioConnectionCounter.get(userID) match {
case Some(vc) => {
if (vc == 1) {
globalAudioConnectionCounter -= userID
true
} else {
globalAudioConnectionCounter += userID -> (vc - 1)
false
}
}
case None => {
false
}
}
}
private def startRecordingVoice() {
recordingVoice = true
@ -239,58 +96,6 @@ class MeetingStatus2x {
recordingVoice
}
private def resetDesktopSharingParams() = {
broadcastingRTMP = false
deskShareStarted = false
rtmpBroadcastingUrl = ""
desktopShareVideoWidth = 0
desktopShareVideoHeight = 0
}
private def getDeskShareStarted(): Boolean = {
return deskShareStarted
}
private def setDeskShareStarted(b: Boolean) {
deskShareStarted = b
}
private def setDesktopShareVideoWidth(videoWidth: Int) {
desktopShareVideoWidth = videoWidth
}
private def setDesktopShareVideoHeight(videoHeight: Int) {
desktopShareVideoHeight = videoHeight
}
private def getDesktopShareVideoWidth(): Int = {
desktopShareVideoWidth
}
private def getDesktopShareVideoHeight(): Int = {
desktopShareVideoHeight
}
private def broadcastingRTMPStarted() {
broadcastingRTMP = true
}
private def isBroadcastingRTMP(): Boolean = {
broadcastingRTMP
}
private def broadcastingRTMPStopped() {
broadcastingRTMP = false
}
private def setRTMPBroadcastingUrl(path: String) {
rtmpBroadcastingUrl = path
}
private def getRTMPBroadcastingUrl(): String = {
rtmpBroadcastingUrl
}
private def isExtensionAllowed(): Boolean = extension.numExtensions < extension.maxExtensions
private def incNumExtension(): Int = {
if (extension.numExtensions < extension.maxExtensions) {

View File

@ -0,0 +1,25 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs.EjectUserFromVoiceCmdMsg
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.VoiceUsers
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.message.senders.MsgBuilder
trait EjectUserFromVoiceCmdMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleEjectUserRequest(msg: EjectUserFromVoiceCmdMsg) {
log.info("Received eject user request. meetingId=" + msg.header.meetingId + " userId=" + msg.body.userId)
for {
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
} yield {
log.info("Ejecting user from voice. meetingId=" + props.meetingProp.intId + " userId=" + u.intId)
val event = MsgBuilder.buildEjectUserFromVoiceConfSysMsg(props.meetingProp.intId, props.voiceProp.voiceConf, u.voiceUserId)
outGW.send(event)
}
}
}

View File

@ -1,26 +0,0 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ EjectUserFromVoiceRequest, EjectVoiceUser }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
trait EjectUserFromVoiceRequestHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleEjectUserRequest(msg: EjectUserFromVoiceRequest) {
log.info("Received eject user request. meetingId=" + msg.meetingID + " userId=" + msg.userId)
for {
u <- Users1x.findWithId(msg.userId, liveMeeting.users)
} yield {
if (u.voiceUser.joined) {
log.info("Ejecting user from voice. meetingId=" + props.meetingProp.intId + " userId=" + u.id)
outGW.send(new EjectVoiceUser(props.meetingProp.intId, props.recordProp.record, msg.ejectedBy, u.id,
props.voiceProp.voiceConf, u.voiceUser.userId))
}
}
}
}

View File

@ -0,0 +1,50 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait EndMeetingSysCmdMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleEndMeeting(msg: EndMeetingSysCmdMsg) {
endMeeting()
def endMeeting(): 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 header = BbbClientMsgHeader(MeetingEndingEvtMsg.NAME, meetingId, "not-used")
val event = MeetingEndingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val endingEvent = buildMeetingEndingEvtMsg(liveMeeting.props.meetingProp.intId)
// Broadcast users the meeting will end
outGW.send(endingEvent)
MeetingStatus2x.meetingHasEnded(liveMeeting.status)
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)
}
val endedEvnt = buildMeetingEndedEvtMsg(liveMeeting.props.meetingProp.intId)
outGW.send(endedEvnt)
}
}
}

View File

@ -1,24 +0,0 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ InitAudioSettings, MuteAllExceptPresenterRequest }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait InitAudioSettingsHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleInitAudioSettings(msg: InitAudioSettings) {
if (!MeetingStatus2x.audioSettingsInitialized(liveMeeting.status)) {
MeetingStatus2x.initializeAudioSettings(liveMeeting.status)
if (MeetingStatus2x.isMeetingMuted(liveMeeting.status) != msg.muted) {
handleMuteAllExceptPresenterRequest(
new MuteAllExceptPresenterRequest(props.meetingProp.intId,
msg.requesterID, msg.muted));
}
}
}
}

View File

@ -0,0 +1,29 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait IsMeetingMutedReqMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleIsMeetingMutedReqMsg(msg: IsMeetingMutedReqMsg) {
def build(meetingId: String, userId: String, muted: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, meetingId, userId)
val envelope = BbbCoreEnvelope(IsMeetingMutedRespMsg.NAME, routing)
val header = BbbClientMsgHeader(IsMeetingMutedRespMsg.NAME, meetingId, userId)
val body = IsMeetingMutedRespMsgBody(muted)
val event = IsMeetingMutedRespMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = build(liveMeeting.props.meetingProp.intId, msg.body.requesterId, MeetingStatus2x.isMeetingMuted(liveMeeting.status))
outGW.send(event)
}
}

View File

@ -1,17 +0,0 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ IsMeetingMutedReply, IsMeetingMutedRequest }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait IsMeetingMutedRequestHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleIsMeetingMutedRequest(msg: IsMeetingMutedRequest) {
outGW.send(new IsMeetingMutedReply(props.meetingProp.intId, props.recordProp.record,
msg.requesterID, MeetingStatus2x.isMeetingMuted(liveMeeting.status)))
}
}

View File

@ -1,56 +0,0 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ MeetingMuted, MuteAllExceptPresenterRequest, MuteVoiceUser }
import org.bigbluebutton.core.models.{ Users2x, VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait MuteAllExceptPresenterRequestHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleMuteAllExceptPresenterRequest(msg: MuteAllExceptPresenterRequest) {
if (msg.mute) {
MeetingStatus2x.muteMeeting(liveMeeting.status)
} else {
MeetingStatus2x.unmuteMeeting(liveMeeting.status)
}
outGW.send(new MeetingMuted(props.meetingProp.intId, props.recordProp.record,
MeetingStatus2x.isMeetingMuted(liveMeeting.status)))
usersWhoAreNotPresenter foreach { u =>
outGW.send(new MuteVoiceUser(props.meetingProp.intId, props.recordProp.record, msg.requesterID,
u.id, props.voiceProp.voiceConf, u.voiceUser.userId, msg.mute))
}
def muteUserInVoiceConf(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfMsg.NAME, props.meetingProp.intId)
val body = MuteUserInVoiceConfMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, true)
val event = MuteUserInVoiceConfMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
// I think the correct flow would be to find those who are presenters and exclude them
// from the list of voice users. The remaining, mute.
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (!vu.listenOnly) {
Users2x.findWithIntId(liveMeeting.users2x, vu.intId) match {
case Some(u) => if (!u.presenter) muteUserInVoiceConf(vu)
case None => muteUserInVoiceConf(vu)
}
}
}
}
}

View File

@ -0,0 +1,68 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ MeetingMuted, MuteVoiceUser }
import org.bigbluebutton.core.models.{ UserState, Users2x, VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait MuteAllExceptPresentersCmdMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleMuteAllExceptPresentersCmdMsg(msg: MuteAllExceptPresentersCmdMsg) {
if (MeetingStatus2x.isMeetingMuted(liveMeeting.status)) {
MeetingStatus2x.unmuteMeeting(liveMeeting.status)
} else {
MeetingStatus2x.muteMeeting(liveMeeting.status)
}
val muted = MeetingStatus2x.isMeetingMuted(liveMeeting.status)
val event = build(props.meetingProp.intId, msg.body.mutedBy, muted, msg.body.mutedBy)
outGW.send(event)
// I think the correct flow would be to find those who are presenters and exclude them
// from the list of voice users. The remaining, mute.
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (!vu.listenOnly) {
Users2x.findWithIntId(liveMeeting.users2x, vu.intId) match {
case Some(u) => if (!u.presenter) muteUserInVoiceConf(vu)
case None => muteUserInVoiceConf(vu)
}
}
}
}
def usersWhoAreNotPresenter(): Vector[UserState] = {
Users2x.findNotPresenters(liveMeeting.users2x)
}
def build(meetingId: String, userId: String, muted: Boolean, mutedBy: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(MeetingMutedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(MeetingMutedEvtMsg.NAME, meetingId, userId)
val body = MeetingMutedEvtMsgBody(muted, mutedBy)
val event = MeetingMutedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def muteUserInVoiceConf(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, props.meetingProp.intId)
val body = MuteUserInVoiceConfSysMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, true)
val event = MuteUserInVoiceConfSysMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
}

View File

@ -0,0 +1,61 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.{ VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait MuteMeetingCmdMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleMuteMeetingCmdMsg(msg: MuteMeetingCmdMsg) {
def build(meetingId: String, userId: String, muted: Boolean, mutedBy: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(MeetingMutedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(MeetingMutedEvtMsg.NAME, meetingId, userId)
val body = MeetingMutedEvtMsgBody(muted, mutedBy)
val event = MeetingMutedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def muteUserInVoiceConf(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, props.meetingProp.intId)
val body = MuteUserInVoiceConfSysMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, true)
val event = MuteUserInVoiceConfSysMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
if (MeetingStatus2x.isMeetingMuted(liveMeeting.status)) {
MeetingStatus2x.unmuteMeeting(liveMeeting.status)
} else {
MeetingStatus2x.muteMeeting(liveMeeting.status)
}
val muted = MeetingStatus2x.isMeetingMuted(liveMeeting.status)
val meetingMutedEvent = build(props.meetingProp.intId, msg.body.mutedBy, muted, msg.body.mutedBy)
outGW.send(meetingMutedEvent)
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { u =>
muteUserInVoiceConf(u)
}
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (!vu.listenOnly) {
muteUserInVoiceConf(vu)
}
}
}
}

View File

@ -1,49 +0,0 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ MeetingMuted, MuteMeetingRequest, MuteVoiceUser }
import org.bigbluebutton.core.models.{ Users1x, VoiceUserState, VoiceUsers }
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
trait MuteMeetingRequestHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleMuteMeetingRequest(msg: MuteMeetingRequest) {
if (msg.mute) {
MeetingStatus2x.muteMeeting(liveMeeting.status)
} else {
MeetingStatus2x.unmuteMeeting(liveMeeting.status)
}
outGW.send(new MeetingMuted(props.meetingProp.intId, props.recordProp.record,
MeetingStatus2x.isMeetingMuted(liveMeeting.status)))
Users1x.getUsers(liveMeeting.users) foreach { u =>
outGW.send(new MuteVoiceUser(props.meetingProp.intId, props.recordProp.record, msg.requesterID,
u.id, props.voiceProp.voiceConf, u.voiceUser.userId, msg.mute))
}
def muteUserInVoiceConf(vu: VoiceUserState): Unit = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, props.meetingProp.intId, vu.intId)
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfMsg.NAME, routing)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfMsg.NAME, props.meetingProp.intId)
val body = MuteUserInVoiceConfMsgBody(props.voiceProp.voiceConf, vu.voiceUserId, true)
val event = MuteUserInVoiceConfMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
outGW.send(msgEvent)
}
VoiceUsers.findAll(liveMeeting.voiceUsers) foreach { vu =>
if (!vu.listenOnly) {
muteUserInVoiceConf(vu)
}
}
}
}

View File

@ -1,8 +1,52 @@
package org.bigbluebutton.core2.message.handlers
/**
* Created by ritz on 2017-06-09.
*/
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait RecordingStartedVoiceConfEvtMsgHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleRecordingStartedVoiceConfEvtMsg(msg: RecordingStartedVoiceConfEvtMsg) {
if (msg.body.recording) {
MeetingStatus2x.setVoiceRecordingFilename(liveMeeting.status, msg.body.stream)
def buildVoiceRecordingStartedEvtMsg(meetingId: String, stream: String, timestamp: String, voiceConf: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(VoiceRecordingStartedEvtMsg.NAME, routing)
val body = VoiceRecordingStartedEvtMsgBody(meetingId, stream, timestamp, voiceConf)
val header = BbbCoreVoiceConfHeader(VoiceRecordingStartedEvtMsg.NAME, meetingId)
val event = VoiceRecordingStartedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildVoiceRecordingStartedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.stream,
msg.body.timestamp, liveMeeting.props.voiceProp.voiceConf)
outGW.send(event)
} else {
MeetingStatus2x.setVoiceRecordingFilename(liveMeeting.status, "")
def buildVoiceRecordingStoppedEvtMsg(meetingId: String, stream: String, timestamp: String, voiceConf: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(VoiceRecordingStoppedEvtMsg.NAME, routing)
val body = VoiceRecordingStoppedEvtMsgBody(meetingId, stream, timestamp, voiceConf)
val header = BbbCoreVoiceConfHeader(VoiceRecordingStoppedEvtMsg.NAME, meetingId)
val event = VoiceRecordingStoppedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildVoiceRecordingStoppedEvtMsg(liveMeeting.props.meetingProp.intId, msg.body.stream,
msg.body.timestamp, liveMeeting.props.voiceProp.voiceConf)
outGW.send(event)
}
}
}

View File

@ -0,0 +1,58 @@
package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ BreakoutRoomsTimeRemainingUpdateOutMessage, MeetingTimeRemainingUpdate, SendTimeRemainingUpdate }
import org.bigbluebutton.core.models.BreakoutRooms
import org.bigbluebutton.core.running.{ BaseMeetingActor, LiveMeeting }
import org.bigbluebutton.core2.MeetingStatus2x
trait SendTimeRemainingUpdateHdlr {
this: BaseMeetingActor =>
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handleSendTimeRemainingUpdate(msg: SendTimeRemainingUpdate) {
if (liveMeeting.props.durationProps.duration > 0) {
val endMeetingTime = MeetingStatus2x.startedOn(liveMeeting.status) + (liveMeeting.props.durationProps.duration * 60)
val timeRemaining = endMeetingTime - liveMeeting.timeNowInSeconds
def buildMeetingTimeRemainingUpdateEvtMsg(meetingId: String, timeLeftInSec: Long): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(MeetingTimeRemainingUpdateEvtMsg.NAME, routing)
val body = MeetingTimeRemainingUpdateEvtMsgBody(timeLeftInSec)
val header = BbbClientMsgHeader(MeetingTimeRemainingUpdateEvtMsg.NAME, meetingId, "not-used")
val event = MeetingTimeRemainingUpdateEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildMeetingTimeRemainingUpdateEvtMsg(liveMeeting.props.meetingProp.intId, timeRemaining.toInt)
outGW.send(event)
}
if (!liveMeeting.props.meetingProp.isBreakout && !BreakoutRooms.getRooms(liveMeeting.breakoutRooms).isEmpty) {
val endMeetingTime = BreakoutRooms.breakoutRoomsStartedOn(liveMeeting.breakoutRooms) +
(BreakoutRooms.breakoutRoomsdurationInMinutes(liveMeeting.breakoutRooms) * 60)
val timeRemaining = endMeetingTime - liveMeeting.timeNowInSeconds
def buildBreakoutRoomsTimeRemainingUpdateEvtMsg(meetingId: String, timeLeftInSec: Long): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, "not-used")
val envelope = BbbCoreEnvelope(BreakoutRoomsTimeRemainingUpdateEvtMsg.NAME, routing)
val body = BreakoutRoomsTimeRemainingUpdateEvtMsgBody(timeLeftInSec)
val header = BbbClientMsgHeader(BreakoutRoomsTimeRemainingUpdateEvtMsg.NAME, meetingId, "not-used")
val event = BreakoutRoomsTimeRemainingUpdateEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
val event = buildBreakoutRoomsTimeRemainingUpdateEvtMsg(liveMeeting.props.meetingProp.intId, timeRemaining.toInt)
outGW.send(event)
} else if (BreakoutRooms.breakoutRoomsStartedOn(liveMeeting.breakoutRooms) != 0) {
BreakoutRooms.breakoutRoomsdurationInMinutes(liveMeeting.breakoutRooms, 0)
BreakoutRooms.breakoutRoomsStartedOn(liveMeeting.breakoutRooms, 0)
}
}
}

View File

@ -2,7 +2,7 @@ package org.bigbluebutton.core2.message.handlers
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ NewPermissionsSetting, SetLockSettings }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x
@ -15,12 +15,13 @@ trait SetLockSettingsHdlr {
if (!liveMeeting.permissionsEqual(msg.settings)) {
liveMeeting.newPermissions(msg.settings)
/*
outGW.send(new NewPermissionsSetting(props.meetingProp.intId, msg.setByUser,
MeetingStatus2x.getPermissions(liveMeeting.status),
Users.getUsers(liveMeeting.users).toArray))
*/
// handleLockLayout(msg.settings.lockedLayout, msg.setByUser)
/**
* outGW.send(new NewPermissionsSetting(props.meetingProp.intId, msg.setByUser,
* MeetingStatus2x.getPermissions(liveMeeting.status),
* Users2x.findAll(liveMeeting.users2x))
*
* handleLockLayout(msg.settings.lockedLayout, msg.setByUser)
*/
}
}
}

View File

@ -12,7 +12,7 @@ trait GetGuestsWaitingApprovalReqMsgHdlr extends HandlerHelpers {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: GetGuestsWaitingApprovalReqMsg): Unit = {
def handleGetGuestsWaitingApprovalReqMsg(msg: GetGuestsWaitingApprovalReqMsg): Unit = {
val guests = GuestsWaiting.findAll(liveMeeting.guestsWaiting)
val event = MsgBuilder.buildGetGuestsWaitingApprovalRespMsg(
liveMeeting.props.meetingProp.intId,

View File

@ -12,7 +12,7 @@ trait GuestsWaitingApprovedMsgHdlr extends HandlerHelpers {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: GuestsWaitingApprovedMsg): Unit = {
def handleGuestsWaitingApprovedMsg(msg: GuestsWaitingApprovedMsg): Unit = {
msg.body.guests foreach { g =>
approveOrRejectGuest(g, msg.body.approvedBy)
}

View File

@ -12,7 +12,7 @@ trait SetGuestPolicyMsgHdlr {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: SetGuestPolicyMsg): Unit = {
def handleSetGuestPolicyMsg(msg: SetGuestPolicyMsg): Unit = {
val newPolicy = msg.body.policy.toUpperCase()
if (GuestPolicyType.policyTypes.contains(newPolicy)) {
val policy = GuestPolicy(newPolicy, msg.body.setBy)

View File

@ -1,12 +0,0 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.api.ChangeUserRole
import org.bigbluebutton.core.running.MeetingActor
trait ChangeUserRoleHdlr {
this: MeetingActor =>
def handle(msg: ChangeUserRole): Unit = {
usersApp2x.handle(msg)
}
}

View File

@ -1,21 +0,0 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ ChangeUserStatus, UserStatusChange }
import org.bigbluebutton.core.models.{ Users2x }
import org.bigbluebutton.core.running.MeetingActor
trait ChangeUserStatusHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleChangeUserStatus(msg: ChangeUserStatus): Unit = {
for {
u <- Users2x.findWithIntId(liveMeeting.users2x, msg.userID)
} yield {
outGW.send(new UserStatusChange(props.meetingProp.intId, props.recordProp.record, msg.userID, msg.status, msg.value))
}
}
}

View File

@ -1,27 +0,0 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api._
import org.bigbluebutton.core.models._
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core.util.Model1x2xConverter
trait EjectUserFromMeetingHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handle(msg: EjectUserFromMeeting) {
/*
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.userId)
} yield {
usersApp2x.handle(msg)
presentationApp2x.handle(msg, user)
pollApp2x.handle(msg, user)
deskshareApp2x.handle(msg, user)
}
*/
}
}

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ GetLockSettings, NewPermissionsSetting }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x

View File

@ -2,7 +2,6 @@ package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ InitLockSettings, PermissionsSettingInitialized }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.MeetingStatus2x

View File

@ -0,0 +1,33 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.models.Users2x
import org.bigbluebutton.core.running.MeetingActor
trait LockUserInMeetingCmdMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handle(msg: LockUserInMeetingCmdMsg) {
def build(meetingId: String, userId: String, lockedBy: String, locked: Boolean): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, meetingId, userId)
val envelope = BbbCoreEnvelope(UserLockedInMeetingEvtMsg.NAME, routing)
val body = UserLockedInMeetingEvtMsgBody(userId, locked, lockedBy)
val header = BbbClientMsgHeader(UserLockedInMeetingEvtMsg.NAME, meetingId, userId)
val event = UserLockedInMeetingEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
for {
uvo <- Users2x.setUserLocked(liveMeeting.users2x, msg.body.userId, msg.body.lock)
} yield {
log.info("Lock user. meetingId=" + props.meetingProp.intId + " userId=" + uvo.intId + " locked=" + uvo.locked)
val event = build(props.meetingProp.intId, uvo.intId, msg.body.lockedBy, uvo.locked)
outGW.send(event)
}
}
}

View File

@ -1,21 +0,0 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ LockUserRequest, UserLocked }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
trait LockUserRequestHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleLockUserRequest(msg: LockUserRequest) {
for {
uvo <- Users1x.lockUser(msg.userID, msg.lock, liveMeeting.users)
} yield {
log.info("Lock user. meetingId=" + props.meetingProp.intId + " userId=" + uvo.id + " locked=" + uvo.locked)
outGW.send(new UserLocked(props.meetingProp.intId, uvo.id, uvo.locked))
}
}
}

View File

@ -1,23 +1,27 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.common2.msgs.MuteUserCmdMsg
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ MuteUserRequest, MuteVoiceUser }
import org.bigbluebutton.core.models.{ Users1x, Users2x, VoiceUsers }
import org.bigbluebutton.core.models.VoiceUsers
import org.bigbluebutton.core.running.MeetingActor
import org.bigbluebutton.core2.message.senders.MsgBuilder
trait MuteUserRequestHdlr {
trait MuteUserCmdMsgHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleMuteUserRequest(msg: MuteUserRequest) {
log.info("Received mute user request. meetingId=" + props.meetingProp.intId + " userId=" + msg.userID + " mute=" + msg.mute)
def handleMuteUserCmdMsg(msg: MuteUserCmdMsg) {
log.info("Received mute user request. meetingId=" + props.meetingProp.intId + " userId="
+ msg.body.userId)
for {
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.userID)
u <- VoiceUsers.findWithIntId(liveMeeting.voiceUsers, msg.body.userId)
} yield {
log.info("Send mute user request. meetingId=" + props.meetingProp.intId + " userId=" + u.intId + " user=" + u)
outGW.send(new MuteVoiceUser(props.meetingProp.intId, props.recordProp.record,
msg.requesterID, u.intId, props.voiceProp.voiceConf, u.voiceUserId, msg.mute))
val event = MsgBuilder.buildMuteUserInVoiceConfSysMsg(props.meetingProp.intId, props.voiceProp.voiceConf,
u.voiceUserId, !u.muted)
outGW.send(event)
}
}
}

View File

@ -2,8 +2,8 @@ package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ UserChangedEmojiStatus, UserEmojiStatus }
import org.bigbluebutton.core.models.{ Users1x, Users2x }
import org.bigbluebutton.core.api.{ UserEmojiStatus }
import org.bigbluebutton.core.models.{ Users2x }
import org.bigbluebutton.core.running.MeetingActor
trait UserEmojiStatusHdlr {

View File

@ -10,7 +10,7 @@ trait UserJoinMeetingReqMsgHdlr extends HandlerHelpers {
val liveMeeting: LiveMeeting
val outGW: OutMessageGateway
def handle(msg: UserJoinMeetingReqMsg): Unit = {
def handleUserJoinMeetingReqMsg(msg: UserJoinMeetingReqMsg): Unit = {
userJoinMeeting(outGW, msg.body.authToken, liveMeeting)
}

View File

@ -1,22 +0,0 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ UserShareWebcam, UserSharedWebcam }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
trait UserShareWebcamHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleUserShareWebcam(msg: UserShareWebcam) {
for {
uvo <- Users1x.userSharedWebcam(msg.userId, liveMeeting.users, msg.stream)
} yield {
log.info("User shared webcam. meetingId=" + props.meetingProp.intId + " userId=" + uvo.id + " stream=" + msg.stream)
outGW.send(new UserSharedWebcam(props.meetingProp.intId, props.recordProp.record, uvo.id, msg.stream))
}
}
}

View File

@ -1,21 +0,0 @@
package org.bigbluebutton.core2.message.handlers.users
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ UserUnshareWebcam, UserUnsharedWebcam }
import org.bigbluebutton.core.models.Users1x
import org.bigbluebutton.core.running.MeetingActor
trait UserUnshareWebcamHdlr {
this: MeetingActor =>
val outGW: OutMessageGateway
def handleUserunshareWebcam(msg: UserUnshareWebcam) {
for {
uvo <- Users1x.userUnsharedWebcam(msg.userId, liveMeeting.users, msg.stream)
} yield {
log.info("User unshared webcam. meetingId=" + props.meetingProp.intId + " userId=" + uvo.id + " stream=" + msg.stream)
outGW.send(new UserUnsharedWebcam(props.meetingProp.intId, props.recordProp.record, uvo.id, msg.stream))
}
}
}

View File

@ -1,5 +1,6 @@
package org.bigbluebutton.core2.message.senders
import org.bigbluebutton.common2.domain.DefaultProps
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models.GuestWaiting
@ -115,4 +116,83 @@ object MsgBuilder {
BbbCommonEnvCoreMsg(envelope, event)
}
def buildMeetingCreatedEvtMsg(meetingId: String, props: DefaultProps): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(MeetingCreatedEvtMsg.NAME, routing)
val header = BbbCoreBaseHeader(MeetingCreatedEvtMsg.NAME)
val body = MeetingCreatedEvtBody(props)
val event = MeetingCreatedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildMeetingDestroyedEvtMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(MeetingDestroyedEvtMsg.NAME, routing)
val body = MeetingDestroyedEvtMsgBody(meetingId)
val header = BbbCoreBaseHeader(MeetingDestroyedEvtMsg.NAME)
val event = MeetingDestroyedEvtMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildEndAndKickAllSysMsg(meetingId: String, userId: String): BbbCommonEnvCoreMsg = {
val routing = Routing.addMsgToClientRouting(MessageTypes.SYSTEM, meetingId, userId)
val envelope = BbbCoreEnvelope(EndAndKickAllSysMsg.NAME, routing)
val body = EndAndKickAllSysMsgBody(meetingId)
val header = BbbCoreHeaderWithMeetingId(EndAndKickAllSysMsg.NAME, meetingId)
val event = EndAndKickAllSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildDisconnectAllClientsSysMsg(meetingId: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(DisconnectAllClientsSysMsg.NAME, routing)
val body = DisconnectAllClientsSysMsgBody(meetingId)
val header = BbbCoreHeaderWithMeetingId(DisconnectAllClientsSysMsg.NAME, meetingId)
val event = DisconnectAllClientsSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
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)
}
def buildPubSubPongSysRespMsg(system: String, timestamp: Long): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(PubSubPongSysRespMsg.NAME, routing)
val body = PubSubPongSysRespMsgBody(system, timestamp)
val header = BbbCoreBaseHeader(PubSubPongSysRespMsg.NAME)
val event = PubSubPongSysRespMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildEjectUserFromVoiceConfSysMsg(meetingId: String, voiceConf: String, voiceUserId: String): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(EjectUserFromVoiceConfSysMsg.NAME, routing)
val body = EjectUserFromVoiceConfSysMsgBody(voiceConf, voiceUserId)
val header = BbbCoreHeaderWithMeetingId(EjectUserFromVoiceConfSysMsg.NAME, meetingId)
val event = EjectUserFromVoiceConfSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
def buildMuteUserInVoiceConfSysMsg(meetingId: String, voiceConf: String, voiceUserId: String, mute: Boolean): BbbCommonEnvCoreMsg = {
val routing = collection.immutable.HashMap("sender" -> "bbb-apps-akka")
val envelope = BbbCoreEnvelope(MuteUserInVoiceConfSysMsg.NAME, routing)
val body = MuteUserInVoiceConfSysMsgBody(voiceConf, voiceUserId, mute)
val header = BbbCoreHeaderWithMeetingId(MuteUserInVoiceConfSysMsg.NAME, meetingId)
val event = MuteUserInVoiceConfSysMsg(header, body)
BbbCommonEnvCoreMsg(envelope, event)
}
}

View File

@ -1,28 +0,0 @@
package org.bigbluebutton.core2.message.senders
import org.bigbluebutton.core.OutMessageGateway
import org.bigbluebutton.core.api.{ DisconnectUser, EjectVoiceUser, UserEjectedFromMeeting, UserLeft }
import org.bigbluebutton.core.running.LiveMeeting
import org.bigbluebutton.common2.domain.UserVO
trait MsgSenders1x {
val outGW: OutMessageGateway
val liveMeeting: LiveMeeting
def sendEjectVoiceUser(intId: String, ejectedBy: String, voiceUserId: String): Unit = {
outGW.send(new EjectVoiceUser(liveMeeting.props.meetingProp.intId, liveMeeting.props.recordProp.record,
ejectedBy, intId, liveMeeting.props.voiceProp.voiceConf, voiceUserId))
}
def sendUserEjectedFromMeeting(intId: String, ejectedBy: String): Unit = {
outGW.send(new UserEjectedFromMeeting(liveMeeting.props.meetingProp.intId, liveMeeting.props.recordProp.record, intId, ejectedBy))
}
def sendDisconnectUser(intId: String): Unit = {
outGW.send(new DisconnectUser(liveMeeting.props.meetingProp.intId, intId))
}
def sendUserLeft(user: UserVO): Unit = {
outGW.send(new UserLeft(liveMeeting.props.meetingProp.intId, liveMeeting.props.recordProp.record, user))
}
}

View File

@ -51,7 +51,7 @@ class AppsRedisSubscriberActor(msgReceiver: RedisMessageReceiver, jsonMsgBus: In
//log.error(s"SHOULD NOT BE RECEIVING: $message")
if (message.channel == toAkkaAppsRedisChannel || message.channel == fromVoiceConfRedisChannel) {
val receivedJsonMessage = new ReceivedJsonMessage(message.channel, message.data.utf8String)
log.debug(s"RECEIVED:\n [${receivedJsonMessage.channel}] \n ${receivedJsonMessage.data} \n")
// log.debug(s"RECEIVED:\n [${receivedJsonMessage.channel}] \n ${receivedJsonMessage.data} \n")
jsonMsgBus.publish(IncomingJsonMessage(toAkkaAppsJsonChannel, receivedJsonMessage))
}
}

View File

@ -38,8 +38,8 @@ class RedisRecorderActor(val system: ActorSystem)
}
def receive = {
case msg: SendPublicMessageEvent => handleSendPublicMessageEvent(msg)
case msg: ClearPublicChatHistoryReply => handleClearPublicChatHistoryReply(msg)
//case msg: SendPublicMessageEvent => handleSendPublicMessageEvent(msg)
//case msg: ClearPublicChatHistoryReply => handleClearPublicChatHistoryReply(msg)
case msg: ClearPresentationOutMsg => handleClearPresentationOutMsg(msg)
case msg: RemovePresentationOutMsg => handleRemovePresentationOutMsg(msg)
case msg: ResizeAndMoveSlideOutMsg => handleResizeAndMoveSlideOutMsg(msg)
@ -71,7 +71,7 @@ class RedisRecorderActor(val system: ActorSystem)
case _ => // do nothing
}
private def handleSendPublicMessageEvent(msg: SendPublicMessageEvent) {
/* private def handleSendPublicMessageEvent(msg: SendPublicMessageEvent) {
if (msg.recorded) {
val message = JavaConverters.mapAsJavaMap(msg.message)
val ev = new PublicChatRecordEvent()
@ -85,16 +85,16 @@ class RedisRecorderActor(val system: ActorSystem)
record(msg.meetingID, JavaConverters.mapAsScalaMap(ev.toMap).toMap)
}
}
}*/
private def handleClearPublicChatHistoryReply(msg: ClearPublicChatHistoryReply) {
/* private def handleClearPublicChatHistoryReply(msg: ClearPublicChatHistoryReply) {
if (msg.recorded) {
val ev = new ClearPublicChatRecordEvent()
ev.setTimestamp(TimestampGenerator.generateTimestamp())
ev.setMeetingId(msg.meetingID)
record(msg.meetingID, JavaConverters.mapAsScalaMap(ev.toMap).toMap)
}
}
}*/
private def handleClearPresentationOutMsg(msg: ClearPresentationOutMsg) {

View File

@ -28,10 +28,10 @@ trait RxJsonMsgDeserializer {
}
def routeEjectUserFromVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
def deserialize(jsonNode: JsonNode): Option[EjectUserFromVoiceConfMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[EjectUserFromVoiceConfMsg](jsonNode)
def deserialize(jsonNode: JsonNode): Option[EjectUserFromVoiceConfSysMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[EjectUserFromVoiceConfSysMsg](jsonNode)
result match {
case Some(msg) => Some(msg.asInstanceOf[EjectUserFromVoiceConfMsg])
case Some(msg) => Some(msg.asInstanceOf[EjectUserFromVoiceConfSysMsg])
case None =>
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
None
@ -46,10 +46,10 @@ trait RxJsonMsgDeserializer {
}
def routeMuteUserInVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
def deserialize(jsonNode: JsonNode): Option[MuteUserInVoiceConfMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[MuteUserInVoiceConfMsg](jsonNode)
def deserialize(jsonNode: JsonNode): Option[MuteUserInVoiceConfSysMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[MuteUserInVoiceConfSysMsg](jsonNode)
result match {
case Some(msg) => Some(msg.asInstanceOf[MuteUserInVoiceConfMsg])
case Some(msg) => Some(msg.asInstanceOf[MuteUserInVoiceConfSysMsg])
case None =>
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
None
@ -64,10 +64,10 @@ trait RxJsonMsgDeserializer {
}
def routeTransferUserToVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
def deserialize(jsonNode: JsonNode): Option[TransferUserToVoiceConfMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[TransferUserToVoiceConfMsg](jsonNode)
def deserialize(jsonNode: JsonNode): Option[TransferUserToVoiceConfSysMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[TransferUserToVoiceConfSysMsg](jsonNode)
result match {
case Some(msg) => Some(msg.asInstanceOf[TransferUserToVoiceConfMsg])
case Some(msg) => Some(msg.asInstanceOf[TransferUserToVoiceConfSysMsg])
case None =>
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
None
@ -82,10 +82,10 @@ trait RxJsonMsgDeserializer {
}
def routeStartRecordingVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
def deserialize(jsonNode: JsonNode): Option[StartRecordingVoiceConfMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[StartRecordingVoiceConfMsg](jsonNode)
def deserialize(jsonNode: JsonNode): Option[StartRecordingVoiceConfSysMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[StartRecordingVoiceConfSysMsg](jsonNode)
result match {
case Some(msg) => Some(msg.asInstanceOf[StartRecordingVoiceConfMsg])
case Some(msg) => Some(msg.asInstanceOf[StartRecordingVoiceConfSysMsg])
case None =>
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
None
@ -100,10 +100,10 @@ trait RxJsonMsgDeserializer {
}
def routeStopRecordingVoiceConfMsg(envelope: BbbCoreEnvelope, jsonNode: JsonNode): Unit = {
def deserialize(jsonNode: JsonNode): Option[StopRecordingVoiceConfMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[StopRecordingVoiceConfMsg](jsonNode)
def deserialize(jsonNode: JsonNode): Option[StopRecordingVoiceConfSysMsg] = {
val (result, error) = JsonDeserializer.toBbbCommonMsg[StopRecordingVoiceConfSysMsg](jsonNode)
result match {
case Some(msg) => Some(msg.asInstanceOf[StopRecordingVoiceConfMsg])
case Some(msg) => Some(msg.asInstanceOf[StopRecordingVoiceConfSysMsg])
case None =>
log.error("Failed to deserialize message: error: {} \n msg: {}", error, jsonNode)
None

View File

@ -32,15 +32,15 @@ class RxJsonMsgHdlrActor(val fsApp: FreeswitchApplication) extends Actor with Ac
envelope.name match {
case EjectAllFromVoiceConfMsg.NAME =>
routeEjectAllFromVoiceConfMsg(envelope, jsonNode)
case EjectUserFromVoiceConfMsg.NAME =>
case EjectUserFromVoiceConfSysMsg.NAME =>
routeEjectUserFromVoiceConfMsg(envelope, jsonNode)
case MuteUserInVoiceConfMsg.NAME =>
case MuteUserInVoiceConfSysMsg.NAME =>
routeMuteUserInVoiceConfMsg(envelope, jsonNode)
case TransferUserToVoiceConfMsg.NAME =>
case TransferUserToVoiceConfSysMsg.NAME =>
routeTransferUserToVoiceConfMsg(envelope, jsonNode)
case StartRecordingVoiceConfMsg.NAME =>
case StartRecordingVoiceConfSysMsg.NAME =>
routeStartRecordingVoiceConfMsg(envelope, jsonNode)
case StopRecordingVoiceConfMsg.NAME =>
case StopRecordingVoiceConfSysMsg.NAME =>
routeStopRecordingVoiceConfMsg(envelope, jsonNode)
case _ => // do nothing
}

Some files were not shown because too many files have changed in this diff Show More