Merge branch 'v2.6.x-release' into fix-warnings-on-create

This commit is contained in:
André Castro 2023-04-13 11:27:50 -03:00 committed by GitHub
commit e00a258d0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
413 changed files with 1801 additions and 1294 deletions

View File

@ -14,6 +14,7 @@ import org.bigbluebutton.SystemConfiguration
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.running.RunningMeeting import org.bigbluebutton.core.running.RunningMeeting
import org.bigbluebutton.core.util.ColorPicker
import org.bigbluebutton.core2.RunningMeetings import org.bigbluebutton.core2.RunningMeetings
import org.bigbluebutton.core2.message.senders.MsgBuilder import org.bigbluebutton.core2.message.senders.MsgBuilder
import org.bigbluebutton.service.HealthzService import org.bigbluebutton.service.HealthzService
@ -183,6 +184,9 @@ class BigBlueButtonActor(
// Stop the meeting actor. // Stop the meeting actor.
context.stop(m.actorRef) context.stop(m.actorRef)
} }
//Remove ColorPicker idx of the meeting
ColorPicker.reset(m.props.meetingProp.intId)
} }
} }

View File

@ -0,0 +1,42 @@
package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.apps.RightsManagementTrait
import org.bigbluebutton.core.models.{ UserState, Users2x }
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
trait ChangeUserMobileFlagReqMsgHdlr extends RightsManagementTrait {
this: UsersApp =>
val liveMeeting: LiveMeeting
val outGW: OutMsgRouter
def handleChangeUserMobileFlagReqMsg(msg: ChangeUserMobileFlagReqMsg): Unit = {
log.info("handleChangeUserMobileFlagReqMsg: mobile={} userId={}", msg.body.mobile, msg.body.userId)
def broadcastUserMobileChanged(user: UserState, mobile: Boolean): Unit = {
val routingChange = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, user.intId
)
val envelopeChange = BbbCoreEnvelope(UserMobileFlagChangedEvtMsg.NAME, routingChange)
val headerChange = BbbClientMsgHeader(UserMobileFlagChangedEvtMsg.NAME, liveMeeting.props.meetingProp.intId,
user.intId)
val bodyChange = UserMobileFlagChangedEvtMsgBody(user.intId, mobile)
val eventChange = UserMobileFlagChangedEvtMsg(headerChange, bodyChange)
val msgEventChange = BbbCommonEnvCoreMsg(envelopeChange, eventChange)
outGW.send(msgEventChange)
}
for {
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.body.userId)
} yield {
if (user.mobile != msg.body.mobile) {
val userMobile = Users2x.setMobile(liveMeeting.users2x, user)
broadcastUserMobileChanged(userMobile, msg.body.mobile)
}
}
}
}

View File

@ -3,6 +3,7 @@ package org.bigbluebutton.core.apps.users
import org.bigbluebutton.common2.msgs._ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.models._ import org.bigbluebutton.core.models._
import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter } import org.bigbluebutton.core.running.{ LiveMeeting, OutMsgRouter }
import org.bigbluebutton.core.util.ColorPicker
import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender } import org.bigbluebutton.core2.message.senders.{ MsgBuilder, Sender }
trait RegisterUserReqMsgHdlr { trait RegisterUserReqMsgHdlr {
@ -56,7 +57,7 @@ trait RegisterUserReqMsgHdlr {
val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId, val regUser = RegisteredUsers.create(msg.body.intUserId, msg.body.extUserId,
msg.body.name, msg.body.role, msg.body.authToken, msg.body.name, msg.body.role, msg.body.authToken,
msg.body.avatarURL, msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false) msg.body.avatarURL, ColorPicker.nextColor(liveMeeting.props.meetingProp.intId), msg.body.guest, msg.body.authed, guestStatus, msg.body.excludeFromDashboard, false)
checkUserConcurrentAccesses(regUser) checkUserConcurrentAccesses(regUser)
@ -89,7 +90,7 @@ trait RegisterUserReqMsgHdlr {
val g = GuestApprovedVO(regUser.id, GuestStatus.ALLOW) val g = GuestApprovedVO(regUser.id, GuestStatus.ALLOW)
UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID) UsersApp.approveOrRejectGuest(liveMeeting, outGW, g, SystemUser.ID)
case GuestStatus.WAIT => case GuestStatus.WAIT =>
val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.authed, regUser.registeredOn) val guest = GuestWaiting(regUser.id, regUser.name, regUser.role, regUser.guest, regUser.avatarURL, regUser.color, regUser.authed, regUser.registeredOn)
addGuestToWaitingForApproval(guest, liveMeeting.guestsWaiting) addGuestToWaitingForApproval(guest, liveMeeting.guestsWaiting)
notifyModeratorsOfGuestWaiting(Vector(guest), liveMeeting.users2x, liveMeeting.props.meetingProp.intId) notifyModeratorsOfGuestWaiting(Vector(guest), liveMeeting.users2x, liveMeeting.props.meetingProp.intId)
val notifyEvent = MsgBuilder.buildNotifyRoleInMeetingEvtMsg( val notifyEvent = MsgBuilder.buildNotifyRoleInMeetingEvtMsg(

View File

@ -158,6 +158,7 @@ class UsersApp(
with SelectRandomViewerReqMsgHdlr with SelectRandomViewerReqMsgHdlr
with AssignPresenterReqMsgHdlr with AssignPresenterReqMsgHdlr
with ChangeUserPinStateReqMsgHdlr with ChangeUserPinStateReqMsgHdlr
with ChangeUserMobileFlagReqMsgHdlr
with EjectUserFromMeetingCmdMsgHdlr with EjectUserFromMeetingCmdMsgHdlr
with EjectUserFromMeetingSysMsgHdlr with EjectUserFromMeetingSysMsgHdlr
with MuteUserCmdMsgHdlr { with MuteUserCmdMsgHdlr {

View File

@ -5,7 +5,7 @@ import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter } import org.bigbluebutton.core.running.{ LiveMeeting, MeetingActor, OutMsgRouter }
import org.bigbluebutton.core2.message.senders.MsgBuilder import org.bigbluebutton.core2.message.senders.MsgBuilder
import org.bigbluebutton.core.models._ import org.bigbluebutton.core.models._
import org.bigbluebutton.core.apps.users.UsersApp import org.bigbluebutton.core.util.ColorPicker
import org.bigbluebutton.core2.MeetingStatus2x import org.bigbluebutton.core2.MeetingStatus2x
trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration { trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
@ -19,6 +19,8 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
val guestPolicy = GuestsWaiting.getGuestPolicy(liveMeeting.guestsWaiting) val guestPolicy = GuestsWaiting.getGuestPolicy(liveMeeting.guestsWaiting)
val isDialInUser = msg.body.intId.startsWith(IntIdPrefixType.DIAL_IN) val isDialInUser = msg.body.intId.startsWith(IntIdPrefixType.DIAL_IN)
val userColor = ColorPicker.nextColor(liveMeeting.props.meetingProp.intId)
def notifyModeratorsOfGuestWaiting(guest: GuestWaiting, users: Users2x, meetingId: String): Unit = { def notifyModeratorsOfGuestWaiting(guest: GuestWaiting, users: Users2x, meetingId: String): Unit = {
val moderators = Users2x.findAll(users).filter(p => p.role == Roles.MODERATOR_ROLE) val moderators = Users2x.findAll(users).filter(p => p.role == Roles.MODERATOR_ROLE)
moderators foreach { mod => moderators foreach { mod =>
@ -32,7 +34,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
def registerUserInRegisteredUsers() = { def registerUserInRegisteredUsers() = {
val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId, val regUser = RegisteredUsers.create(msg.body.intId, msg.body.voiceUserId,
msg.body.callerIdName, Roles.VIEWER_ROLE, "", msg.body.callerIdName, Roles.VIEWER_ROLE, "", userColor,
"", true, true, GuestStatus.WAIT, true, false) "", true, true, GuestStatus.WAIT, true, false)
RegisteredUsers.add(liveMeeting.registeredUsers, regUser) RegisteredUsers.add(liveMeeting.registeredUsers, regUser)
} }
@ -48,9 +50,11 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
guestStatus = GuestStatus.WAIT, guestStatus = GuestStatus.WAIT,
emoji = "none", emoji = "none",
pin = false, pin = false,
mobile = false,
presenter = false, presenter = false,
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin, locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
avatar = "", avatar = "",
color = userColor,
clientType = "", clientType = "",
pickExempted = false, pickExempted = false,
userLeftFlag = UserLeftFlag(false, 0) userLeftFlag = UserLeftFlag(false, 0)
@ -60,7 +64,7 @@ trait UserJoinedVoiceConfEvtMsgHdlr extends SystemConfiguration {
def registerUserAsGuest() = { def registerUserAsGuest() = {
if (GuestsWaiting.findWithIntId(liveMeeting.guestsWaiting, msg.body.intId) == None) { if (GuestsWaiting.findWithIntId(liveMeeting.guestsWaiting, msg.body.intId) == None) {
val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", true, System.currentTimeMillis()) val guest = GuestWaiting(msg.body.intId, msg.body.callerIdName, Roles.VIEWER_ROLE, true, "", userColor, true, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guest) GuestsWaiting.add(liveMeeting.guestsWaiting, guest)
notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId) notifyModeratorsOfGuestWaiting(guest, liveMeeting.users2x, liveMeeting.props.meetingProp.intId)

View File

@ -68,7 +68,7 @@ class GuestsWaiting {
} }
} }
case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, authenticated: Boolean, registeredOn: Long) case class GuestWaiting(intId: String, name: String, role: String, guest: Boolean, avatar: String, color: String, authenticated: Boolean, registeredOn: Long)
case class GuestPolicy(policy: String, setBy: String) case class GuestPolicy(policy: String, setBy: String)
object GuestPolicyType { object GuestPolicyType {

View File

@ -5,7 +5,7 @@ import org.bigbluebutton.core.domain.BreakoutRoom2x
object RegisteredUsers { object RegisteredUsers {
def create(userId: String, extId: String, name: String, roles: String, def create(userId: String, extId: String, name: String, roles: String,
token: String, avatar: String, guest: Boolean, authenticated: Boolean, token: String, avatar: String, color: String, guest: Boolean, authenticated: Boolean,
guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = { guestStatus: String, excludeFromDashboard: Boolean, loggedOut: Boolean): RegisteredUser = {
new RegisteredUser( new RegisteredUser(
userId, userId,
@ -14,6 +14,7 @@ object RegisteredUsers {
roles, roles,
token, token,
avatar, avatar,
color,
guest, guest,
authenticated, authenticated,
guestStatus, guestStatus,
@ -191,6 +192,7 @@ case class RegisteredUser(
role: String, role: String,
authToken: String, authToken: String,
avatarURL: String, avatarURL: String,
color: String,
guest: Boolean, guest: Boolean,
authed: Boolean, authed: Boolean,
guestStatus: String, guestStatus: String,

View File

@ -107,6 +107,12 @@ object Users2x {
newUserState newUserState
} }
def setMobile(users: Users2x, u: UserState): UserState = {
val newUserState = modify(u)(_.mobile).setTo(true)
users.save(newUserState)
newUserState
}
def ejectFromMeeting(users: Users2x, intId: String): Option[UserState] = { def ejectFromMeeting(users: Users2x, intId: String): Option[UserState] = {
for { for {
_ <- users.remove(intId) _ <- users.remove(intId)
@ -354,12 +360,14 @@ case class UserState(
role: String, role: String,
guest: Boolean, guest: Boolean,
pin: Boolean, pin: Boolean,
mobile: Boolean,
authed: Boolean, authed: Boolean,
guestStatus: String, guestStatus: String,
emoji: String, emoji: String,
locked: Boolean, locked: Boolean,
presenter: Boolean, presenter: Boolean,
avatar: String, avatar: String,
color: String,
roleChangedOn: Long = System.currentTimeMillis(), roleChangedOn: Long = System.currentTimeMillis(),
lastActivityTime: Long = System.currentTimeMillis(), lastActivityTime: Long = System.currentTimeMillis(),
lastInactivityInspect: Long = 0, lastInactivityInspect: Long = 0,

View File

@ -109,6 +109,8 @@ class ReceivedJsonMsgHandlerActor(
routeGenericMsg[UserActivitySignCmdMsg](envelope, jsonNode) routeGenericMsg[UserActivitySignCmdMsg](envelope, jsonNode)
case ChangeUserPinStateReqMsg.NAME => case ChangeUserPinStateReqMsg.NAME =>
routeGenericMsg[ChangeUserPinStateReqMsg](envelope, jsonNode) routeGenericMsg[ChangeUserPinStateReqMsg](envelope, jsonNode)
case ChangeUserMobileFlagReqMsg.NAME =>
routeGenericMsg[ChangeUserMobileFlagReqMsg](envelope, jsonNode)
case SelectRandomViewerReqMsg.NAME => case SelectRandomViewerReqMsg.NAME =>
routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode) routeGenericMsg[SelectRandomViewerReqMsg](envelope, jsonNode)

View File

@ -63,9 +63,11 @@ trait HandlerHelpers extends SystemConfiguration {
guestStatus = regUser.guestStatus, guestStatus = regUser.guestStatus,
emoji = "none", emoji = "none",
pin = false, pin = false,
mobile = false,
presenter = false, presenter = false,
locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin, locked = MeetingStatus2x.getPermissions(liveMeeting.status).lockOnJoin,
avatar = regUser.avatarURL, avatar = regUser.avatarURL,
color = regUser.color,
clientType = clientType, clientType = clientType,
pickExempted = false, pickExempted = false,
userLeftFlag = UserLeftFlag(false, 0) userLeftFlag = UserLeftFlag(false, 0)

View File

@ -384,10 +384,11 @@ class MeetingActor(
case m: RecordAndClearPreviousMarkersCmdMsg => case m: RecordAndClearPreviousMarkersCmdMsg =>
state = usersApp.handleRecordAndClearPreviousMarkersCmdMsg(m, state) state = usersApp.handleRecordAndClearPreviousMarkersCmdMsg(m, state)
updateUserLastActivity(m.body.setBy) updateUserLastActivity(m.body.setBy)
case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m) case m: GetRecordingStatusReqMsg => usersApp.handleGetRecordingStatusReqMsg(m)
case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m) case m: ChangeUserEmojiCmdMsg => handleChangeUserEmojiCmdMsg(m)
case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m) case m: SelectRandomViewerReqMsg => usersApp.handleSelectRandomViewerReqMsg(m)
case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m) case m: ChangeUserPinStateReqMsg => usersApp.handleChangeUserPinStateReqMsg(m)
case m: ChangeUserMobileFlagReqMsg => usersApp.handleChangeUserMobileFlagReqMsg(m)
// Client requested to eject user // Client requested to eject user
case m: EjectUserFromMeetingCmdMsg => case m: EjectUserFromMeetingCmdMsg =>

View File

@ -0,0 +1,19 @@
package org.bigbluebutton.core.util
object ColorPicker {
private val colors = List("#7b1fa2", "#6a1b9a", "#4a148c", "#5e35b1", "#512da8", "#4527a0", "#311b92",
"#3949ab", "#303f9f", "#283593", "#1a237e", "#1976d2", "#1565c0", "#0d47a1", "#0277bd", "#01579b")
private var meetingCurrIdx: Map[String, Int] = Map()
def nextColor(meetingId: String): String = {
val currentIdx = meetingCurrIdx.getOrElse(meetingId, 0)
val color = colors(currentIdx)
meetingCurrIdx += meetingId -> (currentIdx + 1) % colors.length
color
}
def reset(meetingId: String): Unit = {
meetingCurrIdx -= meetingId
}
}

View File

@ -13,5 +13,6 @@ object RandomStringGenerator {
// Generate a random alphabnumeric string of length n // Generate a random alphabnumeric string of length n
def randomAlphanumericString(n: Int) = def randomAlphanumericString(n: Int) =
randomString("abcdefghijklmnopqrstuvwxyz0123456789")(n) randomString("abcdefghijklmnopqrstuvwxyz0123456789")(n)
} }

View File

@ -77,6 +77,7 @@ class AnalyticsActor(val includeChat: Boolean) extends Actor with ActorLogging {
case m: UserDisconnectedFromGlobalAudioMsg => logMessage(msg) case m: UserDisconnectedFromGlobalAudioMsg => logMessage(msg)
case m: AssignPresenterReqMsg => logMessage(msg) case m: AssignPresenterReqMsg => logMessage(msg)
case m: ChangeUserPinStateReqMsg => logMessage(msg) case m: ChangeUserPinStateReqMsg => logMessage(msg)
case m: ChangeUserMobileFlagReqMsg => logMessage(msg)
case m: ScreenshareRtmpBroadcastStartedVoiceConfEvtMsg => logMessage(msg) case m: ScreenshareRtmpBroadcastStartedVoiceConfEvtMsg => logMessage(msg)
case m: ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsg => logMessage(msg) case m: ScreenshareRtmpBroadcastStoppedVoiceConfEvtMsg => logMessage(msg)
case m: ScreenshareRtmpBroadcastStartedEvtMsg => logMessage(msg) case m: ScreenshareRtmpBroadcastStartedEvtMsg => logMessage(msg)

View File

@ -78,7 +78,7 @@ object MsgBuilder {
val envelope = BbbCoreEnvelope(GetGuestsWaitingApprovalRespMsg.NAME, routing) val envelope = BbbCoreEnvelope(GetGuestsWaitingApprovalRespMsg.NAME, routing)
val header = BbbClientMsgHeader(GetGuestsWaitingApprovalRespMsg.NAME, meetingId, userId) val header = BbbClientMsgHeader(GetGuestsWaitingApprovalRespMsg.NAME, meetingId, userId)
val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.avatar, g.authenticated, g.registeredOn)) val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.avatar, g.color, g.authenticated, g.registeredOn))
val body = GetGuestsWaitingApprovalRespMsgBody(guestsWaiting) val body = GetGuestsWaitingApprovalRespMsgBody(guestsWaiting)
val event = GetGuestsWaitingApprovalRespMsg(header, body) val event = GetGuestsWaitingApprovalRespMsg(header, body)
@ -90,7 +90,7 @@ object MsgBuilder {
val envelope = BbbCoreEnvelope(GuestsWaitingForApprovalEvtMsg.NAME, routing) val envelope = BbbCoreEnvelope(GuestsWaitingForApprovalEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(GuestsWaitingForApprovalEvtMsg.NAME, meetingId, userId) val header = BbbClientMsgHeader(GuestsWaitingForApprovalEvtMsg.NAME, meetingId, userId)
val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.avatar, g.authenticated, g.registeredOn)) val guestsWaiting = guests.map(g => GuestWaitingVO(g.intId, g.name, g.role, g.guest, g.avatar, g.color, g.authenticated, g.registeredOn))
val body = GuestsWaitingForApprovalEvtMsgBody(guestsWaiting) val body = GuestsWaitingForApprovalEvtMsgBody(guestsWaiting)
val event = GuestsWaitingForApprovalEvtMsg(header, body) val event = GuestsWaitingForApprovalEvtMsg(header, body)

View File

@ -13,7 +13,7 @@ object UserJoinedMeetingEvtMsgBuilder {
guestStatus = userState.guestStatus, guestStatus = userState.guestStatus,
emoji = userState.emoji, emoji = userState.emoji,
pin = userState.pin, pin = userState.pin,
presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, presenter = userState.presenter, locked = userState.locked, avatar = userState.avatar, color = userState.color,
clientType = userState.clientType) clientType = userState.clientType)
val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body) val event = UserJoinedMeetingEvtMsg(meetingId, userState.intId, body)

View File

@ -20,13 +20,13 @@ trait FakeTestData {
val guest1 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.WEBRTC, muted = false, val guest1 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.WEBRTC, muted = false,
talking = false, listenOnly = false) talking = false, listenOnly = false)
Users2x.add(liveMeeting.users2x, guest1) Users2x.add(liveMeeting.users2x, guest1)
val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", guest1.authed, System.currentTimeMillis()) val guestWait1 = GuestWaiting(guest1.intId, guest1.name, guest1.role, guest1.guest, "", "#ff6242", guest1.authed, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait1) GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait1)
val guest2 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.FLASH, muted = false, val guest2 = createUserVoiceAndCam(liveMeeting, Roles.VIEWER_ROLE, guest = true, authed = true, CallingWith.FLASH, muted = false,
talking = false, listenOnly = false) talking = false, listenOnly = false)
Users2x.add(liveMeeting.users2x, guest2) Users2x.add(liveMeeting.users2x, guest2)
val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", guest2.authed, System.currentTimeMillis()) val guestWait2 = GuestWaiting(guest2.intId, guest2.name, guest2.role, guest2.guest, "", "#ff6242", guest2.authed, System.currentTimeMillis())
GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait2) GuestsWaiting.add(liveMeeting.guestsWaiting, guestWait2)
val vu1 = FakeUserGenerator.createFakeVoiceOnlyUser(CallingWith.PHONE, muted = false, talking = false, listenOnly = false) val vu1 = FakeUserGenerator.createFakeVoiceOnlyUser(CallingWith.PHONE, muted = false, talking = false, listenOnly = false)
@ -67,8 +67,8 @@ trait FakeTestData {
def createFakeUser(liveMeeting: LiveMeeting, regUser: RegisteredUser): UserState = { def createFakeUser(liveMeeting: LiveMeeting, regUser: RegisteredUser): UserState = {
UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false, UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, pin = false,
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus, mobile = false, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, clientType = "unknown", emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242", clientType = "unknown",
pickExempted = false, userLeftFlag = UserLeftFlag(false, 0)) pickExempted = false, userLeftFlag = UserLeftFlag(false, 0))
} }

View File

@ -52,9 +52,10 @@ object FakeUserGenerator {
val authToken = RandomStringGenerator.randomAlphanumericString(16) val authToken = RandomStringGenerator.randomAlphanumericString(16)
val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" + val avatarURL = "https://www." + RandomStringGenerator.randomAlphanumericString(32) + ".com/" +
RandomStringGenerator.randomAlphanumericString(10) + ".png" RandomStringGenerator.randomAlphanumericString(10) + ".png"
val color = "#ff6242"
val ru = RegisteredUsers.create(userId = id, extId, name, role, val ru = RegisteredUsers.create(userId = id, extId, name, role,
authToken, avatarURL, guest, authed, guestStatus = GuestStatus.ALLOW, false, false) authToken, avatarURL, color, guest, authed, guestStatus = GuestStatus.ALLOW, false, false)
RegisteredUsers.add(users, ru) RegisteredUsers.add(users, ru)
ru ru
} }

View File

@ -43,8 +43,8 @@ object TestDataGen {
def createUserFor(liveMeeting: LiveMeeting, regUser: RegisteredUser, presenter: Boolean): UserState = { def createUserFor(liveMeeting: LiveMeeting, regUser: RegisteredUser, presenter: Boolean): UserState = {
val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role, val u = UserState(intId = regUser.id, extId = regUser.externId, name = regUser.name, role = regUser.role,
guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus, guest = regUser.guest, authed = regUser.authed, guestStatus = regUser.guestStatus,
emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, clientType = "unknown", emoji = "none", locked = false, presenter = false, avatar = regUser.avatarURL, color = "#ff6242",
userLeftFlag = UserLeftFlag(false, 0)) clientType = "unknown", userLeftFlag = UserLeftFlag(false, 0))
Users2x.add(liveMeeting.users2x, u) Users2x.add(liveMeeting.users2x, u)
u u
} }

View File

@ -19,7 +19,7 @@ case class GetGuestsWaitingApprovalRespMsg(
body: GetGuestsWaitingApprovalRespMsgBody body: GetGuestsWaitingApprovalRespMsgBody
) extends BbbCoreMsg ) extends BbbCoreMsg
case class GetGuestsWaitingApprovalRespMsgBody(guests: Vector[GuestWaitingVO]) case class GetGuestsWaitingApprovalRespMsgBody(guests: Vector[GuestWaitingVO])
case class GuestWaitingVO(intId: String, name: String, role: String, guest: Boolean, avatar: String, authenticated: Boolean, registeredOn: Long) case class GuestWaitingVO(intId: String, name: String, role: String, guest: Boolean, avatar: String, color: String, authenticated: Boolean, registeredOn: Long)
/** /**
* Message sent to client for list of guest waiting for approval. This is sent when * Message sent to client for list of guest waiting for approval. This is sent when

View File

@ -88,11 +88,22 @@ case class UserJoinedMeetingEvtMsg(
header: BbbClientMsgHeader, header: BbbClientMsgHeader,
body: UserJoinedMeetingEvtMsgBody body: UserJoinedMeetingEvtMsgBody
) extends BbbCoreMsg ) extends BbbCoreMsg
case class UserJoinedMeetingEvtMsgBody(intId: String, extId: String, name: String, role: String, case class UserJoinedMeetingEvtMsgBody(
guest: Boolean, authed: Boolean, guestStatus: String, intId: String,
emoji: String, extId: String,
pin: Boolean, name: String,
presenter: Boolean, locked: Boolean, avatar: String, clientType: String) role: String,
guest: Boolean,
authed: Boolean,
guestStatus: String,
emoji: String,
pin: Boolean,
presenter: Boolean,
locked: Boolean,
avatar: String,
color: String,
clientType: String
)
/** /**
* Sent by client to get all users in a meeting. * Sent by client to get all users in a meeting.
@ -189,6 +200,20 @@ object UserEmojiChangedEvtMsg { val NAME = "UserEmojiChangedEvtMsg" }
case class UserEmojiChangedEvtMsg(header: BbbClientMsgHeader, body: UserEmojiChangedEvtMsgBody) extends BbbCoreMsg case class UserEmojiChangedEvtMsg(header: BbbClientMsgHeader, body: UserEmojiChangedEvtMsgBody) extends BbbCoreMsg
case class UserEmojiChangedEvtMsgBody(userId: String, emoji: String) case class UserEmojiChangedEvtMsgBody(userId: String, emoji: String)
/**
* Sent from client about a user mobile flag.
*/
object ChangeUserMobileFlagReqMsg { val NAME = "ChangeUserMobileFlagReqMsg" }
case class ChangeUserMobileFlagReqMsg(header: BbbClientMsgHeader, body: ChangeUserMobileFlagReqMsgBody) extends StandardMsg
case class ChangeUserMobileFlagReqMsgBody(userId: String, mobile: Boolean)
/**
* Sent to all clients about a user mobile flag.
*/
object UserMobileFlagChangedEvtMsg { val NAME = "UserMobileFlagChangedEvtMsg" }
case class UserMobileFlagChangedEvtMsg(header: BbbClientMsgHeader, body: UserMobileFlagChangedEvtMsgBody) extends BbbCoreMsg
case class UserMobileFlagChangedEvtMsgBody(userId: String, mobile: Boolean)
object AssignPresenterReqMsg { val NAME = "AssignPresenterReqMsg" } object AssignPresenterReqMsg { val NAME = "AssignPresenterReqMsg" }
case class AssignPresenterReqMsg(header: BbbClientMsgHeader, body: AssignPresenterReqMsgBody) extends StandardMsg case class AssignPresenterReqMsg(header: BbbClientMsgHeader, body: AssignPresenterReqMsgBody) extends StandardMsg
case class AssignPresenterReqMsgBody(requesterId: String, newPresenterId: String, newPresenterName: String, assignedBy: String) case class AssignPresenterReqMsgBody(requesterId: String, newPresenterId: String, newPresenterName: String, assignedBy: String)

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
set -ex set -ex
RELEASE=4.0.1 RELEASE=4.0.2
cat <<MSG cat <<MSG
This tool downloads prebuilt packages built on Github Actions This tool downloads prebuilt packages built on Github Actions
The corresponding source can be browsed at https://github.com/bigbluebutton/bbb-presentation-video/tree/${RELEASE} The corresponding source can be browsed at https://github.com/bigbluebutton/bbb-presentation-video/tree/${RELEASE}

View File

@ -44,9 +44,10 @@ fi
HOST=$(cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $tmpfile $BBB_WEB_ETC_CONFIG | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*\///;p}' | tail -n 1) HOST=$(cat $SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties $tmpfile $BBB_WEB_ETC_CONFIG | grep -v '#' | sed -n '/^bigbluebutton.web.serverURL/{s/.*\///;p}' | tail -n 1)
HTML5_CONFIG=/usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml HTML5_CONFIG=/etc/bigbluebutton/bbb-html5.yml
BBB_WEB_CONFIG=$SERVLET_DIR/WEB-INF/classes/bigbluebutton.properties if [ ! -f "${HTML5_CONFIG}" ]; then
touch $HTML5_CONFIG
fi
# #
# Enable Looging of the HTML5 client for debugging # Enable Looging of the HTML5 client for debugging

View File

@ -348,3 +348,9 @@
.icon-bbb-closed_caption_stop:before { .icon-bbb-closed_caption_stop:before {
content: "\e966"; content: "\e966";
} }
.icon-bbb-link:before {
content: "\e967";
}
.icon-bbb-manage_layout:before {
content: "\e968";
}

View File

@ -1,13 +1,13 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import _ from "lodash"; import _ from 'lodash';
export default function addAnnotation(meetingId, whiteboardId, userId, annotation, Annotations) { async function addAnnotation(meetingId, whiteboardId, userId, annotation, Annotations) {
check(meetingId, String); check(meetingId, String);
check(whiteboardId, String); check(whiteboardId, String);
check(annotation, Object); check(annotation, Object);
const { const {
id, wbId, id, wbId,
} = annotation; } = annotation;
let { annotationInfo } = annotation; let { annotationInfo } = annotation;
@ -17,9 +17,9 @@ export default function addAnnotation(meetingId, whiteboardId, userId, annotatio
id, id,
}; };
const oldAnnotation = Annotations.findOne(selector); const oldAnnotation = await Annotations.findOneAsync(selector);
if (oldAnnotation) { if (oldAnnotation) {
annotationInfo = _.merge(oldAnnotation.annotationInfo, annotationInfo) annotationInfo = _.merge(oldAnnotation.annotationInfo, annotationInfo);
} }
const modifier = { const modifier = {
@ -34,3 +34,5 @@ export default function addAnnotation(meetingId, whiteboardId, userId, annotatio
return { selector, modifier }; return { selector, modifier };
} }
export default addAnnotation;

View File

@ -16,8 +16,8 @@ if (Meteor.isServer) {
// 6. meetingId, whiteboardId, userId ( 1 ) // 6. meetingId, whiteboardId, userId ( 1 )
// These 2 indexes seem to cover all of the cases // These 2 indexes seem to cover all of the cases
Annotations._ensureIndex({ id: 1 }); Annotations.createIndexAsync({ id: 1 });
Annotations._ensureIndex({ meetingId: 1, whiteboardId: 1, userId: 1 }); Annotations.createIndexAsync({ meetingId: 1, whiteboardId: 1, userId: 1 });
} }
export default Annotations; export default Annotations;

View File

@ -1,10 +1,9 @@
import _ from 'lodash';
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import modifyWhiteboardAccess from '/imports/api/whiteboard-multi-user/server/modifiers/modifyWhiteboardAccess'; import modifyWhiteboardAccess from '/imports/api/whiteboard-multi-user/server/modifiers/modifyWhiteboardAccess';
import clearAnnotations from '../modifiers/clearAnnotations'; import clearAnnotations from '../modifiers/clearAnnotations';
import addAnnotation from '../modifiers/addAnnotation'; import addAnnotation from '../modifiers/addAnnotation';
export default function handleWhiteboardAnnotations({ header, body }, meetingId) { async function handleWhiteboardAnnotations({ header, body }, meetingId) {
check(header, Object); check(header, Object);
if (header.userId !== 'nodeJSapp') { return false; } if (header.userId !== 'nodeJSapp') { return false; }
@ -17,12 +16,15 @@ export default function handleWhiteboardAnnotations({ header, body }, meetingId)
check(whiteboardId, String); check(whiteboardId, String);
check(multiUser, Array); check(multiUser, Array);
clearAnnotations(meetingId, whiteboardId); await clearAnnotations(meetingId, whiteboardId);
// we use a for loop here instead of a map because we need to guarantee the order of the annotations.
_.each(annotations, (annotation) => { for (const annotation of annotations) {
const { wbId, userId } = annotation; const { wbId, userId } = annotation;
addAnnotation(meetingId, wbId, userId, annotation); await addAnnotation(meetingId, wbId, userId, annotation);
}); }
modifyWhiteboardAccess(meetingId, whiteboardId, multiUser); await modifyWhiteboardAccess(meetingId, whiteboardId, multiUser);
return true;
} }
export default handleWhiteboardAnnotations;

View File

@ -3,7 +3,7 @@ import AnnotationsStreamer from '/imports/api/annotations/server/streamer';
import clearAnnotations from '../modifiers/clearAnnotations'; import clearAnnotations from '../modifiers/clearAnnotations';
export default function handleWhiteboardCleared({ body }, meetingId) { export default async function handleWhiteboardCleared({ body }, meetingId) {
check(body, { check(body, {
userId: String, userId: String,
whiteboardId: String, whiteboardId: String,
@ -14,9 +14,11 @@ export default function handleWhiteboardCleared({ body }, meetingId) {
if (fullClear) { if (fullClear) {
AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId }); AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId });
return clearAnnotations(meetingId, whiteboardId); const result = await clearAnnotations(meetingId, whiteboardId);
return result;
} }
AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId, userId }); AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId, userId });
return clearAnnotations(meetingId, whiteboardId, userId); const result = await clearAnnotations(meetingId, whiteboardId, userId);
return result;
} }

View File

@ -3,16 +3,16 @@ import { check } from 'meteor/check';
import AnnotationsStreamer from '/imports/api/annotations/server/streamer'; import AnnotationsStreamer from '/imports/api/annotations/server/streamer';
import removeAnnotation from '../modifiers/removeAnnotation'; import removeAnnotation from '../modifiers/removeAnnotation';
export default function handleWhiteboardDelete({ body }, meetingId) { export default async function handleWhiteboardDelete({ body }, meetingId) {
const whiteboardId = body.whiteboardId; const { whiteboardId } = body;
const shapesIds = body.annotationsIds; const shapesIds = body.annotationsIds;
check(whiteboardId, String); check(whiteboardId, String);
check(shapesIds, Array); check(shapesIds, Array);
//console.log("!!!!!!!!!!!! handleWhiteboardDelete !!!!!!!!!!!!!!!!!",shapesIds) const result = await Promise.all(shapesIds.map(async (shapeId) => {
shapesIds.map(shapeId => {
AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId, shapeId }); AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId, shapeId });
removeAnnotation(meetingId, whiteboardId, shapeId); await removeAnnotation(meetingId, whiteboardId, shapeId);
}) }));
return result;
} }

View File

@ -29,7 +29,7 @@ const process = () => {
Meteor.setTimeout(process, ANNOTATION_PROCESS_INTERVAL); Meteor.setTimeout(process, ANNOTATION_PROCESS_INTERVAL);
}; };
export default function handleWhiteboardSend({ envelope, header, body }, meetingId) { export default async function handleWhiteboardSend({ envelope, header, body }, meetingId) {
const userId = header.userId; const userId = header.userId;
const whiteboardId = body.whiteboardId; const whiteboardId = body.whiteboardId;
const annotations = body.annotations; const annotations = body.annotations;
@ -43,13 +43,14 @@ export default function handleWhiteboardSend({ envelope, header, body }, meeting
if (!annotationsQueue.hasOwnProperty(meetingId)) { if (!annotationsQueue.hasOwnProperty(meetingId)) {
annotationsQueue[meetingId] = []; annotationsQueue[meetingId] = [];
} }
// we use a for loop here instead of a map because we need to guarantee the order of the annotations.
annotations.forEach(annotation => { for (const annotation of annotations) {
annotationsQueue[meetingId].push({ meetingId, whiteboardId, userId: annotation.userId, annotation }); annotationsQueue[meetingId].push({ meetingId, whiteboardId, userId: annotation.userId, annotation });
if (instanceIdFromMessage === myInstanceId) { if (instanceIdFromMessage === myInstanceId) {
addAnnotation(meetingId, whiteboardId, annotation.userId, annotation); await addAnnotation(meetingId, whiteboardId, annotation.userId, annotation);
} }
}) }
if (queueMetrics) { if (queueMetrics) {
Metrics.setAnnotationQueueLength(meetingId, annotationsQueue[meetingId].length); Metrics.setAnnotationQueueLength(meetingId, annotationsQueue[meetingId].length);
} }

View File

@ -3,13 +3,14 @@ import { check } from 'meteor/check';
import AnnotationsStreamer from '/imports/api/annotations/server/streamer'; import AnnotationsStreamer from '/imports/api/annotations/server/streamer';
import removeAnnotation from '../modifiers/removeAnnotation'; import removeAnnotation from '../modifiers/removeAnnotation';
export default function handleWhiteboardUndo({ body }, meetingId) { export default async function handleWhiteboardUndo({ body }, meetingId) {
const whiteboardId = body.whiteboardId; const { whiteboardId } = body;
const shapeId = body.annotationId; const shapeId = body.annotationId;
check(whiteboardId, String); check(whiteboardId, String);
check(shapeId, String); check(shapeId, String);
AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId, shapeId }); AnnotationsStreamer(meetingId).emit('removed', { meetingId, whiteboardId, shapeId });
return removeAnnotation(meetingId, whiteboardId, shapeId); const result = await removeAnnotation(meetingId, whiteboardId, shapeId);
return result;
} }

View File

@ -3,15 +3,15 @@ import Logger from '/imports/startup/server/logger';
import Annotations from '/imports/api/annotations'; import Annotations from '/imports/api/annotations';
import addAnnotationQuery from '/imports/api/annotations/addAnnotation'; import addAnnotationQuery from '/imports/api/annotations/addAnnotation';
export default function addAnnotation(meetingId, whiteboardId, userId, annotation) { export default async function addAnnotation(meetingId, whiteboardId, userId, annotation) {
check(meetingId, String); check(meetingId, String);
check(whiteboardId, String); check(whiteboardId, String);
check(annotation, Object); check(annotation, Object);
const query = addAnnotationQuery(meetingId, whiteboardId, userId, annotation, Annotations); const query = await addAnnotationQuery(meetingId, whiteboardId, userId, annotation, Annotations);
try { try {
const { insertedId } = Annotations.upsert(query.selector, query.modifier); const { insertedId } = await Annotations.upsertAsync(query.selector, query.modifier);
if (insertedId) { if (insertedId) {
Logger.info(`Added annotation id=${annotation.id} whiteboard=${whiteboardId}`); Logger.info(`Added annotation id=${annotation.id} whiteboard=${whiteboardId}`);

View File

@ -1,7 +1,7 @@
import Annotations from '/imports/api/annotations'; import Annotations from '/imports/api/annotations';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function clearAnnotations(meetingId, whiteboardId, userId) { export default async function clearAnnotations(meetingId, whiteboardId, userId) {
const selector = {}; const selector = {};
if (meetingId) { if (meetingId) {
@ -17,7 +17,7 @@ export default function clearAnnotations(meetingId, whiteboardId, userId) {
} }
try { try {
const numberAffected = Annotations.remove(selector); const numberAffected = await Annotations.removeAsync(selector);
if (numberAffected) { if (numberAffected) {
if (userId) { if (userId) {

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Annotations from '/imports/api/annotations'; import Annotations from '/imports/api/annotations';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function removeAnnotation(meetingId, whiteboardId, shapeId) { export default async function removeAnnotation(meetingId, whiteboardId, shapeId) {
check(meetingId, String); check(meetingId, String);
check(whiteboardId, String); check(whiteboardId, String);
check(shapeId, String); check(shapeId, String);
@ -14,7 +14,7 @@ export default function removeAnnotation(meetingId, whiteboardId, shapeId) {
}; };
try { try {
const numberAffected = Annotations.remove(selector); const numberAffected = await Annotations.removeAsync(selector);
if (numberAffected) { if (numberAffected) {
Logger.info(`Removed annotation id=${shapeId} whiteboard=${whiteboardId}`); Logger.info(`Removed annotation id=${shapeId} whiteboard=${whiteboardId}`);

View File

@ -3,7 +3,7 @@ import { Meteor } from 'meteor/meteor';
const AudioCaptions = new Mongo.Collection('audio-captions'); const AudioCaptions = new Mongo.Collection('audio-captions');
if (Meteor.isServer) { if (Meteor.isServer) {
AudioCaptions._ensureIndex({ meetingId: 1 }); AudioCaptions.createIndexAsync({ meetingId: 1 });
} }
export default AudioCaptions; export default AudioCaptions;

View File

@ -1,6 +1,6 @@
import setTranscript from '/imports/api/audio-captions/server/modifiers/setTranscript'; import setTranscript from '/imports/api/audio-captions/server/modifiers/setTranscript';
export default function transcriptUpdated({ header, body }) { export default async function transcriptUpdated({ header, body }) {
const { meetingId } = header; const { meetingId } = header;
const { const {
@ -8,5 +8,5 @@ export default function transcriptUpdated({ header, body }) {
transcript, transcript,
} = body; } = body;
setTranscript(meetingId, transcriptId, transcript); await setTranscript(meetingId, transcriptId, transcript);
} }

View File

@ -1,10 +1,10 @@
import AudioCaptions from '/imports/api/audio-captions'; import AudioCaptions from '/imports/api/audio-captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function clearAudioCaptions(meetingId) { export default async function clearAudioCaptions(meetingId) {
if (meetingId) { if (meetingId) {
try { try {
const numberAffected = AudioCaptions.remove({ meetingId }); const numberAffected = await AudioCaptions.removeAsync({ meetingId });
if (numberAffected) { if (numberAffected) {
Logger.info(`Cleared AudioCaptions (${meetingId})`); Logger.info(`Cleared AudioCaptions (${meetingId})`);
@ -14,7 +14,7 @@ export default function clearAudioCaptions(meetingId) {
} }
} else { } else {
try { try {
const numberAffected = AudioCaptions.remove({}); const numberAffected = await AudioCaptions.removeAsync({});
if (numberAffected) { if (numberAffected) {
Logger.info('Cleared AudioCaptions (all)'); Logger.info('Cleared AudioCaptions (all)');

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import AudioCaptions from '/imports/api/audio-captions'; import AudioCaptions from '/imports/api/audio-captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function setTranscript(meetingId, transcriptId, transcript) { export default async function setTranscript(meetingId, transcriptId, transcript) {
try { try {
check(meetingId, String); check(meetingId, String);
check(transcriptId, String); check(transcriptId, String);
@ -17,7 +17,7 @@ export default function setTranscript(meetingId, transcriptId, transcript) {
}, },
}; };
const numberAffected = AudioCaptions.upsert(selector, modifier); const numberAffected = await AudioCaptions.upsertAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.debug(`Set transcriptId=${transcriptId} transcript=${transcript} meeting=${meetingId}`); Logger.debug(`Set transcriptId=${transcriptId} transcript=${transcript} meeting=${meetingId}`);

View File

@ -3,8 +3,9 @@ import { Meteor } from 'meteor/meteor';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation'; import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
function audioCaptions() { async function audioCaptions() {
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing AudioCaptions was requested by unauth connection ${this.connection.id}`); Logger.warn(`Publishing AudioCaptions was requested by unauth connection ${this.connection.id}`);

View File

@ -7,7 +7,7 @@ const collectionOptions = Meteor.isClient ? {
const AuthTokenValidation = new Mongo.Collection('auth-token-validation', collectionOptions); const AuthTokenValidation = new Mongo.Collection('auth-token-validation', collectionOptions);
if (Meteor.isServer) { if (Meteor.isServer) {
AuthTokenValidation._ensureIndex({ connectionId: 1 }); AuthTokenValidation.createIndexAsync({ connectionId: 1 });
} }
export const ValidationStates = Object.freeze({ export const ValidationStates = Object.freeze({

View File

@ -2,15 +2,14 @@ import AuthTokenValidation from '/imports/api/auth-token-validation';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import ClientConnections from '/imports/startup/server/ClientConnections'; import ClientConnections from '/imports/startup/server/ClientConnections';
export default function clearAuthTokenValidation(meetingId) { export default async function clearAuthTokenValidation(meetingId) {
return AuthTokenValidation.remove({ meetingId }, (err, num) => { try {
if (err) { await AuthTokenValidation.removeAsync({ meetingId });
Logger.info(`Error when removing auth-token-validation for meeting=${meetingId}`);
}
if (!process.env.BBB_HTML5_ROLE || process.env.BBB_HTML5_ROLE === 'frontend') { if (!process.env.BBB_HTML5_ROLE || process.env.BBB_HTML5_ROLE === 'frontend') {
ClientConnections.removeMeeting(meetingId); ClientConnections.removeMeeting(meetingId);
} }
Logger.info(`Cleared AuthTokenValidation (${meetingId})`); Logger.info(`Cleared AuthTokenValidation (${meetingId})`);
}); } catch (error) {
Logger.info(`Error when removing auth-token-validation for meeting=${meetingId}`);
}
} }

View File

@ -1,16 +1,14 @@
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import AuthTokenValidation from '/imports/api/auth-token-validation'; import AuthTokenValidation from '/imports/api/auth-token-validation';
export default function removeValidationState(meetingId, userId, connectionId) { export default async function removeValidationState(meetingId, userId, connectionId) {
const selector = { const selector = {
meetingId, userId, connectionId, meetingId, userId, connectionId,
}; };
const cb = (err) => { try {
if (err) { await AuthTokenValidation.removeAsync(selector);
Logger.error(`Could not remove from collection AuthTokenValidation: ${err}`); } catch (error) {
} Logger.error(`Could not remove from collection AuthTokenValidation: ${error}`);
}; }
return AuthTokenValidation.remove(selector, cb);
} }

View File

@ -1,7 +1,13 @@
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import AuthTokenValidation from '/imports/api/auth-token-validation'; import AuthTokenValidation from '/imports/api/auth-token-validation';
export default function upsertValidationState(meetingId, userId, validationStatus, connectionId, reason = null) { export default async function upsertValidationState(
meetingId,
userId,
validationStatus,
connectionId,
reason = null,
) {
const selector = { const selector = {
meetingId, userId, connectionId, meetingId, userId, connectionId,
}; };
@ -17,8 +23,9 @@ export default function upsertValidationState(meetingId, userId, validationStatu
}; };
try { try {
AuthTokenValidation.remove({ meetingId, userId, connectionId: { $ne: connectionId } }); await AuthTokenValidation
const { numberAffected } = AuthTokenValidation.upsert(selector, modifier); .removeAsync({ meetingId, userId, connectionId: { $ne: connectionId } });
const { numberAffected } = AuthTokenValidation.upsertAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.info(`Upserted ${JSON.stringify(selector)} ${validationStatus} in AuthTokenValidation`); Logger.info(`Upserted ${JSON.stringify(selector)} ${validationStatus} in AuthTokenValidation`);

View File

@ -7,7 +7,7 @@ const collectionOptions = Meteor.isClient ? {
const BreakoutsHistory = new Mongo.Collection('breakouts-history', collectionOptions); const BreakoutsHistory = new Mongo.Collection('breakouts-history', collectionOptions);
if (Meteor.isServer) { if (Meteor.isServer) {
BreakoutsHistory._ensureIndex({ meetingId: 1 }); BreakoutsHistory.createIndexAsync({ meetingId: 1 });
} }
export default BreakoutsHistory; export default BreakoutsHistory;

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import BreakoutsHistory from '/imports/api/breakouts-history'; import BreakoutsHistory from '/imports/api/breakouts-history';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function handleBreakoutRoomsList({ body }) { export default async function handleBreakoutRoomsList({ body }) {
const { const {
meetingId, meetingId,
rooms, rooms,
@ -22,7 +22,7 @@ export default function handleBreakoutRoomsList({ body }) {
}; };
try { try {
const { insertedId } = BreakoutsHistory.upsert(selector, modifier); const { insertedId } = await BreakoutsHistory.upsertAsync(selector, modifier);
if (insertedId) { if (insertedId) {
Logger.info(`Added rooms to breakout-history Data: meeting=${meetingId}`); Logger.info(`Added rooms to breakout-history Data: meeting=${meetingId}`);

View File

@ -2,8 +2,7 @@ import Logger from '/imports/startup/server/logger';
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import BreakoutsHistory from '/imports/api/breakouts-history'; import BreakoutsHistory from '/imports/api/breakouts-history';
export default function handleSendMessageToAllBreakoutRoomsEvtMsg({ body }, meetingId) { export default async function handleSendMessageToAllBreakoutRoomsEvtMsg({ body }, meetingId) {
const { const {
senderId, senderId,
msg, msg,
@ -30,7 +29,7 @@ export default function handleSendMessageToAllBreakoutRoomsEvtMsg({ body }, meet
}; };
try { try {
const { insertedId } = BreakoutsHistory.upsert(selector, modifier); const { insertedId } = await BreakoutsHistory.upsertAsync(selector, modifier);
if (insertedId) { if (insertedId) {
Logger.info(`Added broadCastMsg to breakout-history Data: meeting=${meetingId}`); Logger.info(`Added broadCastMsg to breakout-history Data: meeting=${meetingId}`);

View File

@ -9,8 +9,9 @@ import { publicationSafeGuard } from '/imports/api/common/server/helpers';
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
function breakoutsHistory() { async function breakoutsHistory() {
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing Meetings-history was requested by unauth connection ${this.connection.id}`); Logger.warn(`Publishing Meetings-history was requested by unauth connection ${this.connection.id}`);
@ -20,7 +21,7 @@ function breakoutsHistory() {
const { meetingId, userId } = tokenValidation; const { meetingId, userId } = tokenValidation;
Logger.debug('Publishing Breakouts-History', { meetingId, userId }); Logger.debug('Publishing Breakouts-History', { meetingId, userId });
const User = Users.findOne({ userId, meetingId }, { fields: { userId: 1, role: 1 } }); const User = await Users.findOneAsync({ userId, meetingId }, { fields: { userId: 1, role: 1 } });
if (!User || User.role !== ROLE_MODERATOR) { if (!User || User.role !== ROLE_MODERATOR) {
return BreakoutsHistory.find({ meetingId: '' }); return BreakoutsHistory.find({ meetingId: '' });
} }
@ -32,8 +33,9 @@ function breakoutsHistory() {
}; };
// Monitor this publication and stop it when user is not a moderator anymore // Monitor this publication and stop it when user is not a moderator anymore
const comparisonFunc = () => { const comparisonFunc = async () => {
const user = Users.findOne({ userId, meetingId }, { fields: { role: 1, userId: 1 } }); const user = await Users
.findOneAsync({ userId, meetingId }, { fields: { role: 1, userId: 1 } });
const condition = user.role === ROLE_MODERATOR; const condition = user.role === ROLE_MODERATOR;
if (!condition) { if (!condition) {

View File

@ -11,8 +11,8 @@ if (Meteor.isServer) {
// 1. breakoutId ( handleJoinUrl, roomStarted, clearBreakouts ) // 1. breakoutId ( handleJoinUrl, roomStarted, clearBreakouts )
// 2. parentMeetingId ( updateTimeRemaining ) // 2. parentMeetingId ( updateTimeRemaining )
Breakouts._ensureIndex({ breakoutId: 1 }); Breakouts.createIndexAsync({ breakoutId: 1 });
Breakouts._ensureIndex({ parentMeetingId: 1 }); Breakouts.createIndexAsync({ parentMeetingId: 1 });
} }
export default Breakouts; export default Breakouts;

View File

@ -1,9 +1,9 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import clearBreakouts from '../modifiers/clearBreakouts'; import clearBreakouts from '../modifiers/clearBreakouts';
export default function handleBreakoutClosed({ body }) { export default async function handleBreakoutClosed({ body }) {
const { breakoutId } = body; const { breakoutId } = body;
check(breakoutId, String); check(breakoutId, String);
const result = await clearBreakouts(breakoutId);
return clearBreakouts(breakoutId); return result;
} }

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import Breakouts from '/imports/api/breakouts'; import Breakouts from '/imports/api/breakouts';
export default function handleBreakoutJoinURL({ body }) { export default async function handleBreakoutJoinURL({ body }) {
const { const {
redirectToHtml5JoinURL, redirectToHtml5JoinURL,
userId, userId,
@ -28,24 +28,19 @@ export default function handleBreakoutJoinURL({ body }) {
const ATTEMPT_EVERY_MS = 1000; const ATTEMPT_EVERY_MS = 1000;
let numberAffected = 0; let numberAffected = 0;
const updateBreakout = async () => {
numberAffected = await Breakouts.updateAsync(selector, modifier);
};
const updateBreakout = Meteor.bindEnvironment(() => { await new Promise((resolve) => {
numberAffected = Breakouts.update(selector, modifier); const updateBreakoutInterval = setInterval(async () => {
}); await updateBreakout();
const updateBreakoutPromise = new Promise((resolve) => {
const updateBreakoutInterval = setInterval(() => {
updateBreakout();
if (numberAffected) { if (numberAffected) {
resolve(clearInterval(updateBreakoutInterval)); resolve(clearInterval(updateBreakoutInterval));
} }
}, ATTEMPT_EVERY_MS); }, ATTEMPT_EVERY_MS);
}); });
Logger.info(`Upserted breakout id=${breakoutId}`);
updateBreakoutPromise.then(() => {
Logger.info(`Upserted breakout id=${breakoutId}`);
});
} catch (err) { } catch (err) {
Logger.error(`Adding breakout to collection: ${err}`); Logger.error(`Adding breakout to collection: ${err}`);
} }

View File

@ -4,7 +4,7 @@ import { check } from 'meteor/check';
import flat from 'flat'; import flat from 'flat';
import handleBreakoutRoomsListHist from '/imports/api/breakouts-history/server/handlers/breakoutRoomsList'; import handleBreakoutRoomsListHist from '/imports/api/breakouts-history/server/handlers/breakoutRoomsList';
export default function handleBreakoutRoomsList({ body }, meetingId) { export default async function handleBreakoutRoomsList({ body }, meetingId) {
// 0 seconds default breakout time, forces use of real expiration time // 0 seconds default breakout time, forces use of real expiration time
const DEFAULT_TIME_REMAINING = 0; const DEFAULT_TIME_REMAINING = 0;
@ -14,7 +14,7 @@ export default function handleBreakoutRoomsList({ body }, meetingId) {
} = body; } = body;
// set firstly the last seq, then client will know when receive all // set firstly the last seq, then client will know when receive all
rooms.sort((a, b) => ((a.sequence < b.sequence) ? 1 : -1)).forEach((breakout) => { await rooms.sort((a, b) => ((a.sequence < b.sequence) ? 1 : -1)).forEach(async (breakout) => {
const { breakoutId, html5JoinUrls, ...breakoutWithoutUrls } = breakout; const { breakoutId, html5JoinUrls, ...breakoutWithoutUrls } = breakout;
check(meetingId, String); check(meetingId, String);
@ -43,18 +43,13 @@ export default function handleBreakoutRoomsList({ body }, meetingId) {
...urls, ...urls,
}, },
}; };
const numberAffected = await Breakouts.upsertAsync(selector, modifier);
try { if (numberAffected) {
const { numberAffected } = Breakouts.upsert(selector, modifier); Logger.info('Updated timeRemaining and externalMeetingId '
+ `for breakout id=${breakoutId}`);
if (numberAffected) { } else {
Logger.info('Updated timeRemaining and externalMeetingId ' Logger.error(`updating breakout: ${numberAffected}`);
+ `for breakout id=${breakoutId}`);
}
} catch (err) {
Logger.error(`updating breakout: ${err}`);
} }
handleBreakoutRoomsListHist({ body });
}); });
handleBreakoutRoomsListHist({ body });
} }

View File

@ -4,7 +4,7 @@ import Logger from '/imports/startup/server/logger';
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import { lowercaseTrim } from '/imports/utils/string-utils'; import { lowercaseTrim } from '/imports/utils/string-utils';
export default function joinedUsersChanged({ body }) { export default async function joinedUsersChanged({ body }) {
check(body, Object); check(body, Object);
const { const {
@ -22,7 +22,8 @@ export default function joinedUsersChanged({ body }) {
breakoutId, breakoutId,
}; };
const usersMapped = users.map(user => ({ userId: user.id, name: user.name, sortName: lowercaseTrim(user.name) })); const usersMapped = users
.map((user) => ({ userId: user.id, name: user.name, sortName: lowercaseTrim(user.name) }));
const modifier = { const modifier = {
$set: { $set: {
joinedUsers: usersMapped, joinedUsers: usersMapped,
@ -30,14 +31,23 @@ export default function joinedUsersChanged({ body }) {
}; };
try { try {
const numberAffected = Breakouts.update(selector, modifier); const numberAffected = await Breakouts.updateAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
updateUserBreakoutRoom(parentId, breakoutId, users); await updateUserBreakoutRoom(parentId, breakoutId, users);
Logger.info(`Updated joined users in breakout id=${breakoutId}`); Logger.info(`Updated joined users in breakout id=${breakoutId}`);
} }
} catch (err) { } catch (err) {
Logger.error(`updating joined users in breakout: ${err}`); Logger.error(`updating joined users in breakout: ${err}`);
} }
// .then((res) => {
// if (res.numberAffected) {
// updateUserBreakoutRoom(parentId, breakoutId, users);
// Logger.info(`Updated joined users in breakout id=${breakoutId}`);
// }
// }).catch((err) => {
// Logger.error(`updating joined users in breakout: ${err}`);
// });
} }

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import Breakouts from '/imports/api/breakouts'; import Breakouts from '/imports/api/breakouts';
export default function handleUpdateTimeRemaining({ body }, meetingId) { export default async function handleUpdateTimeRemaining({ body }, meetingId) {
const { const {
timeRemaining, timeRemaining,
} = body; } = body;
@ -23,14 +23,11 @@ export default function handleUpdateTimeRemaining({ body }, meetingId) {
const options = { const options = {
multi: true, multi: true,
}; };
const numberAffected = Breakouts.updateAsync(selector, modifier, options);
try { if (numberAffected) {
const numberAffected = Breakouts.update(selector, modifier, options); Logger.info(`Updated breakout time remaining for breakouts where parentMeetingId=${meetingId}`);
} else {
if (numberAffected) { Logger.error(`Updating breakouts: ${numberAffected}`);
Logger.info(`Updated breakout time remaining for breakouts where parentMeetingId=${meetingId}`);
}
} catch (err) {
Logger.error(`Updating breakouts: ${err}`);
} }
} }

View File

@ -2,7 +2,7 @@ import Breakouts from '/imports/api/breakouts';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import { check } from 'meteor/check'; import { check } from 'meteor/check';
export default function userBreakoutChanged({ body }) { export default async function userBreakoutChanged({ body }) {
check(body, Object); check(body, Object);
const { const {
@ -49,11 +49,11 @@ export default function userBreakoutChanged({ body }) {
let numberAffectedRows = 0; let numberAffectedRows = 0;
if (oldBreakoutSelector.breakoutId !== '') { if (oldBreakoutSelector.breakoutId !== '') {
numberAffectedRows += Breakouts.update(oldBreakoutSelector, oldModifier); numberAffectedRows += await Breakouts.updateAsync(oldBreakoutSelector, oldModifier);
} }
if (newBreakoutSelector.breakoutId !== '') { if (newBreakoutSelector.breakoutId !== '') {
numberAffectedRows += Breakouts.update(newBreakoutSelector, newModifier); numberAffectedRows += await Breakouts.updateAsync(newBreakoutSelector, newModifier);
} }
if (numberAffectedRows > 0) { if (numberAffectedRows > 0) {

View File

@ -1,14 +1,14 @@
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import Breakouts from '/imports/api/breakouts'; import Breakouts from '/imports/api/breakouts';
export default function clearBreakouts(breakoutId) { export default async function clearBreakouts(breakoutId) {
if (breakoutId) { if (breakoutId) {
const selector = { const selector = {
breakoutId, breakoutId,
}; };
try { try {
const numberAffected = Breakouts.remove(selector); const numberAffected = await Breakouts.removeAsync(selector);
if (numberAffected) { if (numberAffected) {
Logger.info(`Cleared Breakouts (${breakoutId})`); Logger.info(`Cleared Breakouts (${breakoutId})`);
@ -18,7 +18,7 @@ export default function clearBreakouts(breakoutId) {
} }
} else { } else {
try { try {
const numberAffected = Breakouts.remove({}); const numberAffected = await Breakouts.removeAsync({});
if (numberAffected) { if (numberAffected) {
Logger.info('Cleared Breakouts (all)'); Logger.info('Cleared Breakouts (all)');
} }

View File

@ -7,8 +7,9 @@ import { publicationSafeGuard } from '/imports/api/common/server/helpers';
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
function breakouts() { async function breakouts() {
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing Breakouts was requested by unauth connection ${this.connection.id}`); Logger.warn(`Publishing Breakouts was requested by unauth connection ${this.connection.id}`);
@ -16,7 +17,7 @@ function breakouts() {
} }
const { meetingId, userId } = tokenValidation; const { meetingId, userId } = tokenValidation;
const User = Users.findOne({ userId, meetingId }, { fields: { role: 1 } }); const User = await Users.findOneAsync({ userId, meetingId }, { fields: { role: 1 } });
Logger.debug('Publishing Breakouts', { meetingId, userId }); Logger.debug('Publishing Breakouts', { meetingId, userId });
const fields = { const fields = {
@ -45,8 +46,8 @@ function breakouts() {
], ],
}; };
// Monitor this publication and stop it when user is not a moderator anymore // Monitor this publication and stop it when user is not a moderator anymore
const comparisonFunc = () => { const comparisonFunc = async () => {
const user = Users.findOne({ userId, meetingId }, { fields: { role: 1, userId: 1 } }); const user = await Users.findOneAsync({ userId, meetingId }, { fields: { role: 1, userId: 1 } });
const condition = user.role === ROLE_MODERATOR; const condition = user.role === ROLE_MODERATOR;
if (!condition) { if (!condition) {

View File

@ -7,7 +7,7 @@ const collectionOptions = Meteor.isClient ? {
const Captions = new Mongo.Collection('captions', collectionOptions); const Captions = new Mongo.Collection('captions', collectionOptions);
if (Meteor.isServer) { if (Meteor.isServer) {
Captions._ensureIndex({ meetingId: 1, locale: 1 }); Captions.createIndexAsync({ meetingId: 1, locale: 1 });
} }
export default Captions; export default Captions;

View File

@ -1,11 +1,11 @@
import updateCaptionsOwner from '/imports/api/captions/server/modifiers/updateCaptionsOwner'; import updateCaptionsOwner from '/imports/api/captions/server/modifiers/updateCaptionsOwner';
export default function captionsOwnerUpdated({ header, body }) { export default async function captionsOwnerUpdated({ header, body }) {
const { meetingId } = header; const { meetingId } = header;
const { const {
locale, locale,
ownerId, ownerId,
} = body; } = body;
updateCaptionsOwner(meetingId, locale, ownerId); await updateCaptionsOwner(meetingId, locale, ownerId);
} }

View File

@ -14,12 +14,15 @@ const init = (meetingId) => {
method: 'get', method: 'get',
url: LOCALES_URL, url: LOCALES_URL,
responseType: 'json', responseType: 'json',
}).then((response) => { }).then(async (response) => {
const { status } = response; const { status } = response;
if (status !== 200) return; if (status !== 200) return;
const locales = response.data; const locales = response.data;
locales.forEach((locale) => createCaptions(meetingId, locale.locale, locale.name)); await Promise.all(locales.map(async (locale) => {
const caption = await createCaptions(meetingId, locale.locale, locale.name);
return caption;
}));
}).catch((error) => Logger.error(`Could not create captions for ${meetingId}: ${error}`)); }).catch((error) => Logger.error(`Could not create captions for ${meetingId}: ${error}`));
}; };

View File

@ -5,7 +5,7 @@ import Logger from '/imports/startup/server/logger';
import setTranscript from '/imports/api/captions/server/modifiers/setTranscript'; import setTranscript from '/imports/api/captions/server/modifiers/setTranscript';
import updatePad from '/imports/api/pads/server/methods/updatePad'; import updatePad from '/imports/api/pads/server/methods/updatePad';
export default function pushSpeechTranscript(locale, transcript, type) { export default async function pushSpeechTranscript(locale, transcript, type) {
try { try {
const { meetingId, requesterUserId } = extractCredentials(this.userId); const { meetingId, requesterUserId } = extractCredentials(this.userId);
@ -15,7 +15,7 @@ export default function pushSpeechTranscript(locale, transcript, type) {
check(transcript, String); check(transcript, String);
check(type, String); check(type, String);
const captions = Captions.findOne({ const captions = await Captions.findOneAsync({
meetingId, meetingId,
ownerId: requesterUserId, ownerId: requesterUserId,
locale, locale,
@ -28,7 +28,7 @@ export default function pushSpeechTranscript(locale, transcript, type) {
updatePad(meetingId, requesterUserId, locale, text); updatePad(meetingId, requesterUserId, locale, text);
} }
setTranscript(meetingId, locale, transcript); await setTranscript(meetingId, locale, transcript);
} }
} catch (err) { } catch (err) {
Logger.error(`Exception while invoking method pushSpeechTranscript ${err.stack}`); Logger.error(`Exception while invoking method pushSpeechTranscript ${err.stack}`);

View File

@ -4,7 +4,7 @@ import { extractCredentials } from '/imports/api/common/server/helpers';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import setDictation from '/imports/api/captions/server/modifiers/setDictation'; import setDictation from '/imports/api/captions/server/modifiers/setDictation';
export default function startDictation(locale) { export default async function startDictation(locale) {
try { try {
const { meetingId, requesterUserId } = extractCredentials(this.userId); const { meetingId, requesterUserId } = extractCredentials(this.userId);
@ -12,13 +12,13 @@ export default function startDictation(locale) {
check(requesterUserId, String); check(requesterUserId, String);
check(locale, String); check(locale, String);
const captions = Captions.findOne({ const captions = await Captions.findOneAsync({
meetingId, meetingId,
ownerId: requesterUserId, ownerId: requesterUserId,
locale, locale,
}); });
if (captions) setDictation(meetingId, locale, true); if (captions) await setDictation(meetingId, locale, true);
} catch (err) { } catch (err) {
Logger.error(`Exception while invoking method startDictation ${err.stack}`); Logger.error(`Exception while invoking method startDictation ${err.stack}`);
} }

View File

@ -4,7 +4,7 @@ import { extractCredentials } from '/imports/api/common/server/helpers';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import setDictation from '/imports/api/captions/server/modifiers/setDictation'; import setDictation from '/imports/api/captions/server/modifiers/setDictation';
export default function stopDictation(locale) { export default async function stopDictation(locale) {
try { try {
const { meetingId, requesterUserId } = extractCredentials(this.userId); const { meetingId, requesterUserId } = extractCredentials(this.userId);
@ -12,13 +12,13 @@ export default function stopDictation(locale) {
check(requesterUserId, String); check(requesterUserId, String);
check(locale, String); check(locale, String);
const captions = Captions.findOne({ const captions = await Captions.findOne({
meetingId, meetingId,
ownerId: requesterUserId, ownerId: requesterUserId,
locale, locale,
}); });
if (captions) setDictation(meetingId, locale, false); if (captions) await setDictation(meetingId, locale, false);
} catch (err) { } catch (err) {
Logger.error(`Exception while invoking method stopDictation ${err.stack}`); Logger.error(`Exception while invoking method stopDictation ${err.stack}`);
} }

View File

@ -1,10 +1,10 @@
import Captions from '/imports/api/captions'; import Captions from '/imports/api/captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function clearCaptions(meetingId) { export default async function clearCaptions(meetingId) {
if (meetingId) { if (meetingId) {
try { try {
const numberAffected = Captions.remove({ meetingId }); const numberAffected = await Captions.removeAsync({ meetingId });
if (numberAffected) { if (numberAffected) {
Logger.info(`Cleared Captions (${meetingId})`); Logger.info(`Cleared Captions (${meetingId})`);
@ -14,7 +14,7 @@ export default function clearCaptions(meetingId) {
} }
} else { } else {
try { try {
const numberAffected = Captions.remove({}); const numberAffected = await Captions.removeAsync({});
if (numberAffected) { if (numberAffected) {
Logger.info('Cleared Captions (all)'); Logger.info('Cleared Captions (all)');

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Captions from '/imports/api/captions'; import Captions from '/imports/api/captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function createCaptions(meetingId, locale, name) { export default async function createCaptions(meetingId, locale, name) {
try { try {
check(meetingId, String); check(meetingId, String);
check(locale, String); check(locale, String);
@ -22,7 +22,7 @@ export default function createCaptions(meetingId, locale, name) {
transcript: '', transcript: '',
}; };
const numberAffected = Captions.upsert(selector, modifier); const { numberAffected } = await Captions.upsertAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.verbose(`Created captions=${locale} meeting=${meetingId}`); Logger.verbose(`Created captions=${locale} meeting=${meetingId}`);

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Captions from '/imports/api/captions'; import Captions from '/imports/api/captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function setDictation(meetingId, locale, dictating) { export default async function setDictation(meetingId, locale, dictating) {
try { try {
check(meetingId, String); check(meetingId, String);
check(locale, String); check(locale, String);
@ -20,7 +20,7 @@ export default function setDictation(meetingId, locale, dictating) {
}, },
}; };
const numberAffected = Captions.upsert(selector, modifier); const { numberAffected } = Captions.upsertAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.info(`Set captions=${locale} dictating=${dictating} meeting=${meetingId}`); Logger.info(`Set captions=${locale} dictating=${dictating} meeting=${meetingId}`);

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Captions from '/imports/api/captions'; import Captions from '/imports/api/captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function setTranscript(meetingId, locale, transcript) { export default async function setTranscript(meetingId, locale, transcript) {
try { try {
check(meetingId, String); check(meetingId, String);
check(locale, String); check(locale, String);
@ -19,7 +19,7 @@ export default function setTranscript(meetingId, locale, transcript) {
}, },
}; };
const numberAffected = Captions.upsert(selector, modifier); const numberAffected = await Captions.upsertAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.debug(`Set captions=${locale} transcript=${transcript} meeting=${meetingId}`); Logger.debug(`Set captions=${locale} transcript=${transcript} meeting=${meetingId}`);

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Captions from '/imports/api/captions'; import Captions from '/imports/api/captions';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function updateCaptionsOwner(meetingId, locale, ownerId) { export default async function updateCaptionsOwner(meetingId, locale, ownerId) {
try { try {
check(meetingId, String); check(meetingId, String);
check(locale, String); check(locale, String);
@ -20,7 +20,7 @@ export default function updateCaptionsOwner(meetingId, locale, ownerId) {
}, },
}; };
const numberAffected = Captions.upsert(selector, modifier); const numberAffected = await Captions.upsert(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.info(`Added captions=${locale} owner=${ownerId} meeting=${meetingId}`); Logger.info(`Added captions=${locale} owner=${ownerId} meeting=${meetingId}`);

View File

@ -3,8 +3,9 @@ import { Meteor } from 'meteor/meteor';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation'; import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
function captions() { async function captions() {
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing Captions was requested by unauth connection ${this.connection.id}`); Logger.warn(`Publishing Captions was requested by unauth connection ${this.connection.id}`);

View File

@ -22,7 +22,7 @@ export const indexOf = [].indexOf || function (item) {
return -1; return -1;
}; };
export const processForHTML5ServerOnly = (fn) => (message, ...args) => { export const processForHTML5ServerOnly = (fn) => async (message, ...args) => {
const { envelope } = message; const { envelope } = message;
const { routing } = envelope; const { routing } = envelope;
const { msgType, meetingId, userId } = routing; const { msgType, meetingId, userId } = routing;
@ -32,7 +32,7 @@ export const processForHTML5ServerOnly = (fn) => (message, ...args) => {
meetingId, meetingId,
}; };
const user = Users.findOne(selector); const user = await Users.findOneAsync(selector);
const shouldSkip = user && msgType === MSG_DIRECT_TYPE && userId !== NODE_USER && user.clientType !== 'HTML5'; const shouldSkip = user && msgType === MSG_DIRECT_TYPE && userId !== NODE_USER && user.clientType !== 'HTML5';
if (shouldSkip) return () => { }; if (shouldSkip) return () => { };
@ -51,9 +51,10 @@ export const extractCredentials = (credentials) => {
// The provided function is publication-specific and must check the "survival condition" of the publication. // The provided function is publication-specific and must check the "survival condition" of the publication.
export const publicationSafeGuard = function (fn, self) { export const publicationSafeGuard = function (fn, self) {
let stopped = false; let stopped = false;
const periodicCheck = function () { const periodicCheck = async function () {
if (stopped) return; if (stopped) return;
if (!fn()) { const result = await fn();
if (!result) {
self.added(self._name, 'publication-stop-marker', { id: 'publication-stop-marker', stopped: true }); self.added(self._name, 'publication-stop-marker', { id: 'publication-stop-marker', stopped: true });
self.stop(); self.stop();
} else Meteor.setTimeout(periodicCheck, 1000); } else Meteor.setTimeout(periodicCheck, 1000);

View File

@ -7,7 +7,7 @@ const collectionOptions = Meteor.isClient ? {
const ConnectionStatus = new Mongo.Collection('connection-status', collectionOptions); const ConnectionStatus = new Mongo.Collection('connection-status', collectionOptions);
if (Meteor.isServer) { if (Meteor.isServer) {
ConnectionStatus._ensureIndex({ meetingId: 1, userId: 1 }); ConnectionStatus.createIndexAsync({ meetingId: 1, userId: 1 });
} }
export default ConnectionStatus; export default ConnectionStatus;

View File

@ -1,7 +1,7 @@
import ConnectionStatus from '/imports/api/connection-status'; import ConnectionStatus from '/imports/api/connection-status';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function clearConnectionStatus(meetingId) { export default async function clearConnectionStatus(meetingId) {
const selector = {}; const selector = {};
if (meetingId) { if (meetingId) {
@ -9,7 +9,7 @@ export default function clearConnectionStatus(meetingId) {
} }
try { try {
const numberAffected = ConnectionStatus.remove(selector); const numberAffected = await ConnectionStatus.removeAsync(selector);
if (numberAffected) { if (numberAffected) {
if (meetingId) { if (meetingId) {

View File

@ -7,7 +7,7 @@ const STATS = Meteor.settings.public.stats;
const STATS_INTERVAL = STATS.interval; const STATS_INTERVAL = STATS.interval;
const STATS_CRITICAL_RTT = STATS.rtt[STATS.rtt.length - 1]; const STATS_CRITICAL_RTT = STATS.rtt[STATS.rtt.length - 1];
export default function updateConnectionStatus(meetingId, userId, status) { export default async function updateConnectionStatus(meetingId, userId, status) {
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);
@ -32,14 +32,15 @@ export default function updateConnectionStatus(meetingId, userId, status) {
} }
try { try {
const { numberAffected } = ConnectionStatus.upsert(selector, { $set: modifier }); const { numberAffected } = await ConnectionStatus.upsertAsync(selector, { $set: modifier });
if (numberAffected && status !== 'normal') { if (numberAffected && status !== 'normal') {
changeHasConnectionStatus(true, userId, meetingId); await changeHasConnectionStatus(true, userId, meetingId);
Logger.verbose(`Updated connection status meetingId=${meetingId} userId=${userId} status=${status}`); Logger.verbose(`Updated connection status meetingId=${meetingId} userId=${userId} status=${status}`);
} }
Meteor.setTimeout(() => { Meteor.setTimeout(async () => {
const connectionLossTimeThreshold = new Date().getTime() - (STATS_INTERVAL + STATS_CRITICAL_RTT); const connectionLossTimeThreshold = new Date()
.getTime() - (STATS_INTERVAL + STATS_CRITICAL_RTT);
const selectorNotResponding = { const selectorNotResponding = {
meetingId, meetingId,
@ -48,15 +49,15 @@ export default function updateConnectionStatus(meetingId, userId, status) {
clientNotResponding: false, clientNotResponding: false,
}; };
const numberAffectedNotResponding = ConnectionStatus.update(selectorNotResponding, { const numberAffectedNotResponding = await ConnectionStatus
$set: { clientNotResponding: true } .updateAsync(selectorNotResponding, {
}); $set: { clientNotResponding: true },
});
if (numberAffectedNotResponding) { if (numberAffectedNotResponding) {
Logger.info(`Updated clientNotResponding=true meetingId=${meetingId} userId=${userId}`); Logger.info(`Updated clientNotResponding=true meetingId=${meetingId} userId=${userId}`);
} }
}, STATS_INTERVAL + STATS_CRITICAL_RTT); }, STATS_INTERVAL + STATS_CRITICAL_RTT);
} catch (err) { } catch (err) {
Logger.error(`Updating connection status meetingId=${meetingId} userId=${userId}: ${err}`); Logger.error(`Updating connection status meetingId=${meetingId} userId=${userId}: ${err}`);
} }

View File

@ -8,8 +8,9 @@ import { publicationSafeGuard } from '/imports/api/common/server/helpers';
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator; const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
function connectionStatus() { async function connectionStatus() {
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing ConnectionStatus was requested by unauth connection ${this.connection.id}`); Logger.warn(`Publishing ConnectionStatus was requested by unauth connection ${this.connection.id}`);
@ -27,15 +28,16 @@ function connectionStatus() {
status: 1, status: 1,
statusUpdatedAt: 1, statusUpdatedAt: 1,
clientNotResponding: 1, clientNotResponding: 1,
} };
const User = Users.findOne({ userId, meetingId }, { fields: { role: 1 } }); const User = await Users.findOneAsync({ userId, meetingId }, { fields: { role: 1 } });
Logger.info(`Publishing connection status for ${meetingId} ${userId}`); Logger.info(`Publishing connection status for ${meetingId} ${userId}`);
if (!!User && User.role === ROLE_MODERATOR) { if (!!User && User.role === ROLE_MODERATOR) {
// Monitor this publication and stop it when user is not a moderator anymore // Monitor this publication and stop it when user is not a moderator anymore
const comparisonFunc = () => { const comparisonFunc = async () => {
const user = Users.findOne({ userId, meetingId }, { fields: { role: 1, userId: 1 } }); const user = await Users
.findOneAsync({ userId, meetingId }, { fields: { role: 1, userId: 1 } });
const condition = user.role === ROLE_MODERATOR; const condition = user.role === ROLE_MODERATOR;
if (!condition) { if (!condition) {
@ -46,10 +48,10 @@ function connectionStatus() {
return condition; return condition;
}; };
publicationSafeGuard(comparisonFunc, this); publicationSafeGuard(comparisonFunc, this);
return ConnectionStatus.find({ meetingId }, { fields: fields }); return ConnectionStatus.find({ meetingId }, { fields });
} }
return ConnectionStatus.find({ meetingId, userId }, { fields: fields }); return ConnectionStatus.find({ meetingId, userId }, { fields });
} }
function publish(...args) { function publish(...args) {

View File

@ -1,7 +1,7 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import startExternalVideo from '../modifiers/startExternalVideo'; import startExternalVideo from '../modifiers/startExternalVideo';
export default function handleStartExternalVideo({ header, body }, meetingId) { export default async function handleStartExternalVideo({ header, body }, meetingId) {
check(header, Object); check(header, Object);
check(body, Object); check(body, Object);
check(meetingId, String); check(meetingId, String);
@ -9,5 +9,5 @@ export default function handleStartExternalVideo({ header, body }, meetingId) {
const { userId } = header; const { userId } = header;
const { externalVideoUrl } = body; const { externalVideoUrl } = body;
startExternalVideo(meetingId, userId, externalVideoUrl); await startExternalVideo(meetingId, userId, externalVideoUrl);
} }

View File

@ -1,11 +1,11 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import stopExternalVideo from '../modifiers/stopExternalVideo'; import stopExternalVideo from '../modifiers/stopExternalVideo';
export default function handleStopExternalVideo({ header }, meetingId) { export default async function handleStopExternalVideo({ header }, meetingId) {
check(header, Object); check(header, Object);
check(meetingId, String); check(meetingId, String);
const { userId } = header; const { userId } = header;
stopExternalVideo(userId, meetingId); await stopExternalVideo(userId, meetingId);
} }

View File

@ -1,7 +1,7 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import updateExternalVideo from '../modifiers/updateExternalVideo'; import updateExternalVideo from '../modifiers/updateExternalVideo';
export default function handleUpdateExternalVideo({ header, body }, meetingId) { export default async function handleUpdateExternalVideo({ header, body }, meetingId) {
check(header, Object); check(header, Object);
check(body, Object); check(body, Object);
check(meetingId, String); check(meetingId, String);
@ -15,5 +15,5 @@ export default function handleUpdateExternalVideo({ header, body }, meetingId) {
state, state,
} = body; } = body;
updateExternalVideo(meetingId, userId, status, rate, time, state); await updateExternalVideo(meetingId, userId, status, rate, time, state);
} }

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import { ExternalVideoMeetings } from '/imports/api/meetings'; import { ExternalVideoMeetings } from '/imports/api/meetings';
export default function startExternalVideo(meetingId, userId, externalVideoUrl) { export default async function startExternalVideo(meetingId, userId, externalVideoUrl) {
try { try {
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);
@ -12,7 +12,7 @@ export default function startExternalVideo(meetingId, userId, externalVideoUrl)
const modifier = { $set: { externalVideoUrl } }; const modifier = { $set: { externalVideoUrl } };
Logger.info(`User id=${userId} sharing an external video: ${externalVideoUrl} for meeting ${meetingId}`); Logger.info(`User id=${userId} sharing an external video: ${externalVideoUrl} for meeting ${meetingId}`);
ExternalVideoMeetings.update(selector, modifier); await ExternalVideoMeetings.updateAsync(selector, modifier);
} catch (err) { } catch (err) {
Logger.error(`Error on setting shared external video start in Meetings collection: ${err}`); Logger.error(`Error on setting shared external video start in Meetings collection: ${err}`);
} }

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import { ExternalVideoMeetings } from '/imports/api/meetings'; import { ExternalVideoMeetings } from '/imports/api/meetings';
export default function stopExternalVideo(userId, meetingId) { export default async function stopExternalVideo(userId, meetingId) {
try { try {
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);
@ -11,7 +11,7 @@ export default function stopExternalVideo(userId, meetingId) {
const modifier = { $set: { externalVideoUrl: null } }; const modifier = { $set: { externalVideoUrl: null } };
Logger.info(`External video stop sharing was initiated by:[${userId}] for meeting ${meetingId}`); Logger.info(`External video stop sharing was initiated by:[${userId}] for meeting ${meetingId}`);
ExternalVideoMeetings.update(selector, modifier); await ExternalVideoMeetings.updateAsync(selector, modifier);
} catch (err) { } catch (err) {
Logger.error(`Error on setting shared external video stop in Meetings collection: ${err}`); Logger.error(`Error on setting shared external video stop in Meetings collection: ${err}`);
} }

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import ExternalVideoStreamer from '/imports/api/external-videos/server/streamer'; import ExternalVideoStreamer from '/imports/api/external-videos/server/streamer';
export default function updateExternalVideo(meetingId, userId, status, rate, time, state) { export default async function updateExternalVideo(meetingId, userId, status, rate, time, state) {
try { try {
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);

View File

@ -8,8 +8,8 @@ const GroupChatMsg = new Mongo.Collection('group-chat-msg');
const UsersTyping = new Mongo.Collection('users-typing', collectionOptions); const UsersTyping = new Mongo.Collection('users-typing', collectionOptions);
if (Meteor.isServer) { if (Meteor.isServer) {
GroupChatMsg._ensureIndex({ meetingId: 1, chatId: 1 }); GroupChatMsg.createIndexAsync({ meetingId: 1, chatId: 1 });
UsersTyping._ensureIndex({ meetingId: 1, isTypingTo: 1 }); UsersTyping.createIndexAsync({ meetingId: 1, isTypingTo: 1 });
} }
// As we store chat in context, skip adding to mini mongo // As we store chat in context, skip adding to mini mongo

View File

@ -1,12 +1,13 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import clearGroupChatMsg from '../modifiers/clearGroupChatMsg'; import clearGroupChatMsg from '../modifiers/clearGroupChatMsg';
export default function clearPublicChatHistory({ header, body }) { export default async function clearPublicChatHistory({ header, body }) {
const { meetingId } = header; const { meetingId } = header;
const { chatId } = body; const { chatId } = body;
check(meetingId, String); check(meetingId, String);
check(chatId, String); check(chatId, String);
return clearGroupChatMsg(meetingId, chatId); const result = clearGroupChatMsg(meetingId, chatId);
return result;
} }

View File

@ -9,7 +9,7 @@ const msgBuffer = [];
const bulkFn = _.throttle(addBulkGroupChatMsgs, bufferChatInsertsMs); const bulkFn = _.throttle(addBulkGroupChatMsgs, bufferChatInsertsMs);
export default function handleGroupChatMsgBroadcast({ body }, meetingId) { export default async function handleGroupChatMsgBroadcast({ body }, meetingId) {
const { chatId, msg } = body; const { chatId, msg } = body;
check(meetingId, String); check(meetingId, String);
@ -20,6 +20,6 @@ export default function handleGroupChatMsgBroadcast({ body }, meetingId) {
msgBuffer.push({ meetingId, chatId, msg }); msgBuffer.push({ meetingId, chatId, msg });
bulkFn(msgBuffer); bulkFn(msgBuffer);
} else { } else {
addGroupChatMsg(meetingId, chatId, msg); await addGroupChatMsg(meetingId, chatId, msg);
} }
} }

View File

@ -1,12 +1,12 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import startTyping from '../modifiers/startTyping'; import startTyping from '../modifiers/startTyping';
export default function handleUserTyping({ body }, meetingId) { export default async function handleUserTyping({ body }, meetingId) {
const { chatId, userId } = body; const { chatId, userId } = body;
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);
check(chatId, String); check(chatId, String);
startTyping(meetingId, userId, chatId); await startTyping(meetingId, userId, chatId);
} }

View File

@ -9,7 +9,7 @@ import Logger from '/imports/startup/server/logger';
const CHAT_CONFIG = Meteor.settings.public.chat; const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public; const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
export default function chatMessageBeforeJoinCounter() { export default async function chatMessageBeforeJoinCounter() {
try { try {
const { meetingId, requesterUserId } = extractCredentials(this.userId); const { meetingId, requesterUserId } = extractCredentials(this.userId);
@ -23,7 +23,7 @@ export default function chatMessageBeforeJoinCounter() {
], ],
}).fetch(); }).fetch();
const User = Users.findOne({ userId: requesterUserId, meetingId }); const User = await Users.findOneAsync({ userId: requesterUserId, meetingId });
const chatIdWithCounter = groupChats.map((groupChat) => { const chatIdWithCounter = groupChats.map((groupChat) => {
const msgCount = GroupChatMsg.find({ const msgCount = GroupChatMsg.find({
@ -40,4 +40,6 @@ export default function chatMessageBeforeJoinCounter() {
} catch (err) { } catch (err) {
Logger.error(`Exception while invoking method chatMessageBeforeJoinCounter ${err.stack}`); Logger.error(`Exception while invoking method chatMessageBeforeJoinCounter ${err.stack}`);
} }
//True returned because the function requires a return.
return true;
} }

View File

@ -8,7 +8,7 @@ import Logger from '/imports/startup/server/logger';
const CHAT_CONFIG = Meteor.settings.public.chat; const CHAT_CONFIG = Meteor.settings.public.chat;
const ITENS_PER_PAGE = CHAT_CONFIG.itemsPerPage; const ITENS_PER_PAGE = CHAT_CONFIG.itemsPerPage;
export default function fetchMessagePerPage(chatId, page) { export default async function fetchMessagePerPage(chatId, page) {
try { try {
const { meetingId, requesterUserId } = extractCredentials(this.userId); const { meetingId, requesterUserId } = extractCredentials(this.userId);
@ -17,9 +17,9 @@ export default function fetchMessagePerPage(chatId, page) {
check(chatId, String); check(chatId, String);
check(page, Number); check(page, Number);
const User = Users.findOne({ userId: requesterUserId, meetingId }); const User = await Users.findOneAsync({ userId: requesterUserId, meetingId });
const messages = GroupChatMsg.find( const messages = await GroupChatMsg.find(
{ chatId, meetingId, timestamp: { $lt: User.authTokenValidatedTime } }, { chatId, meetingId, timestamp: { $lt: User.authTokenValidatedTime } },
{ {
sort: { timestamp: 1 }, sort: { timestamp: 1 },
@ -27,9 +27,11 @@ export default function fetchMessagePerPage(chatId, page) {
limit: ITENS_PER_PAGE, limit: ITENS_PER_PAGE,
}, },
) )
.fetch(); .fetchAsync();
return messages; return messages;
} catch (err) { } catch (err) {
Logger.error(`Exception while invoking method fetchMessagePerPage ${err.stack}`); Logger.error(`Exception while invoking method fetchMessagePerPage ${err.stack}`);
} }
//True returned because the function requires a return.
return true;
} }

View File

@ -4,14 +4,14 @@ import { extractCredentials } from '/imports/api/common/server/helpers';
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
export default function stopUserTyping() { export default async function stopUserTyping() {
try { try {
const { meetingId, requesterUserId } = extractCredentials(this.userId); const { meetingId, requesterUserId } = extractCredentials(this.userId);
check(meetingId, String); check(meetingId, String);
check(requesterUserId, String); check(requesterUserId, String);
const userTyping = UsersTyping.findOne({ const userTyping = await UsersTyping.findOneAsync({
meetingId, meetingId,
userId: requesterUserId, userId: requesterUserId,
}); });

View File

@ -21,10 +21,10 @@ export default async function addBulkGroupChatMsgs(msgs) {
message: parseMessage(msg.message), message: parseMessage(msg.message),
sender: sender.id, sender: sender.id,
senderName: sender.name, senderName: sender.name,
senderRole: sender.role senderRole: sender.role,
}; };
}) })
.map(el => flat(el, { safe: true })); .map((el) => flat(el, { safe: true }));
try { try {
const { insertedCount } = await GroupChatMsg.rawCollection().insertMany(mappedMsgs); const { insertedCount } = await GroupChatMsg.rawCollection().insertMany(mappedMsgs);

View File

@ -17,7 +17,7 @@ export function parseMessage(message) {
return parsedMessage; return parsedMessage;
} }
export default function addGroupChatMsg(meetingId, chatId, msg) { export default async function addGroupChatMsg(meetingId, chatId, msg) {
check(meetingId, String); check(meetingId, String);
check(chatId, String); check(chatId, String);
check(msg, { check(msg, {
@ -45,10 +45,10 @@ export default function addGroupChatMsg(meetingId, chatId, msg) {
}; };
try { try {
const insertedId = GroupChatMsg.insert(msgDocument); const insertedId = await GroupChatMsg.insertAsync(msgDocument);
if (insertedId) { if (insertedId) {
changeHasMessages(true, sender.id, meetingId, chatId); await changeHasMessages(true, sender.id, meetingId, chatId);
Logger.info(`Added group-chat-msg msgId=${msg.id} chatId=${chatId} meetingId=${meetingId}`); Logger.info(`Added group-chat-msg msgId=${msg.id} chatId=${chatId} meetingId=${meetingId}`);
} }
} catch (err) { } catch (err) {

View File

@ -16,7 +16,7 @@ export function parseMessage(message) {
return parsedMessage; return parsedMessage;
} }
export default function addSystemMsg(meetingId, chatId, msg) { export default async function addSystemMsg(meetingId, chatId, msg) {
check(meetingId, String); check(meetingId, String);
check(chatId, String); check(chatId, String);
check(msg, { check(msg, {
@ -37,7 +37,7 @@ export default function addSystemMsg(meetingId, chatId, msg) {
}; };
try { try {
const insertedId = GroupChatMsg.insert(msgDocument); const insertedId = await GroupChatMsg.insertAsync(msgDocument);
if (insertedId) { if (insertedId) {
Logger.info(`Added system-msg msgId=${msg.id} chatId=${chatId} meetingId=${meetingId}`); Logger.info(`Added system-msg msgId=${msg.id} chatId=${chatId} meetingId=${meetingId}`);

View File

@ -4,7 +4,7 @@ import addSystemMsg from '/imports/api/group-chat-msg/server/modifiers/addSystem
import clearChatHasMessages from '/imports/api/users-persistent-data/server/modifiers/clearChatHasMessages'; import clearChatHasMessages from '/imports/api/users-persistent-data/server/modifiers/clearChatHasMessages';
import UsersPersistentData from '/imports/api/users-persistent-data'; import UsersPersistentData from '/imports/api/users-persistent-data';
export default function clearGroupChatMsg(meetingId, chatId) { export default async function clearGroupChatMsg(meetingId, chatId) {
const CHAT_CONFIG = Meteor.settings.public.chat; const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_SYSTEM_ID = CHAT_CONFIG.system_userid; const PUBLIC_CHAT_SYSTEM_ID = CHAT_CONFIG.system_userid;
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id; const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
@ -13,7 +13,7 @@ export default function clearGroupChatMsg(meetingId, chatId) {
if (chatId) { if (chatId) {
try { try {
const numberAffected = GroupChatMsg.remove({ meetingId, chatId }); const numberAffected = await GroupChatMsg.removeAsync({ meetingId, chatId });
if (numberAffected) { if (numberAffected) {
Logger.info(`Cleared GroupChatMsg (${meetingId}, ${chatId})`); Logger.info(`Cleared GroupChatMsg (${meetingId}, ${chatId})`);
@ -27,18 +27,17 @@ export default function clearGroupChatMsg(meetingId, chatId) {
}, },
message: CHAT_CLEAR_MESSAGE, message: CHAT_CLEAR_MESSAGE,
}; };
addSystemMsg(meetingId, PUBLIC_GROUP_CHAT_ID, clearMsg); await addSystemMsg(meetingId, PUBLIC_GROUP_CHAT_ID, clearMsg);
clearChatHasMessages(meetingId, chatId); await clearChatHasMessages(meetingId, chatId);
//clear offline users' data //clear offline users' data
const selector = { const selector = {
meetingId, meetingId,
'shouldPersist.hasConnectionStatus': { $ne: true }, 'shouldPersist.hasConnectionStatus': { $ne: true },
'shouldPersist.hasMessages.private': { $ne: true }, 'shouldPersist.hasMessages.private': { $ne: true },
loggedOut: true loggedOut: true,
}; };
await UsersPersistentData.removeAsync(selector);
UsersPersistentData.remove(selector);
} }
} catch (err) { } catch (err) {
Logger.error(`Error on clearing GroupChat (${meetingId}, ${chatId}). ${err}`); Logger.error(`Error on clearing GroupChat (${meetingId}, ${chatId}). ${err}`);
@ -48,7 +47,7 @@ export default function clearGroupChatMsg(meetingId, chatId) {
if (meetingId) { if (meetingId) {
try { try {
const numberAffected = GroupChatMsg.remove({ meetingId }); const numberAffected = await GroupChatMsg.removeAsync({ meetingId });
if (numberAffected) { if (numberAffected) {
Logger.info(`Cleared GroupChatMsg (${meetingId})`); Logger.info(`Cleared GroupChatMsg (${meetingId})`);
@ -58,10 +57,11 @@ export default function clearGroupChatMsg(meetingId, chatId) {
} }
} else { } else {
try { try {
const numberAffected = GroupChatMsg.remove({ chatId: { $eq: PUBLIC_GROUP_CHAT_ID } }); const numberAffected = await GroupChatMsg
.removeAsync({ chatId: { $eq: PUBLIC_GROUP_CHAT_ID } });
if (numberAffected) { if (numberAffected) {
clearChatHasMessages(meetingId, chatId=PUBLIC_GROUP_CHAT_ID); await clearChatHasMessages(meetingId, chatId=PUBLIC_GROUP_CHAT_ID);
Logger.info('Cleared GroupChatMsg (all)'); Logger.info('Cleared GroupChatMsg (all)');
} }
@ -69,4 +69,6 @@ export default function clearGroupChatMsg(meetingId, chatId) {
Logger.error(`Error on clearing GroupChatMsg (all). ${err}`); Logger.error(`Error on clearing GroupChatMsg (all). ${err}`);
} }
} }
//True resturned because the function requires a return.
return true;
} }

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import GroupChatMsg from '/imports/api/group-chat-msg'; import GroupChatMsg from '/imports/api/group-chat-msg';
export default function removeGroupChatMsg(meetingId, chatId) { export default async function removeGroupChatMsg(meetingId, chatId) {
check(meetingId, String); check(meetingId, String);
check(chatId, String); check(chatId, String);
@ -12,7 +12,7 @@ export default function removeGroupChatMsg(meetingId, chatId) {
}; };
try { try {
const numberAffected = GroupChatMsg.remove(selector); const numberAffected = await GroupChatMsg.removeAsync(selector);
if (numberAffected) { if (numberAffected) {
Logger.info(`Removed group-chat-msg id=${chatId} meeting=${meetingId}`); Logger.info(`Removed group-chat-msg id=${chatId} meeting=${meetingId}`);

View File

@ -6,7 +6,7 @@ import stopTyping from './stopTyping';
const TYPING_TIMEOUT = 5000; const TYPING_TIMEOUT = 5000;
export default function startTyping(meetingId, userId, chatId) { export default async function startTyping(meetingId, userId, chatId) {
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);
@ -15,7 +15,7 @@ export default function startTyping(meetingId, userId, chatId) {
userId, userId,
}; };
const user = Users.findOne(selector, { fields: { name: 1, role: 1 } }); const user = await Users.findOneAsync(selector, { fields: { name: 1, role: 1 } });
const modifier = { const modifier = {
meetingId, meetingId,
@ -26,7 +26,7 @@ export default function startTyping(meetingId, userId, chatId) {
time: (new Date()), time: (new Date()),
}; };
const typingUser = UsersTyping.findOne(selector, { const typingUser = await UsersTyping.findOneAsync(selector, {
fields: { fields: {
time: 1, time: 1,
}, },
@ -37,7 +37,7 @@ export default function startTyping(meetingId, userId, chatId) {
} }
try { try {
const { numberAffected } = UsersTyping.upsert(selector, modifier); const { numberAffected } = await UsersTyping.upsertAsync(selector, modifier);
if (numberAffected) { if (numberAffected) {
Logger.debug('Typing indicator update', { userId, chatId }); Logger.debug('Typing indicator update', { userId, chatId });

View File

@ -2,7 +2,7 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import { UsersTyping } from '/imports/api/group-chat-msg'; import { UsersTyping } from '/imports/api/group-chat-msg';
export default function stopTyping(meetingId, userId, sendMsgInitiated = false) { export default async function stopTyping(meetingId, userId, sendMsgInitiated = false) {
check(meetingId, String); check(meetingId, String);
check(userId, String); check(userId, String);
check(sendMsgInitiated, Boolean); check(sendMsgInitiated, Boolean);
@ -12,12 +12,12 @@ export default function stopTyping(meetingId, userId, sendMsgInitiated = false)
userId, userId,
}; };
const user = UsersTyping.findOne(selector); const user = await UsersTyping.findOneAsync(selector);
const stillTyping = !sendMsgInitiated && user && (new Date()) - user.time < 3000; const stillTyping = !sendMsgInitiated && user && (new Date()) - user.time < 3000;
if (stillTyping) return; if (stillTyping) return;
try { try {
const numberAffected = UsersTyping.remove(selector); const numberAffected = await UsersTyping.removeAsync(selector);
if (numberAffected) { if (numberAffected) {
Logger.debug('Stopped typing indicator', { userId }); Logger.debug('Stopped typing indicator', { userId });

View File

@ -6,9 +6,10 @@ import GroupChat from '/imports/api/group-chat';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation'; import AuthTokenValidation, { ValidationStates } from '/imports/api/auth-token-validation';
function groupChatMsg(chatCount) { async function groupChatMsg(chatCount) {
check(chatCount, Number); check(chatCount, Number);
const tokenValidation = AuthTokenValidation.findOne({ connectionId: this.connection.id }); const tokenValidation = await AuthTokenValidation
.findOneAsync({ connectionId: this.connection.id });
if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) { if (!tokenValidation || tokenValidation.validationStatus !== ValidationStates.VALIDATED) {
Logger.warn(`Publishing GroupChatMsg was requested by unauth connection ${this.connection.id}`); Logger.warn(`Publishing GroupChatMsg was requested by unauth connection ${this.connection.id}`);
@ -22,15 +23,15 @@ function groupChatMsg(chatCount) {
Logger.debug('Publishing group-chat-msg', { meetingId, userId }); Logger.debug('Publishing group-chat-msg', { meetingId, userId });
const chats = GroupChat.find({ const chats = await GroupChat.find({
$or: [ $or: [
{ meetingId, users: { $all: [userId] } }, { meetingId, users: { $all: [userId] } },
], ],
}).fetch(); }).fetchAsync();
const chatsIds = chats.map((ct) => ct.chatId); const chatsIds = chats.map((ct) => ct.chatId);
const User = Users.findOne({ userId, meetingId }); const User = await Users.findOneAsync({ userId, meetingId });
const selector = { const selector = {
timestamp: { $gte: User.authTokenValidatedTime }, timestamp: { $gte: User.authTokenValidatedTime },
$or: [ $or: [

View File

@ -7,7 +7,7 @@ const collectionOptions = Meteor.isClient ? {
const GroupChat = new Mongo.Collection('group-chat', collectionOptions); const GroupChat = new Mongo.Collection('group-chat', collectionOptions);
if (Meteor.isServer) { if (Meteor.isServer) {
GroupChat._ensureIndex({ GroupChat.createIndexAsync({
meetingId: 1, chatId: 1, access: 1, users: 1, meetingId: 1, chatId: 1, access: 1, users: 1,
}); });
} }

View File

@ -1,9 +1,9 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import addGroupChat from '../modifiers/addGroupChat'; import addGroupChat from '../modifiers/addGroupChat';
export default function handleGroupChatCreated({ body }, meetingId) { export default async function handleGroupChatCreated({ body }, meetingId) {
check(meetingId, String); check(meetingId, String);
check(body, Object); check(body, Object);
addGroupChat(meetingId, body); await addGroupChat(meetingId, body);
} }

View File

@ -1,9 +1,9 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import addGroupChat from '../modifiers/addGroupChat'; import addGroupChat from '../modifiers/addGroupChat';
export default function handleGroupChatDestroyed({ body }, meetingId) { export default async function handleGroupChatDestroyed({ body }, meetingId) {
check(meetingId, String); check(meetingId, String);
check(body, Object); check(body, Object);
addGroupChat(meetingId, body); await addGroupChat(meetingId, body);
} }

View File

@ -1,11 +1,14 @@
import { check } from 'meteor/check'; import { check } from 'meteor/check';
import addGroupChat from '../modifiers/addGroupChat'; import addGroupChat from '../modifiers/addGroupChat';
export default function handleGroupChats({ body }, meetingId) { export default async function handleGroupChats({ body }, meetingId) {
const { chats } = body; const { chats } = body;
check(meetingId, String); check(meetingId, String);
check(chats, Array); check(chats, Array);
chats.forEach(chat => addGroupChat(meetingId, chat)); await new Promise
.all(chats.map(async (chat) => {
await addGroupChat(meetingId, chat);
}));
} }

View File

@ -3,7 +3,7 @@ import { Match, check } from 'meteor/check';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import GroupChat from '/imports/api/group-chat'; import GroupChat from '/imports/api/group-chat';
export default function addGroupChat(meetingId, chat) { export default async function addGroupChat(meetingId, chat) {
check(meetingId, String); check(meetingId, String);
check(chat, { check(chat, {
id: Match.Maybe(String), id: Match.Maybe(String),
@ -34,7 +34,7 @@ export default function addGroupChat(meetingId, chat) {
}; };
try { try {
const { insertedId } = GroupChat.upsert(selector, modifier); const { insertedId } = await GroupChat.upsertAsync(selector, modifier);
if (insertedId) { if (insertedId) {
Logger.info(`Added group-chat chatId=${chatDocument.chatId} meetingId=${meetingId}`); Logger.info(`Added group-chat chatId=${chatDocument.chatId} meetingId=${meetingId}`);

View File

@ -2,10 +2,10 @@ import GroupChat from '/imports/api/group-chat';
import Logger from '/imports/startup/server/logger'; import Logger from '/imports/startup/server/logger';
import clearGroupChatMsg from '/imports/api/group-chat-msg/server/modifiers/clearGroupChatMsg'; import clearGroupChatMsg from '/imports/api/group-chat-msg/server/modifiers/clearGroupChatMsg';
export default function clearGroupChat(meetingId) { export default async function clearGroupChat(meetingId) {
try { try {
clearGroupChatMsg(meetingId); await clearGroupChatMsg(meetingId);
const numberAffected = GroupChat.remove({ meetingId }); const numberAffected = await GroupChat.removeAsync({ meetingId });
if (numberAffected) { if (numberAffected) {
Logger.info(`Cleared GroupChat (${meetingId})`); Logger.info(`Cleared GroupChat (${meetingId})`);

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