Merge 2.2.29 and 2.2.30 into 2.3.x
This commit is contained in:
commit
3faabd1821
@ -357,7 +357,10 @@ object Polls {
|
||||
def respondToQuestion(pollId: String, questionID: Int, responseID: Int, responder: Responder, polls: Polls) {
|
||||
polls.polls.get(pollId) match {
|
||||
case Some(p) => {
|
||||
p.respondToQuestion(questionID, responseID, responder)
|
||||
if (!p.getResponders().exists(_ == responder)) {
|
||||
p.addResponder(responder)
|
||||
p.respondToQuestion(questionID, responseID, responder)
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
}
|
||||
@ -499,6 +502,7 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I
|
||||
private var _stopped: Boolean = false
|
||||
private var _showResult: Boolean = false
|
||||
private var _numResponders: Int = 0
|
||||
private var _responders = new ArrayBuffer[Responder]()
|
||||
|
||||
def showingResult() { _showResult = true }
|
||||
def showResult(): Boolean = { _showResult }
|
||||
@ -513,6 +517,9 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I
|
||||
_stopped = false
|
||||
}
|
||||
|
||||
def addResponder(responder: Responder) { _responders += (responder) }
|
||||
def getResponders(): ArrayBuffer[Responder] = { return _responders }
|
||||
|
||||
def hasResponses(): Boolean = {
|
||||
questions.foreach(q => {
|
||||
if (q.hasResponders) return true
|
||||
|
@ -981,6 +981,11 @@ public class MeetingService implements MessageListener {
|
||||
User vuser = m.userLeft(message.userId);
|
||||
} else {
|
||||
user.setVoiceJoined(false);
|
||||
// userLeftVoice is also used when user leaves Global (listenonly)
|
||||
// audio. Also tetting listenOnly to false is not a problem,
|
||||
// once user can't join both voice/mic and global/listenonly
|
||||
// at the same time.
|
||||
user.setListeningOnly(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,12 +103,12 @@ enableUFWRules() {
|
||||
|
||||
|
||||
enableMultipleKurentos() {
|
||||
echo " - Configuring three Kurento Media Servers: one for listen only, webcam, and screeshare"
|
||||
echo " - Configuring three Kurento Media Servers (listen only, webcam, and screeshare)"
|
||||
|
||||
# Step 1. Setup shared certificate between FreeSWITCH and Kurento
|
||||
|
||||
HOSTNAME=$(cat /etc/nginx/sites-available/bigbluebutton | grep -v '#' | sed -n '/server_name/{s/.*server_name[ ]*//;s/;//;p}' | cut -d' ' -f1 | head -n 1)
|
||||
openssl req -x509 -new -nodes -newkey rsa:2048 -sha256 -days 3650 -subj "/C=BR/ST=Ottawa/O=BigBlueButton Inc./OU=Live/CN=$HOSTNAME" -keyout /tmp/dtls-srtp-key.pem -out /tmp/dtls-srtp-cert.pem
|
||||
openssl req -x509 -new -nodes -newkey rsa:4096 -sha256 -days 3650 -subj "/C=BR/ST=Ottawa/O=BigBlueButton Inc./OU=Live/CN=$HOSTNAME" -keyout /tmp/dtls-srtp-key.pem -out /tmp/dtls-srtp-cert.pem
|
||||
cat /tmp/dtls-srtp-key.pem /tmp/dtls-srtp-cert.pem > /etc/kurento/dtls-srtp.pem
|
||||
cat /tmp/dtls-srtp-key.pem /tmp/dtls-srtp-cert.pem > /opt/freeswitch/etc/freeswitch/tls/dtls-srtp.pem
|
||||
|
||||
@ -119,50 +119,57 @@ enableMultipleKurentos() {
|
||||
for i in `seq 8888 8890`; do
|
||||
|
||||
cat > /usr/lib/systemd/system/kurento-media-server-${i}.service << HERE
|
||||
# /usr/lib/systemd/system/kurento-media-server-#{i}.service
|
||||
[Unit]
|
||||
Description=Kurento Media Server daemon (${i})
|
||||
After=network.target
|
||||
PartOf=kurento-media-server.service
|
||||
After=kurento-media-server.service
|
||||
# /usr/lib/systemd/system/kurento-media-server-#{i}.service
|
||||
[Unit]
|
||||
Description=Kurento Media Server daemon (${i})
|
||||
After=network.target
|
||||
PartOf=kurento-media-server.service
|
||||
After=kurento-media-server.service
|
||||
|
||||
[Service]
|
||||
UMask=0002
|
||||
Environment=KURENTO_LOGS_PATH=/var/log/kurento-media-server
|
||||
Environment=KURENTO_CONF_FILE=/etc/kurento/kurento-${i}.conf.json
|
||||
User=kurento
|
||||
Group=kurento
|
||||
LimitNOFILE=1000000
|
||||
ExecStartPre=-/bin/rm -f /var/kurento/.cache/gstreamer-1.5/registry.x86_64.bin
|
||||
ExecStart=/usr/bin/kurento-media-server --gst-debug-level=3 --gst-debug="3,Kurento*:4,kms*:4,KurentoWebSocketTransport:5"
|
||||
Type=simple
|
||||
PIDFile=/var/run/kurento-media-server-${i}.pid
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=kurento-media-server.service
|
||||
[Service]
|
||||
UMask=0002
|
||||
Environment=KURENTO_LOGS_PATH=/var/log/kurento-media-server
|
||||
Environment=KURENTO_CONF_FILE=/etc/kurento/kurento-${i}.conf.json
|
||||
User=kurento
|
||||
Group=kurento
|
||||
LimitNOFILE=1000000
|
||||
ExecStartPre=-/bin/rm -f /var/kurento/.cache/gstreamer-1.5/registry.x86_64.bin
|
||||
ExecStart=/usr/bin/kurento-media-server --gst-debug-level=3 --gst-debug="3,Kurento*:4,kms*:4,KurentoWebSocketTransport:5"
|
||||
Type=simple
|
||||
PIDFile=/var/run/kurento-media-server-${i}.pid
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=kurento-media-server.service
|
||||
HERE
|
||||
|
||||
# Make a new configuration file each instance of Kurento that binds to a different port
|
||||
cp /etc/kurento/kurento.conf.json /etc/kurento/kurento-${i}.conf.json
|
||||
sed -i "s/8888/${i}/g" /etc/kurento/kurento-${i}.conf.json
|
||||
|
||||
done
|
||||
|
||||
# Step 3. Override the main kurento-media-server unit to start/stop the three Kurento instances
|
||||
|
||||
cat > /etc/systemd/system/kurento-media-server.service << HERE
|
||||
[Unit]
|
||||
Description=Kurento Media Server
|
||||
[Unit]
|
||||
Description=Kurento Media Server
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/true
|
||||
RemainAfterExit=yes
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/true
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
HERE
|
||||
|
||||
# Step 4. Extend bbb-webrtc-sfu unit to wait for all three KMS servers to start
|
||||
|
||||
mkdir -p /etc/systemd/system/bbb-webrtc-sfu.service.d
|
||||
cat > /etc/systemd/system/bbb-webrtc-sfu.service.d/override.conf << HERE
|
||||
[Unit]
|
||||
After=
|
||||
After=syslog.target network.target freeswitch.service kurento-media-server-8888.service kurento-media-server-8889.service kurento-media-server-8890.service
|
||||
HERE
|
||||
|
||||
systemctl daemon-reload
|
||||
@ -172,7 +179,7 @@ HERE
|
||||
done
|
||||
|
||||
|
||||
# Step 4. Modify bbb-webrtc-sfu config to use the three Kurento servers
|
||||
# Step 5. Modify bbb-webrtc-sfu config to use the three Kurento servers
|
||||
|
||||
KURENTO_CONFIG=/usr/local/bigbluebutton/bbb-webrtc-sfu/config/default.yml
|
||||
|
||||
@ -204,6 +211,8 @@ disableMultipleKurentos() {
|
||||
|
||||
# Remove the overrride (restoring the original kurento-media-server.service unit file)
|
||||
rm -f /etc/systemd/system/kurento-media-server.service
|
||||
rm -f /etc/systemd/system/bbb-webrtc-sfu.service.d/override.conf
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
# Restore bbb-webrtc-sfu configuration to use a single instance of Kurento
|
||||
@ -244,6 +253,8 @@ source /etc/bigbluebutton/bbb-conf/apply-lib.sh
|
||||
#enableHTML5CameraQualityThresholds
|
||||
#enableHTML5WebcamPagination
|
||||
|
||||
#enableMultipleKurentos
|
||||
|
||||
HERE
|
||||
chmod +x /etc/bigbluebutton/bbb-conf/apply-config.sh
|
||||
## Stop Copying HERE
|
||||
|
@ -787,6 +787,26 @@ check_configuration() {
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
|
||||
CHECK_STUN=$(xmlstarlet sel -t -m '//X-PRE-PROCESS[@cmd="set" and starts-with(@data, "external_rtp_ip=")]' -v @data $FREESWITCH_VARS | sed 's/external_rtp_ip=stun://g')
|
||||
if [ "$CHECK_STUN" == "stun.freeswitch.org" ]; then
|
||||
echo
|
||||
echo "# Warning: Detected FreeSWITCH is using default stun.freeswitch.org server. See"
|
||||
echo "#"
|
||||
echo "# http://docs.bigbluebutton.org/2.2/troubleshooting.html#freeswitch-using-default-stun-server"
|
||||
echo "#"
|
||||
echo
|
||||
fi
|
||||
|
||||
if ! which ufw; then
|
||||
echo
|
||||
echo "# Warning: No firewall detected. Recommend using setting up a firewall for your server"
|
||||
echo "#"
|
||||
echo "# http://docs.bigbluebutton.org/2.2/troubleshooting.html#freeswitch-using-default-stun-server"
|
||||
echo "#"
|
||||
echo
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
update_gstreamer() {
|
||||
@ -1111,28 +1131,30 @@ check_state() {
|
||||
echo "#"
|
||||
fi
|
||||
|
||||
if [ "$PROTOCOL" == "https" ]; then
|
||||
if ! cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1 | grep -q https; then
|
||||
echo "# Warning: You have this server defined for https, but in"
|
||||
echo "#"
|
||||
echo "# $SIP_CONFIG"
|
||||
echo "#"
|
||||
echo "# did not find the use of https in definition for proxy_pass"
|
||||
echo "#"
|
||||
echo "# $(cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1)"
|
||||
echo "#"
|
||||
fi
|
||||
if [ "$(yq r /usr/share/meteor/bundle/programs/server/assets/app/config/settings.yml public.media.sipjsHackViaWs)" != "true" ]; then
|
||||
if [ "$PROTOCOL" == "https" ]; then
|
||||
if ! cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1 | grep -q https; then
|
||||
echo "# Warning: You have this server defined for https, but in"
|
||||
echo "#"
|
||||
echo "# $SIP_CONFIG"
|
||||
echo "#"
|
||||
echo "# did not find the use of https in definition for proxy_pass"
|
||||
echo "#"
|
||||
echo "# $(cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1)"
|
||||
echo "#"
|
||||
fi
|
||||
|
||||
if ! cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1 | grep -q 7443; then
|
||||
echo
|
||||
echo "# Warning: You have this server defined for https, but in"
|
||||
echo "#"
|
||||
echo "# $SIP_CONFIG"
|
||||
echo "#"
|
||||
echo "# did not find the use of port 7443 in definition for proxy_pass"
|
||||
echo "#"
|
||||
echo "# $(cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1)"
|
||||
echo "#"
|
||||
if ! cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1 | grep -q 7443; then
|
||||
echo
|
||||
echo "# Warning: You have this server defined for https, but in"
|
||||
echo "#"
|
||||
echo "# $SIP_CONFIG"
|
||||
echo "#"
|
||||
echo "# did not find the use of port 7443 in definition for proxy_pass"
|
||||
echo "#"
|
||||
echo "# $(cat $SIP_CONFIG | grep -v '#' | grep proxy_pass | head -n 1)"
|
||||
echo "#"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -1348,7 +1370,7 @@ if [ $ZIP ]; then
|
||||
tar rf $TMP_LOG_FILE /var/log/mongodb > /dev/null 2>&1
|
||||
tar rf $TMP_LOG_FILE /var/log/redis > /dev/null 2>&1
|
||||
tar rf $TMP_LOG_FILE /var/log/nginx/error.log* > /dev/null 2>&1
|
||||
tar rf $TMP_LOG_FILE /var/log/nginx/bigbluebutton.access.log* > /dev/null 2>&1
|
||||
tar rf $TMP_LOG_FILE /var/log/nginx/bigbluebutton.access.log* > /dev/null 2>&1
|
||||
tar rfh $TMP_LOG_FILE /opt/freeswitch/var/log/freeswitch/ > /dev/null 2>&1
|
||||
|
||||
if [ -f /var/log/nginx/html5-client.log ]; then
|
||||
@ -1668,7 +1690,7 @@ if [ $CLEAN ]; then
|
||||
rm -f /var/log/bbb-fsesl-akka/*
|
||||
fi
|
||||
|
||||
if [ -d /var/log/bbb-apps-akka ]; then
|
||||
if [ -d /var/log/bbb-apps-akka ]; then
|
||||
rm -f /var/log/bbb-apps-akka/*
|
||||
fi
|
||||
|
||||
|
@ -116,6 +116,13 @@ need_root() {
|
||||
fi
|
||||
}
|
||||
|
||||
need_root_or_bigbluebutton() {
|
||||
if [ $EUID != 0 -a "$USER" != 'bigbluebutton']; then
|
||||
echo "Need to be user root or bigbluebutton to run this option"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_header() {
|
||||
if [ ! $HEADER ]; then
|
||||
echo
|
||||
@ -216,7 +223,7 @@ while [ $# -gt 0 ]; do
|
||||
fi
|
||||
|
||||
if [ "$1" = "-delete" -o "$1" = "--delete" ]; then
|
||||
need_root
|
||||
need_root_or_bigbluebutton
|
||||
if [ ! -z "${2}" ]; then
|
||||
MEETING_ID="${2}"
|
||||
shift
|
||||
|
@ -13,7 +13,7 @@ function annotations() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing Annotations for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Annotations', { meetingId, userId });
|
||||
|
||||
return Annotations.find({ meetingId });
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ const MEDIA_TAG = MEDIA.mediaTag;
|
||||
const CALL_TRANSFER_TIMEOUT = MEDIA.callTransferTimeout;
|
||||
const CALL_HANGUP_TIMEOUT = MEDIA.callHangupTimeout;
|
||||
const CALL_HANGUP_MAX_RETRIES = MEDIA.callHangupMaximumRetries;
|
||||
const SIPJS_HACK_VIA_WS = MEDIA.sipjsHackViaWs;
|
||||
const IPV4_FALLBACK_DOMAIN = Meteor.settings.public.app.ipv4FallbackDomain;
|
||||
const CALL_CONNECT_TIMEOUT = 20000;
|
||||
const ICE_NEGOTIATION_TIMEOUT = 20000;
|
||||
@ -30,6 +31,7 @@ const AUDIO_SESSION_NUM_KEY = 'AudioSessionNumber';
|
||||
const USER_AGENT_RECONNECTION_ATTEMPTS = 3;
|
||||
const USER_AGENT_RECONNECTION_DELAY_MS = 5000;
|
||||
const USER_AGENT_CONNECTION_TIMEOUT_MS = 5000;
|
||||
const ICE_GATHERING_TIMEOUT = MEDIA.iceGatheringTimeout || 5000;
|
||||
|
||||
const getAudioSessionNumber = () => {
|
||||
let currItem = parseInt(sessionStorage.getItem(AUDIO_SESSION_NUM_KEY), 10);
|
||||
@ -309,14 +311,18 @@ class SIPSession {
|
||||
});
|
||||
}
|
||||
|
||||
onBeforeUnload() {
|
||||
if (this.userAgent) {
|
||||
stopUserAgent() {
|
||||
if (this.userAgent && (typeof this.userAgent.stop === 'function')) {
|
||||
return this.userAgent.stop();
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
onBeforeUnload() {
|
||||
this.userRequestedHangup = true;
|
||||
return this.stopUserAgent();
|
||||
}
|
||||
|
||||
createUserAgent(iceServers) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (this.userRequestedHangup === true) reject();
|
||||
@ -368,11 +374,13 @@ class SIPSession {
|
||||
sessionDescriptionHandlerFactoryOptions: {
|
||||
peerConnectionConfiguration: {
|
||||
iceServers,
|
||||
sdpSemantics: 'plan-b',
|
||||
},
|
||||
},
|
||||
displayName: callerIdName,
|
||||
register: false,
|
||||
userAgentString: 'BigBlueButton',
|
||||
hackViaWs: SIPJS_HACK_VIA_WS,
|
||||
});
|
||||
|
||||
const handleUserAgentConnection = () => {
|
||||
@ -424,6 +432,9 @@ class SIPSession {
|
||||
error = 1002;
|
||||
bridgeError = 'Websocket failed to connect';
|
||||
}
|
||||
|
||||
this.stopUserAgent();
|
||||
|
||||
this.callback({
|
||||
status: this.baseCallStates.failed,
|
||||
error,
|
||||
@ -459,11 +470,13 @@ class SIPSession {
|
||||
|
||||
const code = getErrorCode(error);
|
||||
|
||||
|
||||
//Websocket's 1006 is currently mapped to BBB's 1002
|
||||
if (code === 1006) {
|
||||
this.stopUserAgent();
|
||||
|
||||
this.callback({
|
||||
status: this.baseCallStates.failed,
|
||||
error: 1006,
|
||||
error: 1002,
|
||||
bridgeError: 'Websocket failed to connect',
|
||||
});
|
||||
return reject({
|
||||
@ -481,6 +494,8 @@ class SIPSession {
|
||||
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
this.stopUserAgent();
|
||||
|
||||
logger.info({
|
||||
logCode: 'sip_js_session_ua_disconnected',
|
||||
extraInfo: {
|
||||
@ -519,19 +534,26 @@ class SIPSession {
|
||||
|
||||
this._reconnecting = true;
|
||||
|
||||
setTimeout(() => {
|
||||
this.userAgent.reconnect().then(() => {
|
||||
this._reconnecting = false;
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
logger.info({
|
||||
logCode: 'sip_js_session_ua_reconnection_attempt',
|
||||
extraInfo: {
|
||||
callerIdName: this.user.callerIdName,
|
||||
},
|
||||
}, `User agent reconnection attempt ${attempts}`);
|
||||
|
||||
this.userAgent.reconnect().then(() => {
|
||||
this._reconnecting = false;
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
setTimeout(() => {
|
||||
this._reconnecting = false;
|
||||
this.reconnect(++attempts).then(() => {
|
||||
resolve();
|
||||
}).catch((error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}, USER_AGENT_RECONNECTION_DELAY_MS);
|
||||
}, USER_AGENT_RECONNECTION_DELAY_MS);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -562,6 +584,7 @@ class SIPSession {
|
||||
: audioDeviceConstraint,
|
||||
video: false,
|
||||
},
|
||||
iceGatheringTimeout: ICE_GATHERING_TIMEOUT,
|
||||
},
|
||||
sessionDescriptionHandlerModifiersPostICEGathering:
|
||||
[stripMDnsCandidates],
|
||||
@ -720,7 +743,7 @@ class SIPSession {
|
||||
callerIdName: this.user.callerIdName,
|
||||
},
|
||||
}, 'ICE connection closed');
|
||||
}
|
||||
} else return;
|
||||
|
||||
this.callback({
|
||||
status: this.baseCallStates.failed,
|
||||
@ -743,15 +766,51 @@ class SIPSession {
|
||||
onconnectionstatechange: (event) => {
|
||||
const peer = event.target;
|
||||
|
||||
logger.info({
|
||||
logCode: 'sip_js_connection_state_change',
|
||||
extraInfo: {
|
||||
connectionStateChange: peer.connectionState,
|
||||
callerIdName: this.user.callerIdName,
|
||||
},
|
||||
}, 'ICE connection state change - Current connection state - '
|
||||
+ `${peer.connectionState}`);
|
||||
|
||||
switch (peer.connectionState) {
|
||||
case 'failed':
|
||||
// Chrome triggers 'failed' for connectionState event, only
|
||||
handleIceNegotiationFailed(peer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
oniceconnectionstatechange: (event) => {
|
||||
const peer = event.target;
|
||||
|
||||
switch (peer.iceConnectionState) {
|
||||
case 'completed':
|
||||
case 'connected':
|
||||
if (iceCompleted) {
|
||||
logger.info({
|
||||
logCode: 'sip_js_ice_connection_success_after_success',
|
||||
extraInfo: {
|
||||
currentState: peer.connectionState,
|
||||
callerIdName: this.user.callerIdName,
|
||||
},
|
||||
}, 'ICE connection success, but user is already connected'
|
||||
+ 'ignoring it...'
|
||||
+ `${peer.iceConnectionState}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info({
|
||||
logCode: 'sip_js_ice_connection_success',
|
||||
extraInfo: {
|
||||
currentState: peer.connectionState,
|
||||
callerIdName: this.user.callerIdName,
|
||||
},
|
||||
}, 'ICE connection success. Current state - '
|
||||
}, 'ICE connection success. Current ICE Connection state - '
|
||||
+ `${peer.iceConnectionState}`);
|
||||
|
||||
clearTimeout(callTimeout);
|
||||
@ -777,11 +836,11 @@ class SIPSession {
|
||||
};
|
||||
};
|
||||
|
||||
const handleSessionTerminated = (message, cause) => {
|
||||
const handleSessionTerminated = (message) => {
|
||||
clearTimeout(callTimeout);
|
||||
clearTimeout(iceNegotiationTimeout);
|
||||
|
||||
if (!message && !cause && !!this.userRequestedHangup) {
|
||||
if (!message && !!this.userRequestedHangup) {
|
||||
return this.callback({
|
||||
status: this.baseCallStates.ended,
|
||||
});
|
||||
@ -791,18 +850,22 @@ class SIPSession {
|
||||
// any possile errors
|
||||
if (!this._currentSessionState) return false;
|
||||
|
||||
|
||||
let mappedCause;
|
||||
let cause;
|
||||
if (!iceCompleted) {
|
||||
mappedCause = '1004';
|
||||
cause = 'ICE error';
|
||||
} else {
|
||||
cause = 'Audio Conference Error';
|
||||
mappedCause = '1005';
|
||||
}
|
||||
|
||||
logger.error({
|
||||
logCode: 'sip_js_call_terminated',
|
||||
extraInfo: { cause, callerIdName: this.user.callerIdName },
|
||||
}, `Audio call terminated. cause=${cause}`);
|
||||
|
||||
let mappedCause;
|
||||
if (!iceCompleted) {
|
||||
mappedCause = '1004';
|
||||
} else {
|
||||
mappedCause = '1005';
|
||||
}
|
||||
|
||||
return this.callback({
|
||||
status: this.baseCallStates.failed,
|
||||
error: mappedCause,
|
||||
|
@ -14,9 +14,10 @@ function breakouts(role) {
|
||||
return Breakouts.find({ meetingId: '' });
|
||||
}
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
Logger.debug(`Publishing Breakouts for ${meetingId} ${userId}`);
|
||||
|
||||
const User = Users.findOne({ userId, meetingId }, { fields: { role: 1 } });
|
||||
Logger.debug('Publishing Breakouts', { meetingId, userId });
|
||||
|
||||
if (!!User && User.role === ROLE_MODERATOR) {
|
||||
const presenterSelector = {
|
||||
$or: [
|
||||
|
@ -24,7 +24,7 @@ export default function appendText(text, locale) {
|
||||
}).then((response) => {
|
||||
const { status } = response;
|
||||
if (status === 200) {
|
||||
Logger.verbose(`Appended text for padId:${padId}`);
|
||||
Logger.verbose('Captions: appended text', { padId });
|
||||
}
|
||||
}).catch(error => Logger.error(`Could not append captions for padId=${padId}: ${error}`));
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ export default function addCaption(meetingId, padId, locale) {
|
||||
|
||||
const { insertedId } = numChanged;
|
||||
if (insertedId) {
|
||||
return Logger.verbose(`Added caption locale=${locale.locale} meeting=${meetingId}`);
|
||||
return Logger.verbose('Captions: added locale', { locale: locale.locale, meetingId });
|
||||
}
|
||||
|
||||
return Logger.verbose(`Upserted caption locale=${locale.locale} meeting=${meetingId}`);
|
||||
return Logger.verbose('Captions: upserted locale', { locale: locale.locale, meetingId });
|
||||
};
|
||||
|
||||
return Captions.upsert(selector, modifier, cb);
|
||||
|
@ -21,10 +21,10 @@ export default function updateOwnerId(meetingId, userId, padId) {
|
||||
|
||||
const cb = (err) => {
|
||||
if (err) {
|
||||
return Logger.error(`Updating captions pad: ${err}`);
|
||||
return Logger.error('Captions: error while updating pad', { err });
|
||||
}
|
||||
updateOwner(meetingId, userId, padId);
|
||||
return Logger.verbose(`Update captions pad=${padId} ownerId=${userId}`);
|
||||
return Logger.verbose('Captions: updated caption', { padId, ownerId: userId });
|
||||
};
|
||||
|
||||
return Captions.update(selector, modifier, { multi: true }, cb);
|
||||
|
@ -27,7 +27,7 @@ export default function updatePad(padId, data, revs) {
|
||||
return Logger.error(`Updating captions pad: ${err}`);
|
||||
}
|
||||
editCaptions(padId, data, revs);
|
||||
return Logger.verbose(`Update captions pad=${padId} revs=${revs}`);
|
||||
return Logger.verbose('Captions: updated pad', { padId, revs });
|
||||
};
|
||||
|
||||
return Captions.update(selector, modifier, { multi: true }, cb);
|
||||
|
@ -18,10 +18,10 @@ export default function updateReadOnlyPadId(padId, readOnlyPadId) {
|
||||
|
||||
const cb = (err) => {
|
||||
if (err) {
|
||||
return Logger.error(`Adding readOnlyPadId captions pad: ${err}`);
|
||||
return Logger.error('Captions: error when adding readOnlyPadId', { err });
|
||||
}
|
||||
|
||||
return Logger.verbose(`Added readOnlyPadId captions pad=${padId} readOnlyPadId=${readOnlyPadId}`);
|
||||
return Logger.verbose('Captions: added readOnlyPadId', { padId, readOnlyPadId });
|
||||
};
|
||||
|
||||
return Captions.update(selector, modifier, { multi: true }, cb);
|
||||
|
@ -12,7 +12,7 @@ function captions() {
|
||||
}
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
Logger.debug(`Publishing Captions for ${meetingId} requested by ${userId}`);
|
||||
Logger.debug('Publishing Captions', { meetingId, requestedBy: userId });
|
||||
|
||||
return Captions.find({ meetingId });
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ const proccess = _.throttle(() => {
|
||||
CursorStreamer(meetingId).emit('message', { meetingId, cursors });
|
||||
|
||||
if (streamerLog) {
|
||||
Logger.debug(`CursorUpdate process for meeting ${meetingId} has finished`);
|
||||
Logger.debug('CursorUpdate process has finished', { meetingId });
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error(`Error while trying to send cursor streamer data for meeting ${meetingId}. ${error}`);
|
||||
|
@ -36,7 +36,7 @@ export default function updateCursor(meetingId, whiteboardId, userId, x = -1, y
|
||||
}
|
||||
|
||||
if (numChanged) {
|
||||
Logger.debug(`Updated cursor meeting=${meetingId}`);
|
||||
Logger.debug('Updated cursor ', { meetingId });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,12 +11,12 @@ export function removeCursorStreamer(meetingId) {
|
||||
export function addCursorStreamer(meetingId) {
|
||||
const streamer = new Meteor.Streamer(`cursor-${meetingId}`, { retransmit: false });
|
||||
if (streamerLog) {
|
||||
Logger.debug(`Cursor streamer created for meeting ${meetingId}`);
|
||||
Logger.debug('Cursor streamer created', { meetingId });
|
||||
}
|
||||
|
||||
streamer.allowRead(function allowRead() {
|
||||
if (streamerLog) {
|
||||
Logger.debug(`Cursor streamer called allowRead for user ${this.userId} in meeting ${meetingId}`);
|
||||
Logger.debug('Cursor streamer called allowRead', { userId: this.userId, meetingId });
|
||||
}
|
||||
return this.userId && this.userId.includes(meetingId);
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ const allowRecentMessages = (eventName, message) => {
|
||||
state,
|
||||
} = message;
|
||||
|
||||
Logger.debug(`ExternalVideo Streamer auth allowed userId: ${userId}, meetingId: ${meetingId}, event: ${eventName}, time: ${time} rate: ${rate}, state: ${state}`);
|
||||
Logger.debug('ExternalVideo Streamer auth allowed', userId, meetingId, eventName, time, rate, state);
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -25,6 +25,6 @@ export default function initializeExternalVideo() {
|
||||
streamer.allowEmit(allowRecentMessages);
|
||||
Logger.info(`Created External Video streamer for ${streamName}`);
|
||||
} else {
|
||||
Logger.debug(`External Video streamer is already created for ${streamName}`);
|
||||
Logger.debug('`External Video streamer is already created', { streamName });
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ export default function startTyping(meetingId, userId, chatId) {
|
||||
Meteor.setTimeout(() => {
|
||||
stopTyping(meetingId, userId);
|
||||
}, TYPING_TIMEOUT);
|
||||
return Logger.debug(`Typing indicator update for userId={${userId}} chatId={${chatId}}`);
|
||||
return Logger.debug('Typing indicator update', { userId, chatId });
|
||||
};
|
||||
|
||||
return UsersTyping.upsert(selector, mod, cb);
|
||||
|
@ -20,7 +20,7 @@ export default function stopTyping(meetingId, userId, sendMsgInitiated = false)
|
||||
if (err) {
|
||||
return Logger.error(`Stop user=${userId} typing indicator error: ${err}`);
|
||||
}
|
||||
return Logger.debug(`Stopped typing indicator for user=${userId}`);
|
||||
return Logger.debug('Stopped typing indicator', { userId });
|
||||
};
|
||||
|
||||
UsersTyping.remove(selector, cb);
|
||||
|
@ -17,7 +17,7 @@ function groupChatMsg(chatsIds) {
|
||||
const CHAT_CONFIG = Meteor.settings.public.chat;
|
||||
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
|
||||
|
||||
Logger.debug(`Publishing group-chat-msg for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing group-chat-msg', { meetingId, userId });
|
||||
|
||||
return GroupChatMsg.find({
|
||||
$or: [
|
||||
@ -44,7 +44,7 @@ function usersTyping() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing users-typing for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing users-typing', { meetingId, userId });
|
||||
|
||||
return UsersTyping.find({ meetingId });
|
||||
}
|
||||
@ -54,4 +54,4 @@ function pubishUsersTyping(...args) {
|
||||
return boundUsersTyping(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('users-typing', pubishUsersTyping);
|
||||
Meteor.publish('users-typing', pubishUsersTyping);
|
||||
|
@ -17,7 +17,7 @@ function groupChat() {
|
||||
const CHAT_CONFIG = Meteor.settings.public.chat;
|
||||
const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
|
||||
|
||||
Logger.debug(`Publishing group-chat for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing group-chat', { meetingId, userId });
|
||||
|
||||
return GroupChat.find({
|
||||
$or: [
|
||||
|
@ -13,7 +13,7 @@ function localSettings() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing local settings for user=${userId}`);
|
||||
Logger.debug('Publishing local settings', { userId });
|
||||
|
||||
return LocalSettings.find({ meetingId, userId });
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ export default function transferUser(fromMeetingId, toMeetingId) {
|
||||
userId: requesterUserId,
|
||||
};
|
||||
|
||||
Logger.verbose(`userId ${requesterUserId} was transferred from
|
||||
meeting ${fromMeetingId}' to meeting '${toMeetingId}`);
|
||||
Logger.verbose('User was transferred from one meting to another', { requesterUserId, fromMeetingId, toMeetingId });
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ function meetings(role) {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing meeting =${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing meeting', { meetingId, userId });
|
||||
|
||||
const selector = {
|
||||
$or: [
|
||||
|
@ -14,7 +14,7 @@ export default function userInstabilityDetected(sender) {
|
||||
sender,
|
||||
};
|
||||
|
||||
Logger.debug(`Receiver ${receiver} reported a network instability in meeting ${meetingId}`);
|
||||
Logger.debug('Receiver reported a network instability', { receiver, meetingId });
|
||||
|
||||
return NetworkInformation.insert(payload);
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ export default function updateNote(noteId, revs) {
|
||||
|
||||
const cb = (err) => {
|
||||
if (err) {
|
||||
return Logger.error(`Updating note pad: ${err}`);
|
||||
return Logger.error('Notes: error when updating note pad', { err });
|
||||
}
|
||||
|
||||
return Logger.verbose(`Update note pad=${noteId} revs=${revs}`);
|
||||
return Logger.verbose('Notes: update note pad', { pad: noteId, revs });
|
||||
};
|
||||
|
||||
return Note.update(selector, modifier, { multi: true }, cb);
|
||||
|
@ -8,12 +8,22 @@ export default function publishVote(pollId, pollAnswerId) {
|
||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||
const EVENT_NAME = 'RespondToPollReqMsg';
|
||||
|
||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||
|
||||
check(pollAnswerId, Number);
|
||||
check(pollId, String);
|
||||
|
||||
const allowedToVote = Polls.findOne({ id: pollId, users: { $in: [requesterUserId] } }, {
|
||||
fields: {
|
||||
users: 1,
|
||||
},
|
||||
});
|
||||
|
||||
if (!allowedToVote) {
|
||||
Logger.info(`Poll User={${requesterUserId}} has already voted in PollId={${pollId}}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const selector = {
|
||||
users: requesterUserId,
|
||||
meetingId,
|
||||
@ -43,11 +53,11 @@ export default function publishVote(pollId, pollAnswerId) {
|
||||
return Logger.error(`Removing responded user from Polls collection: ${err}`);
|
||||
}
|
||||
|
||||
return Logger.info(`Removed responded user=${requesterUserId} from poll (meetingId: ${meetingId}, `
|
||||
Logger.info(`Removed responded user=${requesterUserId} from poll (meetingId: ${meetingId}, `
|
||||
+ `pollId: ${pollId}!)`);
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
};
|
||||
|
||||
Polls.update(selector, modifier, cb);
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ function currentPoll() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing Polls for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Polls', { meetingId, userId });
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
@ -40,7 +40,7 @@ function polls() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing Polls for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing polls', { meetingId, userId });
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
|
@ -12,7 +12,7 @@ function presentationPods() {
|
||||
}
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
Logger.debug(`Publishing PresentationPods for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing presentation-pods', { meetingId, userId });
|
||||
|
||||
return PresentationPods.find({ meetingId });
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ function presentationUploadToken(podId, filename) {
|
||||
filename,
|
||||
};
|
||||
|
||||
Logger.debug(`Publishing PresentationUploadToken for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing PresentationUploadToken', { meetingId, userId });
|
||||
|
||||
return PresentationUploadToken.find(selector);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ export default function handlePresentationConversionUpdate({ body }, meetingId)
|
||||
return Logger.info(`Updated presentation conversion status=${status} id=${presentationId} meeting=${meetingId}`);
|
||||
}
|
||||
|
||||
return Logger.debug(`Upserted presentation conversion status=${status} id=${presentationId} meeting=${meetingId}`);
|
||||
return Logger.debug('Upserted presentation conversion', { status, presentationId, meetingId });
|
||||
};
|
||||
|
||||
return Presentations.upsert(selector, modifier, cb);
|
||||
|
@ -13,7 +13,7 @@ function presentations() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing Presentations for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Presentations', { meetingId, userId });
|
||||
|
||||
return Presentations.find({ meetingId });
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ function screenshare() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing Screenshare for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Screenshare', { meetingId, userId });
|
||||
|
||||
return Screenshare.find({ meetingId });
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ export default function resizeSlide(meetingId, slide) {
|
||||
}
|
||||
|
||||
if (numChanged) {
|
||||
return Logger.debug(`Resized slide positions id=${pageId}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
return Logger.info(`No slide positions found with id=${pageId}`);
|
||||
|
@ -13,7 +13,7 @@ function slides() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing Slides for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Slides', { meetingId, userId });
|
||||
|
||||
return Slides.find({ meetingId });
|
||||
}
|
||||
@ -35,7 +35,7 @@ function slidePositions() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing SlidePositions for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing SlidePositions', { meetingId, userId });
|
||||
|
||||
return SlidePositions.find({ meetingId });
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ function userInfos() {
|
||||
|
||||
const { meetingId, userId: requesterUserId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing UserInfos for ${meetingId} ${requesterUserId}`);
|
||||
Logger.debug('Publishing UserInfos requested', { meetingId, requesterUserId });
|
||||
|
||||
return UserInfos.find({ meetingId, requesterUserId });
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export default function addUserSetting(meetingId, userId, setting, value) {
|
||||
return Logger.error(`Adding user setting to collection: ${err}`);
|
||||
}
|
||||
|
||||
return Logger.verbose(`Upserted user setting for meetingId=${meetingId} userId=${userId} setting=${setting}`);
|
||||
return Logger.verbose('Upserted user setting', { meetingId, userId, setting });
|
||||
};
|
||||
|
||||
return UserSettings.upsert(selector, modifier, cb);
|
||||
|
@ -37,12 +37,12 @@ function userSettings() {
|
||||
UserSettings.upsert(selector, doc);
|
||||
});
|
||||
|
||||
Logger.debug(`Publishing UserSettings for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing UserSettings', { meetingId, userId });
|
||||
|
||||
return UserSettings.find({ meetingId, userId });
|
||||
}
|
||||
|
||||
Logger.debug(`Publishing UserSettings for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing UserSettings', { meetingId, userId });
|
||||
|
||||
return UserSettings.find({ meetingId, userId });
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ export default function assignPresenter(userId) { // TODO-- send username from c
|
||||
requesterId: requesterUserId,
|
||||
};
|
||||
|
||||
Logger.verbose(`User '${userId}' setted as presenter by '${
|
||||
requesterUserId}' from meeting '${meetingId}'`);
|
||||
Logger.verbose('User set as presenter', { userId, meetingId, setBy: requesterUserId });
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -20,7 +20,9 @@ export default function changeRole(userId, role) {
|
||||
changedBy: requesterUserId,
|
||||
};
|
||||
|
||||
Logger.verbose(`User '${userId}' set as '${role} role by '${requesterUserId}' from meeting '${meetingId}'`);
|
||||
Logger.verbose('Changed user role', {
|
||||
userId, role, changedBy: requesterUserId, meetingId,
|
||||
});
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -18,8 +18,9 @@ export default function setEmojiStatus(userId, status) {
|
||||
userId,
|
||||
};
|
||||
|
||||
Logger.verbose(`User '${userId}' emoji status updated to '${status}' by '${
|
||||
requesterUserId}' from meeting '${meetingId}'`);
|
||||
Logger.verbose('User emoji status updated', {
|
||||
userId, status, requesterUserId, meetingId,
|
||||
});
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ export default function setUserEffectiveConnectionType(effectiveConnectionType)
|
||||
|
||||
setEffectiveConnectionType(meetingId, requesterUserId, effectiveConnectionType);
|
||||
|
||||
Logger.verbose(`User ${requesterUserId} effective connection updated to ${effectiveConnectionType}`);
|
||||
Logger.verbose('Updated user effective connection', { requesterUserId, effectiveConnectionType });
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||
}
|
||||
|
@ -21,8 +21,9 @@ export default function toggleUserLock(userId, lock) {
|
||||
lock,
|
||||
};
|
||||
|
||||
Logger.verbose(`User ${lockedBy} updated lock status from ${userId} to ${lock}
|
||||
in meeting ${meetingId}`);
|
||||
Logger.verbose('Updated lock status for user', {
|
||||
meetingId, userId, lock, lockedBy,
|
||||
});
|
||||
|
||||
|
||||
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, lockedBy, payload);
|
||||
|
@ -72,7 +72,7 @@ function users(role) {
|
||||
},
|
||||
};
|
||||
|
||||
Logger.debug(`Publishing Users for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Users', { meetingId, userId });
|
||||
|
||||
return Users.find(selector, options);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ function videoStreams() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing VideoStreams for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing VideoStreams', { meetingId, userId });
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
|
@ -41,7 +41,9 @@ export default function handleVoiceCallStateEvent({ body }, meetingId) {
|
||||
return Logger.error(`Update voice call state=${userId}: ${err}`);
|
||||
}
|
||||
|
||||
return Logger.debug(`Update voice call state=${userId} meeting=${meetingId} clientSession=${clientSession} callState=${callState}`);
|
||||
return Logger.debug('Update voice call', {
|
||||
state: userId, meetingId, clientSession, callState,
|
||||
});
|
||||
};
|
||||
|
||||
return VoiceCallState.upsert(selector, modifier, cb);
|
||||
|
@ -13,7 +13,7 @@ function voiceCallStates() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing VoiceCallStates for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing Voice Call States', { meetingId, userId });
|
||||
|
||||
return VoiceCallStates.find({ meetingId, userId });
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ export default function updateVoiceUser(meetingId, voiceUser) {
|
||||
return Logger.error(`Update voiceUser=${intId}: ${err}`);
|
||||
}
|
||||
|
||||
return Logger.debug(`Update voiceUser=${intId} meeting=${meetingId}`);
|
||||
return Logger.debug('Update voiceUser', { voiceUser: intId, meetingId });
|
||||
};
|
||||
|
||||
if (!voiceUser.talking) {
|
||||
|
@ -26,7 +26,7 @@ function voiceUser() {
|
||||
}
|
||||
});
|
||||
|
||||
Logger.debug(`Publishing Voice User for ${meetingId} ${requesterUserId}`);
|
||||
Logger.debug('Publishing Voice User', { meetingId, requesterUserId });
|
||||
|
||||
this._session.socket.on('close', _.debounce(onCloseConnection, 100));
|
||||
return VoiceUsers.find({ meetingId });
|
||||
|
@ -13,7 +13,7 @@ function whiteboardMultiUser() {
|
||||
|
||||
const { meetingId, userId } = tokenValidation;
|
||||
|
||||
Logger.debug(`Publishing WhiteboardMultiUser for ${meetingId} ${userId}`);
|
||||
Logger.debug('Publishing WhiteboardMultiUser', { meetingId, userId });
|
||||
|
||||
return WhiteboardMultiUser.find({ meetingId });
|
||||
}
|
||||
|
@ -27,17 +27,12 @@ const makeEnvelope = (channel, eventName, header, body, routing) => {
|
||||
return JSON.stringify(envelope);
|
||||
};
|
||||
|
||||
const makeDebugger = enabled => (message) => {
|
||||
if (!enabled) return;
|
||||
Logger.debug(`REDIS: ${message}`);
|
||||
};
|
||||
|
||||
class MeetingMessageQueue {
|
||||
constructor(eventEmitter, asyncMessages = [], debug = () => { }) {
|
||||
constructor(eventEmitter, asyncMessages = [], redisDebugEnabled = false) {
|
||||
this.asyncMessages = asyncMessages;
|
||||
this.emitter = eventEmitter;
|
||||
this.queue = new PowerQueue();
|
||||
this.debug = debug;
|
||||
this.redisDebugEnabled = redisDebugEnabled;
|
||||
|
||||
this.handleTask = this.handleTask.bind(this);
|
||||
this.queue.taskHandler = this.handleTask;
|
||||
@ -60,11 +55,13 @@ class MeetingMessageQueue {
|
||||
|
||||
const callNext = () => {
|
||||
if (called) return;
|
||||
this.debug(`${eventName} completed ${isAsync ? 'async' : 'sync'}`);
|
||||
if (this.redisDebugEnabled) {
|
||||
Logger.debug(`Redis: ${eventName} completed ${isAsync ? 'async' : 'sync'}`);
|
||||
}
|
||||
called = true;
|
||||
const queueLength = this.queue.length();
|
||||
if (queueLength > 100) {
|
||||
Logger.error(`prev queue size=${queueLength} `);
|
||||
if (queueLength > 0) {
|
||||
Logger.warn(`Redis: MeetingMessageQueue for meetingId=${meetingId} has queue size=${queueLength} `);
|
||||
}
|
||||
next();
|
||||
};
|
||||
@ -75,7 +72,9 @@ class MeetingMessageQueue {
|
||||
};
|
||||
|
||||
try {
|
||||
this.debug(`${JSON.stringify(data.parsedMessage.core)} emitted`);
|
||||
if (this.redisDebugEnabled) {
|
||||
Logger.debug(`Redis: ${JSON.stringify(data.parsedMessage.core)} emitted`);
|
||||
}
|
||||
|
||||
if (isAsync) {
|
||||
callNext();
|
||||
@ -129,7 +128,6 @@ class RedisPubSub {
|
||||
|
||||
this.handleSubscribe = this.handleSubscribe.bind(this);
|
||||
this.handleMessage = this.handleMessage.bind(this);
|
||||
this.debug = makeDebugger(this.config.debug);
|
||||
}
|
||||
|
||||
init() {
|
||||
@ -142,12 +140,14 @@ class RedisPubSub {
|
||||
this.sub.psubscribe(channel);
|
||||
});
|
||||
|
||||
this.debug(`Subscribed to '${channelsToSubscribe}'`);
|
||||
if (this.redisDebugEnabled) {
|
||||
Logger.debug(`Redis: Subscribed to '${channelsToSubscribe}'`);
|
||||
}
|
||||
}
|
||||
|
||||
updateConfig(config) {
|
||||
this.config = Object.assign({}, this.config, config);
|
||||
this.debug = makeDebugger(this.config.debug);
|
||||
this.redisDebugEnabled = this.config.debug;
|
||||
}
|
||||
|
||||
|
||||
@ -178,21 +178,23 @@ class RedisPubSub {
|
||||
if (eventName === 'CheckAlivePongSysMsg') {
|
||||
return;
|
||||
}
|
||||
this.debug(`${eventName} skipped`);
|
||||
if (this.redisDebugEnabled) {
|
||||
Logger.debug(`Redis: ${eventName} skipped`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const queueId = meetingId || NO_MEETING_ID;
|
||||
|
||||
if (eventName === 'MeetingCreatedEvtMsg'){
|
||||
if (eventName === 'MeetingCreatedEvtMsg') {
|
||||
const newIntId = parsedMessage.core.body.props.meetingProp.intId;
|
||||
const metadata = parsedMessage.core.body.props.metadataProp.metadata;
|
||||
const instanceId = parseInt(metadata['bbb-meetinginstance']) || 1;
|
||||
|
||||
Logger.warn("MeetingCreatedEvtMsg received with meetingInstance: " + instanceId + " -- this is instance: " + this.instanceId);
|
||||
Logger.warn(`MeetingCreatedEvtMsg received with meetingInstance: ${instanceId} -- this is instance: ${this.instanceId}`);
|
||||
|
||||
if (instanceId === this.instanceId){
|
||||
this.mettingsQueues[newIntId] = new MeetingMessageQueue(this.emitter, async, this.debug);
|
||||
if (instanceId === this.instanceId) {
|
||||
this.mettingsQueues[newIntId] = new MeetingMessageQueue(this.emitter, async, this.redisDebugEnabled);
|
||||
} else {
|
||||
// Logger.error('THIS NODEJS ' + this.instanceId + ' IS **NOT** PROCESSING EVENTS FOR THIS MEETING ' + instanceId)
|
||||
}
|
||||
@ -206,11 +208,9 @@ class RedisPubSub {
|
||||
parsedMessage,
|
||||
});
|
||||
}
|
||||
//else {
|
||||
//Logger.info("Skipping redis message for " + queueId);
|
||||
//}
|
||||
|
||||
|
||||
// else {
|
||||
// Logger.info("Skipping redis message for " + queueId);
|
||||
// }
|
||||
}
|
||||
|
||||
destroyMeetingQueue(id) {
|
||||
@ -279,4 +279,3 @@ Meteor.startup(() => {
|
||||
});
|
||||
|
||||
export default RedisPubSubSingleton;
|
||||
|
||||
|
@ -183,6 +183,7 @@ class AudioModal extends Component {
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { autoplayBlocked, closeModal } = this.props;
|
||||
|
||||
if (autoplayBlocked !== prevProps.autoplayBlocked) {
|
||||
autoplayBlocked ? this.setState({ content: 'autoplayBlocked' }) : closeModal();
|
||||
}
|
||||
@ -246,13 +247,14 @@ class AudioModal extends Component {
|
||||
|
||||
const {
|
||||
joinEchoTest,
|
||||
isConnecting,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
disableActions,
|
||||
} = this.state;
|
||||
|
||||
if (disableActions) return;
|
||||
if (disableActions && isConnecting) return;
|
||||
|
||||
this.setState({
|
||||
hasError: false,
|
||||
|
@ -120,7 +120,7 @@ export class ArcPlayer extends Component {
|
||||
getHostUrl() {
|
||||
const { url } = this.props;
|
||||
const m = url.match(MATCH_URL);
|
||||
return m && 'https://' + m[1] + '.' + m[2];
|
||||
return m && 'https://' + m[1] + m[2];
|
||||
}
|
||||
|
||||
getEmbedUrl() {
|
||||
|
@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import ModalSimple from '/imports/ui/components/modal/simple/component';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import FallbackView from '../fallback-view/component';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
ariaTitle: {
|
||||
id: 'app.error.fallback.modal.ariaTitle',
|
||||
description: 'title announced when fallback modal is showed',
|
||||
},
|
||||
});
|
||||
|
||||
const FallbackModal = ({ error, intl, mountModal }) => (
|
||||
<ModalSimple
|
||||
hideBorder
|
||||
onRequestClose={() => mountModal(null)}
|
||||
contentLabel={intl.formatMessage(intlMessages.ariaTitle)}
|
||||
>
|
||||
<FallbackView {...{ error }} />
|
||||
</ModalSimple>
|
||||
);
|
||||
|
||||
export default withModalMounter(injectIntl(FallbackModal));
|
@ -1,24 +1,40 @@
|
||||
import React from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import { styles } from './styles';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
title: {
|
||||
id: 'app.error.fallback.presentation.title',
|
||||
id: 'app.error.fallback.view.title',
|
||||
description: 'title for presentation when fallback is showed',
|
||||
},
|
||||
description: {
|
||||
id: 'app.error.fallback.presentation.description',
|
||||
id: 'app.error.fallback.view.description',
|
||||
description: 'description for presentation when fallback is showed',
|
||||
},
|
||||
reloadButton: {
|
||||
id: 'app.error.fallback.presentation.reloadButton',
|
||||
id: 'app.error.fallback.view.reloadButton',
|
||||
description: 'Button label when fallback is showed',
|
||||
},
|
||||
});
|
||||
|
||||
const FallbackPresentation = ({ error, intl }) => (
|
||||
const propTypes = {
|
||||
intl: PropTypes.shape({
|
||||
formatMessage: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
error: PropTypes.shape({
|
||||
message: PropTypes.string.isRequired,
|
||||
}),
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
error: {
|
||||
message: '',
|
||||
},
|
||||
};
|
||||
|
||||
const FallbackView = ({ error, intl }) => (
|
||||
<div className={styles.background}>
|
||||
<h1 className={styles.codeError}>
|
||||
{intl.formatMessage(intlMessages.title)}
|
||||
@ -42,4 +58,7 @@ const FallbackPresentation = ({ error, intl }) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
export default injectIntl(FallbackPresentation);
|
||||
FallbackView.propTypes = propTypes;
|
||||
FallbackView.defaultProps = defaultProps;
|
||||
|
||||
export default injectIntl(FallbackView);
|
@ -26,8 +26,9 @@ const intlMessages = defineMessages({
|
||||
|
||||
class TalkingIndicator extends PureComponent {
|
||||
handleMuteUser(id) {
|
||||
const { muteUser, amIModerator } = this.props;
|
||||
if (!amIModerator) return;
|
||||
const { muteUser, amIModerator, isBreakoutRoom } = this.props;
|
||||
// only allow moderator muting anyone in non-breakout
|
||||
if (!amIModerator || isBreakoutRoom) return;
|
||||
muteUser(id);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import Auth from '/imports/ui/services/auth';
|
||||
import { debounce } from 'lodash';
|
||||
import TalkingIndicator from './component';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import { meetingIsBreakout } from '/imports/ui/components/app/service';
|
||||
import Service from './service';
|
||||
|
||||
const APP_CONFIG = Meteor.settings.public.app;
|
||||
@ -60,5 +61,6 @@ export default withTracker(() => {
|
||||
talkers,
|
||||
muteUser: id => debounce(muteUser(id), 500, { leading: true, trailing: false }),
|
||||
openPanel: Session.get('openPanel'),
|
||||
isBreakoutRoom: meetingIsBreakout(),
|
||||
};
|
||||
})(TalkingIndicatorContainer);
|
||||
|
@ -1,8 +1,13 @@
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import Polls from '/imports/api/polls';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
const MAX_CHAR_LENGTH = 5;
|
||||
|
||||
const handleVote = (pollId, answerId) => {
|
||||
makeCall('publishVote', pollId, answerId.id);
|
||||
};
|
||||
|
||||
const mapPolls = () => {
|
||||
const poll = Polls.findOne({});
|
||||
if (!poll) {
|
||||
@ -30,9 +35,7 @@ const mapPolls = () => {
|
||||
},
|
||||
pollExists: true,
|
||||
amIRequester,
|
||||
handleVote(pollId, answerId) {
|
||||
makeCall('publishVote', pollId, answerId.id);
|
||||
},
|
||||
handleVote: debounce(handleVote, 500, { leading: true, trailing: false }),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import ErrorBoundary from '/imports/ui/components/error-boundary/component';
|
||||
import FallbackPresentation from '/imports/ui/components/fallback-errors/fallback-presentation/component';
|
||||
import FallbackView from '/imports/ui/components/fallback-errors/fallback-view/component';
|
||||
import PresentationPodService from './service';
|
||||
import PresentationPods from './component';
|
||||
|
||||
@ -12,7 +12,7 @@ import PresentationPods from './component';
|
||||
const PresentationPodsContainer = ({ presentationPodIds, ...props }) => {
|
||||
if (presentationPodIds && presentationPodIds.length > 0) {
|
||||
return (
|
||||
<ErrorBoundary Fallback={FallbackPresentation}>
|
||||
<ErrorBoundary Fallback={FallbackView}>
|
||||
<PresentationPods presentationPodIds={presentationPodIds} {...props} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
@ -22,7 +22,7 @@ const PresentationPodsContainer = ({ presentationPodIds, ...props }) => {
|
||||
};
|
||||
|
||||
export default withTracker(() => ({
|
||||
presentationPodIds: PresentationPodService.getPresentationPodIds()
|
||||
presentationPodIds: PresentationPodService.getPresentationPodIds(),
|
||||
}))(PresentationPodsContainer);
|
||||
|
||||
PresentationPodsContainer.propTypes = {
|
||||
|
@ -715,7 +715,7 @@ class PresentationUploader extends Component {
|
||||
};
|
||||
|
||||
const hideRemove = this.isDefault(item);
|
||||
const formattedDownloadableLabel = item.isDownloadable
|
||||
const formattedDownloadableLabel = !item.isDownloadable
|
||||
? intl.formatMessage(intlMessages.isDownloadable)
|
||||
: intl.formatMessage(intlMessages.isNotDownloadable);
|
||||
|
||||
|
@ -1,13 +1,19 @@
|
||||
import React from 'react';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import ErrorBoundary from '/imports/ui/components/error-boundary/component';
|
||||
import FallbackModal from '/imports/ui/components/fallback-errors/fallback-modal/component';
|
||||
import Service from './service';
|
||||
import PresentationService from '../service';
|
||||
import Uploader from './component';
|
||||
import PresentationUploader from './component';
|
||||
|
||||
const PRESENTATION_CONFIG = Meteor.settings.public.presentation;
|
||||
|
||||
const UploaderContainer = props => <Uploader {...props} />;
|
||||
const PresentationUploaderContainer = props => (
|
||||
<ErrorBoundary Fallback={() => <FallbackModal />}>
|
||||
<PresentationUploader {...props} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
export default withTracker(() => {
|
||||
const currentPresentations = Service.getPresentations();
|
||||
@ -36,4 +42,4 @@ export default withTracker(() => {
|
||||
selectedToBeNextCurrent: Session.get('selectedToBeNextCurrent') || null,
|
||||
isPresenter: PresentationService.isPresenter('DEFAULT_PRESENTATION_POD'),
|
||||
};
|
||||
})(UploaderContainer);
|
||||
})(PresentationUploaderContainer);
|
||||
|
@ -6,6 +6,7 @@ import Auth from '/imports/ui/services/auth';
|
||||
import { Session } from 'meteor/session';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
|
||||
const ICE_GATHERING_CHECK_ENABLED = Meteor.settings.public.media.recvonlyIceGatheringCheck;
|
||||
const getSessionToken = () => Auth.sessionToken;
|
||||
|
||||
export async function getIceServersList() {
|
||||
@ -43,13 +44,13 @@ export function canGenerateIceCandidates() {
|
||||
pc.onicegatheringstatechange = function (e) {
|
||||
if (e.currentTarget.iceGatheringState === 'complete' && countIceCandidates === 0) {
|
||||
logger.warn({ logCode: 'no_valid_candidate' }, 'No useful ICE candidate found. Will request gUM permission.');
|
||||
reject();
|
||||
reject(new Error('No valid candidate'));
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
pc.close();
|
||||
if (!countIceCandidates) reject();
|
||||
if (!countIceCandidates) reject(new Error('Gathering check timeout'));
|
||||
}, 5000);
|
||||
|
||||
const p = pc.createOffer({ offerToReceiveVideo: true });
|
||||
@ -66,11 +67,20 @@ export function canGenerateIceCandidates() {
|
||||
* generate at least srflx candidates.
|
||||
* This is a workaround due to a behaviour some browsers display (mainly Safari)
|
||||
* where they won't generate srflx or relay candidates if no gUM permission is
|
||||
* given. Since our media servers aren't able to make it work by prflx
|
||||
* candidates, we need to do this.
|
||||
* given.
|
||||
*
|
||||
*
|
||||
* UPDATE:
|
||||
* This used to be valid when Kurento wasn't treating prflx candidates properly.
|
||||
* It is now, so this workaround is being revisited. I've put it under a flag
|
||||
* so that we can field trial it disabled and gauge the impact of removing it.
|
||||
* Hopelly we can get rid of it.
|
||||
*
|
||||
* prlanzarin 11-11-20
|
||||
*/
|
||||
export function tryGenerateIceCandidates() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!ICE_GATHERING_CHECK_ENABLED) return resolve();
|
||||
canGenerateIceCandidates().then(() => {
|
||||
resolve();
|
||||
}).catch(() => {
|
||||
|
85
bigbluebutton-html5/package-lock.json
generated
85
bigbluebutton-html5/package-lock.json
generated
@ -3836,6 +3836,12 @@
|
||||
"minimatch": "~3.0.2"
|
||||
}
|
||||
},
|
||||
"glur": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glur/-/glur-1.1.2.tgz",
|
||||
"integrity": "sha1-8g6jbbEDv8KSNDkh8fkeg8NGdok=",
|
||||
"dev": true
|
||||
},
|
||||
"good-listener": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
|
||||
@ -5454,6 +5460,56 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-image-snapshot": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-image-snapshot/-/jest-image-snapshot-4.2.0.tgz",
|
||||
"integrity": "sha512-6aAqv2wtfOgxiJeBayBCqHo1zX+A12SUNNzo7rIxiXh6W6xYVu8QyHWkada8HeRi+QUTHddp0O0Xa6kmQr+xbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^1.1.3",
|
||||
"get-stdin": "^5.0.1",
|
||||
"glur": "^1.1.2",
|
||||
"lodash": "^4.17.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"pixelmatch": "^5.1.0",
|
||||
"pngjs": "^3.4.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"ssim.js": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
"escape-string-regexp": "^1.0.2",
|
||||
"has-ansi": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"supports-color": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"get-stdin": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
|
||||
"integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-jasmine2": {
|
||||
"version": "25.5.4",
|
||||
"resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.5.4.tgz",
|
||||
@ -8437,6 +8493,23 @@
|
||||
"node-modules-regexp": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"pixelmatch": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.2.1.tgz",
|
||||
"integrity": "sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pngjs": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"pngjs": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-4.0.1.tgz",
|
||||
"integrity": "sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"pkg-dir": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
|
||||
@ -8475,6 +8548,12 @@
|
||||
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
|
||||
"dev": true
|
||||
},
|
||||
"pngjs": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
|
||||
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
|
||||
"dev": true
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
@ -9995,6 +10074,12 @@
|
||||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"ssim.js": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ssim.js/-/ssim.js-3.5.0.tgz",
|
||||
"integrity": "sha512-Aj6Jl2z6oDmgYFFbQqK7fght19bXdOxY7Tj03nF+03M9gCBAjeIiO8/PlEGMfKDwYpw4q6iBqVq2YuREorGg/g==",
|
||||
"dev": true
|
||||
},
|
||||
"stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
|
@ -303,6 +303,7 @@ public:
|
||||
stunTurnServersFetchAddress: "/bigbluebutton/api/stuns"
|
||||
cacheStunTurnServers: true
|
||||
fallbackStunServer: ''
|
||||
recvonlyIceGatheringCheck: true
|
||||
mediaTag: "#remote-media"
|
||||
callTransferTimeout: 5000
|
||||
callHangupTimeout: 2000
|
||||
@ -328,6 +329,12 @@ public:
|
||||
- danger
|
||||
- critical
|
||||
help: STATS_HELP_URL
|
||||
#Timeout (ms) for gathering ICE candidates. When this timeout expires
|
||||
#the SDP is sent to the server with the candidates the browser gathered
|
||||
#so far. Increasing this value might help avoiding 1004 error when
|
||||
#user activates microphone.
|
||||
iceGatheringTimeout: 5000
|
||||
sipjsHackViaWs: false
|
||||
presentation:
|
||||
allowDownloadable: true
|
||||
defaultPresentationFile: default.pdf
|
||||
|
@ -3831,6 +3831,7 @@ class OutgoingRequestMessage {
|
||||
fromTag: "",
|
||||
forceRport: false,
|
||||
hackViaTcp: false,
|
||||
hackViaWs: false,
|
||||
optionTags: ["outbound"],
|
||||
routeSet: [],
|
||||
userAgentString: "sip.js",
|
||||
@ -3937,6 +3938,8 @@ class OutgoingRequestMessage {
|
||||
// FIXME: Hack
|
||||
if (this.options.hackViaTcp) {
|
||||
transport = "TCP";
|
||||
} else if (this.options.hackViaWs) {
|
||||
transport = "WS";
|
||||
}
|
||||
let via = "SIP/2.0/" + transport;
|
||||
via += " " + this.options.viaHost + ";branch=" + branch;
|
||||
@ -9812,6 +9815,7 @@ class UserAgentCore {
|
||||
const fromDisplayName = this.configuration.displayName;
|
||||
const forceRport = this.configuration.viaForceRport;
|
||||
const hackViaTcp = this.configuration.hackViaTcp;
|
||||
const hackViaWs = this.configuration.hackViaWs;
|
||||
const optionTags = this.configuration.supportedOptionTags.slice();
|
||||
if (method === _messages__WEBPACK_IMPORTED_MODULE_0__["C"].REGISTER) {
|
||||
optionTags.push("path", "gruu");
|
||||
@ -9827,6 +9831,7 @@ class UserAgentCore {
|
||||
forceRport,
|
||||
fromDisplayName,
|
||||
hackViaTcp,
|
||||
hackViaWs,
|
||||
optionTags,
|
||||
routeSet,
|
||||
userAgentString,
|
||||
@ -17303,6 +17308,7 @@ class UserAgent {
|
||||
hackAllowUnregisteredOptionTags: false,
|
||||
hackIpInContact: false,
|
||||
hackViaTcp: false,
|
||||
hackViaWs: false,
|
||||
hackWssInTransport: false,
|
||||
logBuiltinEnabled: true,
|
||||
logConfiguration: true,
|
||||
@ -17657,6 +17663,7 @@ class UserAgent {
|
||||
displayName: this.options.displayName,
|
||||
loggerFactory: this.loggerFactory,
|
||||
hackViaTcp: this.options.hackViaTcp,
|
||||
hackViaWs: this.options.hackViaWs,
|
||||
routeSet: this.options.preloadedRouteSet,
|
||||
supportedOptionTags,
|
||||
supportedOptionTagsResponse,
|
||||
|
@ -93,6 +93,11 @@ class ApiController {
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
log.debug request.getParameterMap().toMapString()
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -197,6 +202,11 @@ class ApiController {
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check", REDIRECT_RESPONSE)
|
||||
@ -266,7 +276,6 @@ class ApiController {
|
||||
|
||||
// Do we have a name for the user joining? If none, complain.
|
||||
if (!StringUtils.isEmpty(params.fullName)) {
|
||||
params.fullName = StringUtils.strip(params.fullName);
|
||||
if (StringUtils.isEmpty(params.fullName)) {
|
||||
errors.missingParamError("fullName");
|
||||
}
|
||||
@ -583,6 +592,11 @@ class ApiController {
|
||||
String API_CALL = 'isMeetingRunning'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -659,9 +673,13 @@ class ApiController {
|
||||
************************************/
|
||||
def end = {
|
||||
String API_CALL = "end"
|
||||
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -784,6 +802,11 @@ class ApiController {
|
||||
String API_CALL = "getMeetingInfo"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -867,6 +890,11 @@ class ApiController {
|
||||
String API_CALL = "getMeetings"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -925,6 +953,11 @@ class ApiController {
|
||||
String API_CALL = "getSessions"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -1000,6 +1033,11 @@ class ApiController {
|
||||
String API_CALL = "setPollXML"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
@ -1086,6 +1124,11 @@ class ApiController {
|
||||
String API_CALL = "setConfigXML"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
return
|
||||
@ -1165,6 +1208,11 @@ class ApiController {
|
||||
String API_CALL = "getDefaultConfigXML"
|
||||
ApiErrors errors = new ApiErrors();
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -1204,6 +1252,11 @@ class ApiController {
|
||||
String API_CALL = 'configXML'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()
|
||||
boolean reject = false
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
@ -1251,6 +1304,12 @@ class ApiController {
|
||||
def guestWaitHandler = {
|
||||
String API_CALL = 'guestWait'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
boolean reject = false;
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
@ -1395,13 +1454,21 @@ class ApiController {
|
||||
* ENTER API
|
||||
***********************************************/
|
||||
def enter = {
|
||||
String API_CALL = 'enter'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
boolean reject = false;
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
UserSession us = getUserSession(sessionToken);
|
||||
Meeting meeting = null;
|
||||
|
||||
String respMessage = "Session " + sessionToken + " not found."
|
||||
String respMessage = "Session not found."
|
||||
|
||||
if (!hasValidSession(sessionToken)) {
|
||||
reject = true;
|
||||
@ -1409,7 +1476,7 @@ class ApiController {
|
||||
meeting = meetingService.getMeeting(us.meetingID);
|
||||
if (meeting == null || meeting.isForciblyEnded()) {
|
||||
reject = true
|
||||
respMessage = "Meeting not found or ended for session " + sessionToken + "."
|
||||
respMessage = "Meeting not found or ended for session."
|
||||
} else {
|
||||
if (hasReachedMaxParticipants(meeting, us)) {
|
||||
reject = true;
|
||||
@ -1419,7 +1486,7 @@ class ApiController {
|
||||
}
|
||||
}
|
||||
if (us.guestStatus.equals(GuestPolicy.DENY)) {
|
||||
respMessage = "User denied for user with session " + sessionToken + "."
|
||||
respMessage = "User denied for user with session."
|
||||
reject = true
|
||||
}
|
||||
}
|
||||
@ -1439,6 +1506,7 @@ class ApiController {
|
||||
builder.response {
|
||||
returncode RESP_CODE_FAILED
|
||||
message respMessage
|
||||
sessionToken
|
||||
logoutURL logoutUrl
|
||||
}
|
||||
render(contentType: "application/json", text: builder.toPrettyString())
|
||||
@ -1537,6 +1605,14 @@ class ApiController {
|
||||
* STUN/TURN API
|
||||
***********************************************/
|
||||
def stuns = {
|
||||
String API_CALL = 'stuns'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
boolean reject = false;
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
@ -1608,6 +1684,13 @@ class ApiController {
|
||||
* SIGNOUT API
|
||||
*************************************************/
|
||||
def signOut = {
|
||||
String API_CALL = 'signOut'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
String sessionToken = sanitizeSessionToken(params.sessionToken)
|
||||
|
||||
@ -1654,6 +1737,11 @@ class ApiController {
|
||||
String API_CALL = "getRecordings"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -1728,6 +1816,11 @@ class ApiController {
|
||||
String API_CALL = "publishRecordings"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -1809,6 +1902,11 @@ class ApiController {
|
||||
String API_CALL = "deleteRecordings"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -1879,6 +1977,11 @@ class ApiController {
|
||||
String API_CALL = "updateRecordings"
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
// BEGIN - backward compatibility
|
||||
if (StringUtils.isEmpty(params.checksum)) {
|
||||
invalid("checksumError", "You did not pass the checksum security check")
|
||||
@ -1950,13 +2053,17 @@ class ApiController {
|
||||
def uploadDocuments(conf) { //
|
||||
log.debug("ApiController#uploadDocuments(${conf.getInternalId()})");
|
||||
|
||||
//sanitizeInput
|
||||
params.each {
|
||||
key, value -> params[key] = sanitizeInput(value)
|
||||
}
|
||||
|
||||
String requestBody = request.inputStream == null ? null : request.inputStream.text;
|
||||
requestBody = StringUtils.isEmpty(requestBody) ? null : requestBody;
|
||||
|
||||
if (requestBody == null) {
|
||||
downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId(), true /* default presentation */, '');
|
||||
} else {
|
||||
log.debug "Request body: \n" + requestBody;
|
||||
def xml = new XmlSlurper().parseText(requestBody);
|
||||
xml.children().each { module ->
|
||||
log.debug("module config found: [${module.@name}]");
|
||||
@ -2143,6 +2250,16 @@ class ApiController {
|
||||
return us
|
||||
}
|
||||
|
||||
private def sanitizeInput (input) {
|
||||
if(input == null)
|
||||
return
|
||||
|
||||
if(!("java.lang.String".equals(input.getClass().getName())))
|
||||
return input
|
||||
|
||||
StringUtils.strip(input.replaceAll("\\p{Cntrl}", ""));
|
||||
}
|
||||
|
||||
def sanitizeSessionToken(param) {
|
||||
if (param == null) {
|
||||
log.info("sanitizeSessionToken: token is null")
|
||||
|
Loading…
Reference in New Issue
Block a user