Merge branch 'bbb-2x-mconf' of github.com:bigbluebutton/bigbluebutton into implement-bbb-web-msgs
This commit is contained in:
commit
35b87ee069
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
|
||||
}
|
@ -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 = {
|
||||
|
||||
}
|
||||
}
|
@ -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]()
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
115
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/DeskshareModel.scala
Executable file
115
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/DeskshareModel.scala
Executable 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
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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))
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
@ -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)))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 = {
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -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
|
||||
|
2
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/AssignPresenterReqMsgHdlr.scala
Normal file → Executable file
2
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/AssignPresenterReqMsgHdlr.scala
Normal file → Executable 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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
4
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SyncGetUsersMeetingRespMsgHdlr.scala
Normal file → Executable file
4
akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/users/SyncGetUsersMeetingRespMsgHdlr.scala
Normal file → Executable 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 = {
|
||||
|
@ -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 {
|
@ -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 =>
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 =>
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
*/
|
@ -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"
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)))
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user