Merge remote-tracking branch 'Upstream/master' into start-poll-01

This commit is contained in:
KDSBrowne 2018-10-16 15:19:24 +00:00
commit 45eeb1d400
22 changed files with 703 additions and 862 deletions

View File

@ -101,6 +101,16 @@ object RecMeta {
}
}
def getDataMetrics(metaXml: Elem): Option[RecMetaDataMetrics] = {
val data = metaXml \ "data"
if (data.isEmpty) None
else {
val format = getText(data, "format", "unknown")
val link = getText(data, "link", "unknown")
Some(RecMetaDataMetrics(format, link))
}
}
def getExtensions(playbackXml: NodeSeq): Option[NodeSeq] = {
val extensions = playbackXml \ "extensions"
if (extensions.isEmpty) None
@ -135,6 +145,7 @@ object RecMeta {
val meeting = getMeeting(metaXml)
val meta = getMeta(metaXml)
val playback = getPlayback(metaXml)
val dataMetrics = getDataMetrics(metaXml)
val breakout = getBreakout(metaXml)
val breakoutRooms = getBreakoutRooms(metaXml)
@ -168,7 +179,7 @@ object RecMeta {
Some(RecMeta(id, meetingId, internalMeetingId, meetingName, state, published,
startTime, endTime, participants, rawSize, isBreakout,
meeting, meta, playback, breakout, breakoutRooms))
meeting, meta, playback, dataMetrics, breakout, breakoutRooms))
}
}
@ -176,7 +187,7 @@ case class RecMeta(id: String, meetingId: String, internalMeetingId: Option[ Str
meetingName: String, state: String, published: Boolean, startTime: Long, endTime: Long,
participants: Int, rawSize: Long, isBreakout: Boolean, meeting: Option[RecMetaMeeting],
meta: Option[collection.immutable.Map[String, String]], playback: Option[RecMetaPlayback],
breakout: Option[RecMetaBreakout], breakoutRooms: Vector[String]) {
dataMetrics: Option[RecMetaDataMetrics], breakout: Option[RecMetaBreakout], breakoutRooms: Vector[String]) {
def setState(state: String): RecMeta = this.copy(state = state)
def setPublished(publish: Boolean): RecMeta = this.copy(published = publish)
@ -253,6 +264,8 @@ case class RecMeta(id: String, meetingId: String, internalMeetingId: Option[ Str
}
playback foreach(p => buffer += p.toXml())
dataMetrics foreach(p => buffer += p.toXml())
<recording>{buffer}</recording>
}
@ -305,6 +318,8 @@ case class RecMeta(id: String, meetingId: String, internalMeetingId: Option[ Str
playback foreach(p => buffer += p.toMetadataXml())
dataMetrics foreach(p => buffer += p.toMetadataXml())
buffer += rawSizeElem
<recording>{buffer}</recording>
@ -390,6 +405,43 @@ case class RecMetaPlayback(format: String, link: String, processingTime: Int,
}
}
case class RecMetaDataMetrics(format: String, link: String) {
def toXml(): Elem = {
val formatElem = <type>{format}</type>
val urlElem = <url>{link}</url>
val buffer = new scala.xml.NodeBuffer
buffer += formatElem
buffer += urlElem
<data><format>{buffer}</format></data>
}
def toMetadataXml(): Elem = {
val formatElem = <format>{format}</format>
val urlElem = <link>{link}</link>
val buffer = new scala.xml.NodeBuffer
buffer += formatElem
buffer += urlElem
<data>{buffer}</data>
}
// Merged data formats when responding to get recordings API call
def toFormatXml(): Elem = {
val buffer = new scala.xml.NodeBuffer
val formatElem = <type>{format}</type>
val urlElem = <url>{link}</url>
buffer += formatElem
buffer += urlElem
<format>{buffer}</format>
}
}
case class RecMetaImage(width: String, height: String, alt: String, link: String)
@ -429,6 +481,7 @@ case class RecMetaResponse(
meeting: Option[RecMetaMeeting],
meta: Option[collection.immutable.Map[String, String]],
playbacks: ListBuffer[RecMetaPlayback],
data: ListBuffer[RecMetaDataMetrics],
breakout: Option[RecMetaBreakout],
breakoutRooms: Vector[String]) {
@ -438,6 +491,10 @@ case class RecMetaResponse(
case Some(p) => this.playbacks += p
case None =>
}
r.dataMetrics match {
case Some(p) => this.data += p
case None =>
}
this
}
@ -498,6 +555,12 @@ case class RecMetaResponse(
val playbackElem = <playback>{formats}</playback>
buffer += playbackElem
// Iterate over all formats before include the data tag
val dataFormats = new scala.xml.NodeBuffer
data foreach(p => dataFormats += p.toFormatXml())
val dataFormatElem = <data>{dataFormats}</data>
buffer += dataFormatElem
<recording>{buffer}</recording>
}
}

View File

@ -10,7 +10,7 @@ import org.bigbluebutton.api.domain.RecordingMetadata
import org.bigbluebutton.api2.RecordingServiceGW
import org.bigbluebutton.api2.domain._
import scala.xml.{Elem, PrettyPrinter, XML}
import scala.xml.{Elem, PrettyPrinter, XML}
import scala.collection.JavaConverters._
import scala.collection.mutable.{Buffer, ListBuffer, Map}
import scala.collection.Iterable
@ -123,6 +123,10 @@ class RecMetaXmlHelper extends RecordingServiceGW with LogHelper {
case Some(p) => ListBuffer(p)
case None => ListBuffer()
},
recMeta.dataMetrics match {
case Some(p) => ListBuffer(p)
case None => ListBuffer()
},
recMeta.breakout,
recMeta.breakoutRooms
)

View File

@ -30,11 +30,14 @@
<g:if test="${ismoderator}">
<th class="header c6 lastcol" style="text-align:center;" scope="col"><g:message code="tool.view.actions" /></th>
</g:if>
<g:else>
<th class="header c5 lastcol" style="text-align:center;" scope="col"></th>
</g:else>
</tr>
</thead>
<tbody>
<g:each in="${recordingList}" var="r">
<g:if test="${ismoderator || r.published == 'true'}">
<g:if test="${ismoderator || r.published}">
<tr class="r0 lastrow">
<td class="cell c0" style="text-align:center;">
<g:if test="${r.published}">
@ -75,6 +78,10 @@
</a>
</td>
</g:if>
<g:else>
<td class="cell c5 lastcol" style="text-align:center;">
</td>
</g:else>
</tr>
</g:if>
</g:each>

View File

@ -2,6 +2,7 @@ const isFirefox = typeof window.InstallTrigger !== 'undefined';
const isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
const isChrome = !!window.chrome && !isOpera;
const isSafari = navigator.userAgent.indexOf('Safari') >= 0 && !isChrome;
const isElectron = navigator.userAgent.toLowerCase().indexOf(' electron/') > -1;
const kurentoHandler = null;
Kurento = function (
@ -639,6 +640,31 @@ window.getScreenConstraints = function (sendSource, callback) {
});
};
const optionalConstraints = [
{ googCpuOveruseDetection: true },
{ googCpuOveruseEncodeUsage: true },
{ googCpuUnderuseThreshold: 55 },
{ googCpuOveruseThreshold: 100 },
{ googPayloadPadding: true },
{ googScreencastMinBitrate: 600 },
{ googHighStartBitrate: true },
{ googHighBitrate: true },
{ googVeryHighBitrate: true },
];
if (isElectron) {
var sourceId = ipcRenderer.sendSync('screen-chooseSync');
kurentoManager.kurentoScreenshare.extensionInstalled = true;
// this statement sets gets 'sourceId" and sets "chromeMediaSourceId"
screenConstraints.video.chromeMediaSource = { exact: [sendSource] };
screenConstraints.video.chromeMediaSourceId = sourceId;
screenConstraints.optional = optionalConstraints;
console.log('getScreenConstraints for Chrome returns => ', screenConstraints);
return callback(null, screenConstraints);
}
if (isChrome) {
const extensionKey = kurentoManager.getChromeExtensionKey();
getChromeScreenConstraints(extensionKey).then((constraints) => {
@ -654,17 +680,7 @@ window.getScreenConstraints = function (sendSource, callback) {
// this statement sets gets 'sourceId" and sets "chromeMediaSourceId"
screenConstraints.video.chromeMediaSource = { exact: [sendSource] };
screenConstraints.video.chromeMediaSourceId = sourceId;
screenConstraints.optional = [
{ googCpuOveruseDetection: true },
{ googCpuOveruseEncodeUsage: true },
{ googCpuUnderuseThreshold: 55 },
{ googCpuOveruseThreshold: 100 },
{ googPayloadPadding: true },
{ googScreencastMinBitrate: 600 },
{ googHighStartBitrate: true },
{ googHighBitrate: true },
{ googVeryHighBitrate: true },
];
screenConstraints.optional = optionalConstraints;
console.log('getScreenConstraints for Chrome returns => ', screenConstraints);
return callback(null, screenConstraints);

View File

@ -3,13 +3,8 @@ import { check } from 'meteor/check';
import Meetings from '/imports/api/meetings';
import Logger from '/imports/startup/server/logger';
import addGroupChatMsg from '/imports/api/group-chat-msg/server/modifiers/addGroupChatMsg';
export default function addMeeting(meeting) {
const meetingId = meeting.meetingProp.intId;
const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_SYSTEM_ID = CHAT_CONFIG.system_userid;
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
check(meetingId, String);
check(meeting, {
@ -81,19 +76,6 @@ export default function addMeeting(meeting) {
),
};
const welcomeMsg = {
color: '0',
timestamp: Date.now(),
correlationId: `${PUBLIC_CHAT_SYSTEM_ID}-${Date.now()}`,
sender: {
id: PUBLIC_CHAT_SYSTEM_ID,
name: '',
},
message: meeting.welcomeProp.welcomeMsg,
};
addGroupChatMsg(meetingId, PUBLIC_GROUP_CHAT_ID, welcomeMsg);
const cb = (err, numChanged) => {
if (err) {
Logger.error(`Adding meeting to collection: ${err}`);

View File

@ -77,6 +77,7 @@ export default function addUser(meetingId, user) {
roles: [ROLE_VIEWER.toLowerCase()],
sortName: user.name.trim().toLowerCase(),
color,
logTime: Date.now(),
},
flat(user),
),

View File

@ -2,6 +2,7 @@ import { Meteor } from 'meteor/meteor';
import Langmap from 'langmap';
import Users from '/imports/api/users';
import fs from 'fs';
import './settings';
import Logger from './logger';
import Redis from './redis';

View File

@ -0,0 +1,18 @@
import { Meteor } from 'meteor/meteor';
import fs from 'fs';
import YAML from 'yaml';
const YAML_FILE_PATH = 'assets/app/config/settings.yml';
try {
if (fs.existsSync(YAML_FILE_PATH)) {
const SETTINGS = YAML.parse(fs.readFileSync(YAML_FILE_PATH, 'utf-8'));
Meteor.settings = SETTINGS;
__meteor_runtime_config__.PUBLIC_SETTINGS = SETTINGS.public;
} else {
throw new Error('File doesn\'t exists');
}
} catch (error) {
console.error('Error on load configuration file.', error);
}

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import { withTracker } from 'meteor/react-meteor-data';
import Auth from '/imports/ui/services/auth';
import Chat from './component';
import ChatService from './service';
@ -52,7 +53,61 @@ export default injectIntl(withTracker(({ params, intl }) => {
let systemMessageIntl = {};
if (chatID === PUBLIC_CHAT_KEY) {
messages = ChatService.reduceAndMapGroupMessages(ChatService.getPublicGroupMessages());
const { welcomeProp } = ChatService.getMeeting();
const user = ChatService.getUser(Auth.userID);
messages = ChatService.getPublicGroupMessages();
const time = user.logTime;
const welcomeId = `welcome-msg-${time}`;
const welcomeMsg = {
id: welcomeId,
content: [{
id: welcomeId,
text: welcomeProp.welcomeMsg,
time,
}],
time,
sender: null,
};
const moderatorTime = time + 1;
const moderatorId = `moderator-msg-${moderatorTime}`;
const moderatorMsg = {
id: moderatorId,
content: [{
id: moderatorId,
text: welcomeProp.modOnlyMessage,
time: moderatorTime,
}],
time: moderatorTime,
sender: null,
};
const messagesBeforeWelcomeMsg =
ChatService.reduceAndMapGroupMessages(messages.filter(message => message.timestamp < time));
const messagesAfterWelcomeMsg =
ChatService.reduceAndMapGroupMessages(messages.filter(message => message.timestamp >= time));
const clearMessage = messages.filter(message => message.message === 'PUBLIC_CHAT_CLEAR');
const hasClearMessage = clearMessage.length;
const showWelcomeMsg =
(hasClearMessage && clearMessage[0].timestamp < time) || !hasClearMessage;
const showModeratorMsg =
(user.isModerator)
&& ((hasClearMessage && clearMessage[0].timestamp < moderatorTime) || !hasClearMessage);
const messagesFormated = messagesBeforeWelcomeMsg
.concat(showWelcomeMsg ? welcomeMsg : [])
.concat(showModeratorMsg ? moderatorMsg : [])
.concat(messagesAfterWelcomeMsg);
messages = messagesFormated.sort((a, b) => (a.time - b.time));
} else {
messages = ChatService.getPrivateGroupMessages(chatID);

View File

@ -34,6 +34,8 @@ const getUser = (userId) => {
return mapUser(user);
};
const getMeeting = () => Meetings.findOne({});
const mapGroupMessage = (message) => {
const mappedMessage = {
id: message._id,
@ -267,6 +269,7 @@ export default {
getPublicGroupMessages,
getPrivateGroupMessages,
getUser,
getMeeting,
getScrollPosition,
hasUnreadMessages,
lastReadMessageTime,

View File

@ -41,5 +41,5 @@
.overlay {
@extend .overlay;
background-color: rgba(0, 0, 0, .5);
background-color: rgba(6, 23, 42, 0.75);
}

View File

@ -30,6 +30,7 @@ const mapUser = (user) => {
isPhoneUser: user.phone_user,
isOnline: user.connectionStatus === 'online',
clientType: user.clientType,
logTime: user.logTime,
};
mappedUser.isLocked = user.locked && !(mappedUser.isPresenter || mappedUser.isModerator);

View File

@ -2028,8 +2028,7 @@
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"inquirer": {
"version": "3.3.0",
@ -4017,9 +4016,16 @@
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"dev": true,
"requires": {
"minimist": "0.0.10",
"wordwrap": "0.0.3"
},
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
@ -5980,6 +5986,11 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
},
"yaml": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.0.0.tgz",
"integrity": "sha512-HLMg8IQRQLLPZ/tVtR0j5ShAh4HJKt8soYsu0Fn3Y5eoIFJoh1cs1mvvOnRD236mjeBDarlk5Ng/b/IHQs+5Rg=="
},
"yargs": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",

View File

@ -7,8 +7,8 @@
"generate-refs-visual-regression": "rm -rf tests/webdriverio/screenshots; npm run test-visual-regression",
"test-visual-regression-desktop": "export BROWSER_NAME=firefox; wdio ./tests/webdriverio/wdio.vreg.conf.js; export BROWSER_NAME=chrome; wdio ./tests/webdriverio/wdio.vreg.conf.js",
"generate-refs-visual-regression-desktop": "rm -rf tests/webdriverio/screenshots; npm run test-visual-regression-desktop",
"start:prod": "meteor reset && ROOT_URL=http://127.0.0.1/html5client NODE_ENV=production meteor --production --settings private/config/settings-production.json",
"start:dev": "ROOT_URL=http://127.0.0.1/html5client NODE_ENV=development meteor --settings private/config/settings-development.json",
"start:prod": "meteor reset && ROOT_URL=http://127.0.0.1/html5client NODE_ENV=production meteor --production",
"start:dev": "ROOT_URL=http://127.0.0.1/html5client NODE_ENV=development meteor",
"test": "wdio ./tests/webdriverio/wdio.conf.js",
"lint": "eslint . --ext .jsx,.js",
"precommit": "lint-staged"
@ -67,7 +67,8 @@
"redis": "~2.8.0",
"string-hash": "~1.1.3",
"tippy.js": "~2.0.2",
"winston": "^2.4.4"
"winston": "^2.4.4",
"yaml": "^1.0.0"
},
"devDependencies": {
"chai": "~4.1.2",

View File

@ -1,410 +0,0 @@
{
"public": {
"app": {
"mobileFont": 16,
"desktopFont": 14,
"audioChatNotification": false,
"autoJoin": true,
"listenOnlyMode": true,
"forceListenOnly": false,
"skipCheck": false,
"clientTitle": "BigBlueButton",
"appName": "BigBlueButton HTML5 Client",
"bbbServerVersion": "2.0-rc",
"copyright": "©2018 BigBlueButton Inc.",
"html5ClientBuild": "HTML5_CLIENT_VERSION",
"lockOnJoin": true,
"basename": "/html5client",
"askForFeedbackOnLogout": false,
"defaultSettings": {
"application": {
"chatAudioAlerts": false,
"chatPushAlerts": false,
"fontSize": "16px",
"fallbackLocale": "en"
},
"audio": {
"inputDeviceId": "undefined",
"outputDeviceId": "undefined"
},
"dataSaving": {
"viewParticipantsWebcams": true,
"viewScreenshare": true
},
"cc": {
"backgroundColor": "#FFFFFF",
"fontColor": "#000000",
"enabled": false,
"fontFamily": "Calibri",
"fontSize": "16px",
"takeOwnership": false
},
"participants": {
"muteAll": false,
"lockAll": false,
"microphone": false,
"publicChat": false,
"privateChat": false,
"layout": false
}
},
"shortcuts": {
"openOptions": {"accesskey": "O", "descId": "openOptions"},
"toggleUserList": {"accesskey": "U", "descId": "toggleUserList"},
"toggleMute": {"accesskey": "M", "descId": "toggleMute"},
"joinAudio": {"accesskey": "J", "descId": "joinAudio"},
"leaveAudio": {"accesskey": "L", "descId": "leaveAudio"},
"togglePublicChat": {"accesskey": "P", "descId": "togglePublicChat"},
"hidePrivateChat": {"accesskey": "H", "descId": "hidePrivateChat"},
"closePrivateChat": {"accesskey": "G", "descId": "closePrivateChat"},
"openActions": {"accesskey": "A", "descId": "openActions"},
"openStatus": {"accesskey": "S", "descId": "openStatus"}
},
"branding": {
"displayBrandingArea": false
},
"allowHTML5Moderator": true,
"allowModeratorToUnmuteAudio": true,
"httpsConnection": false,
"connectionTimeout": 60000,
"showHelpButton": true
},
"kurento": {
"wsUrl": "HOST",
"chromeDefaultExtensionKey": "akgoaoikmbmhcopjgakkcepdgdgkjfbc",
"chromeDefaultExtensionLink": "https://chrome.google.com/webstore/detail/bigbluebutton-screenshare/akgoaoikmbmhcopjgakkcepdgdgkjfbc",
"chromeExtensionKey": "KEY",
"chromeExtensionLink": "LINK",
"chromeScreenshareSources": ["window", "screen"],
"firefoxScreenshareSource": "window",
"cameraConstraints": {
"width": {
"max": 640
},
"height": {
"max": 480
}
},
"enableScreensharing": false,
"enableVideo": false,
"enableVideoStats": false,
"enableListenOnly": false
},
"acl": {
"viewer": {
"subscriptions": [
"users",
"cursor",
"screenshare",
"meetings",
"polls",
"chat",
"presentations",
"annotations",
"slides",
"captions",
"breakouts",
"voiceUsers",
"whiteboard-multi-user",
"presentation-pods",
"group-chat",
"group-chat-msg",
"users-settings"
],
"methods": [
"listenOnlyToggle",
"userLogout",
"setEmojiStatus",
"toggleSelfVoice",
"publishVote",
"sendChat",
"createGroupChat",
"destroyGroupChat",
"sendGroupChatMsg"
]
},
"moderator": {
"methods": [
"assignPresenter",
"removeUser",
"muteUser",
"unmuteUser",
"endMeeting",
"toggleVoice",
"clearPublicChatHistory",
"changeRole",
"ejectUserFromVoice",
"toggleRecording"
]
},
"presenter": {
"methods": [
"assignPresenter",
"switchSlide",
"modifyWhiteboardAccess",
"undoAnnotation",
"clearWhiteboard",
"moveCursor",
"sendAnnotation",
"removePresentation",
"setPresentation",
"requestPresentationUploadToken",
"zoomSlide",
"startPoll",
"stopPoll",
"publishPoll"
]
}
},
"poll": {
"max_custom": 5
},
"chat": {
"min_message_length": 1,
"max_message_length": 5000,
"grouping_messages_window": 10000,
"type_system": "SYSTEM_MESSAGE",
"type_public": "PUBLIC_ACCESS",
"type_private": "PRIVATE_ACCESS",
"system_userid": "SYSTEM_MESSAGE",
"system_username": "SYSTEM_MESSAGE",
"public_id": "public",
"public_group_id": "MAIN-PUBLIC-GROUP-CHAT",
"public_userid": "public_chat_userid",
"public_username": "public_chat_username",
"storage_key": "UNREAD_CHATS",
"path_route": "users/chat/",
"system_messages_keys": {
"chat_clear": "PUBLIC_CHAT_CLEAR"
}
},
"media": {
"WebRTCHangupRetryInterval": 2000,
"vertoServerAddress": "HOST",
"freeswitchProfilePassword": "1234",
"vertoPort": "8082",
"useSIPAudio": true,
"stunTurnServersFetchAddress": "/bigbluebutton/api/stuns",
"mediaTag": "#remote-media",
"callTransferTimeout": 5000,
"callHangupTimeout": 2000,
"callHangupMaximumRetries": 10,
"echoTestNumber": "9196"
},
"presentation": {
"defaultPresentationFile": "default.pdf",
"uploadEndpoint": "/bigbluebutton/presentation/upload",
"uploadSizeMin": 0,
"uploadSizeMax": 50000000,
"uploadValidMimeTypes": [
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.oasis.opendocument.text",
"application/rtf",
"text/plain",
"application/vnd.oasis.opendocument.spreadsheet",
"application/vnd.oasis.opendocument.presentation",
"application/vnd.oasis.opendocument.text",
"application/vnd.oasis.opendocument.graphics",
"application/vnd.oasis.opendocument.chart",
"application/vnd.oasis.opendocument.image",
"application/pdf",
"image/jpeg",
"image/png"
]
},
"user": {
"role_moderator": "MODERATOR",
"role_viewer": "VIEWER",
"role_presenter": "PRESENTER"
},
"whiteboard": {
"annotations": {
"status": {
"start": "DRAW_START",
"update": "DRAW_UPDATE",
"end": "DRAW_END"
}
},
"toolbar": {
"colors": [
{
"label": "black",
"value": "#000000"
},
{
"label": "white",
"value": "#ffffff"
},
{
"label": "red",
"value": "#ff0000"
},
{
"label": "orange",
"value": "#ff8800"
},
{
"label": "eletricLime",
"value": "#ccff00"
},
{
"label": "Lime",
"value": "#00ff00"
},
{
"label": "Cyan",
"value": "#00ffff"
},
{
"label": "dodgerBlue",
"value": "#0088ff"
},
{
"label": "blue",
"value": "#0000ff"
},
{
"label": "violet",
"value": "#8800ff"
},
{
"label": "magenta",
"value": "#ff00ff"
},
{
"label": "silver",
"value": "#c0c0c0"
}
],
"thickness": [
{
"value": 14
},
{
"value": 12
},
{
"value": 10
},
{
"value": 8
},
{
"value": 6
},
{
"value": 4
},
{
"value": 2
},
{
"value": 1
}
],
"font_sizes": [
{
"value": 36
},
{
"value": 32
},
{
"value": 28
},
{
"value": 24
},
{
"value": 20
},
{
"value": 16
}
],
"tools": [
{
"icon": "text_tool",
"value": "text"
},
{
"icon": "line_tool",
"value": "line"
},
{
"icon": "circle_tool",
"value": "ellipse"
},
{
"icon": "triangle_tool",
"value": "triangle"
},
{
"icon": "rectangle_tool",
"value": "rectangle"
},
{
"icon": "pen_tool",
"value": "pencil"
},
{
"icon": "hand",
"value": "hand"
}
]
}
},
"clientLog": {
"server": { "enabled": true, "level": "info" },
"console": { "enabled": false, "level": "debug" },
"external": { "enabled": false, "level": "info", "url": "https://LOG_HOST/html5Log", "method": "POST" }
}
},
"private": {
"app": {
"captionsChunkLength": 1000,
"pencilChunkLength": 100
},
"redis": {
"host": "127.0.0.1",
"post": "6379",
"timeout": 5000,
"debug": true,
"channels": {
"toAkkaApps": "to-akka-apps-redis-channel"
},
"subscribeTo": [
"to-html5-redis-channel",
"from-akka-apps-*"
],
"async": [
"from-akka-apps-wb-redis-channel"
],
"ignored": [
"CheckAlivePongSysMsg",
"DoLatencyTracerMsg"
]
},
"serverLog": {
"level": "info"
}
}
}

View File

@ -1,410 +0,0 @@
{
"public": {
"app": {
"mobileFont": 16,
"desktopFont": 14,
"audioChatNotification": false,
"autoJoin": true,
"listenOnlyMode": true,
"forceListenOnly": false,
"skipCheck": false,
"clientTitle": "BigBlueButton",
"appName": "BigBlueButton HTML5 Client",
"bbbServerVersion": "2.0-rc",
"copyright": "©2018 BigBlueButton Inc.",
"html5ClientBuild": "HTML5_CLIENT_VERSION",
"lockOnJoin": true,
"basename": "/html5client",
"askForFeedbackOnLogout": false,
"defaultSettings": {
"application": {
"chatAudioAlerts": false,
"chatPushAlerts": false,
"fontSize": "16px",
"fallbackLocale": "en"
},
"audio": {
"inputDeviceId": "undefined",
"outputDeviceId": "undefined"
},
"dataSaving": {
"viewParticipantsWebcams": true,
"viewScreenshare": true
},
"cc": {
"backgroundColor": "#FFFFFF",
"fontColor": "#000000",
"enabled": false,
"fontFamily": "Calibri",
"fontSize": "16px",
"takeOwnership": false
},
"participants": {
"muteAll": false,
"lockAll": false,
"microphone": false,
"publicChat": false,
"privateChat": false,
"layout": false
}
},
"shortcuts": {
"openOptions": {"accesskey": "O", "descId": "openOptions"},
"toggleUserList": {"accesskey": "U", "descId": "toggleUserList"},
"toggleMute": {"accesskey": "M", "descId": "toggleMute"},
"joinAudio": {"accesskey": "J", "descId": "joinAudio"},
"leaveAudio": {"accesskey": "L", "descId": "leaveAudio"},
"togglePublicChat": {"accesskey": "P", "descId": "togglePublicChat"},
"hidePrivateChat": {"accesskey": "H", "descId": "hidePrivateChat"},
"closePrivateChat": {"accesskey": "G", "descId": "closePrivateChat"},
"openActions": {"accesskey": "A", "descId": "openActions"},
"openStatus": {"accesskey": "S", "descId": "openStatus"}
},
"branding": {
"displayBrandingArea": false
},
"allowHTML5Moderator": true,
"allowModeratorToUnmuteAudio": true,
"httpsConnection": true,
"connectionTimeout": 10000,
"showHelpButton": true
},
"kurento": {
"wsUrl": "HOST",
"chromeDefaultExtensionKey": "akgoaoikmbmhcopjgakkcepdgdgkjfbc",
"chromeDefaultExtensionLink": "https://chrome.google.com/webstore/detail/bigbluebutton-screenshare/akgoaoikmbmhcopjgakkcepdgdgkjfbc",
"chromeExtensionKey": "KEY",
"chromeExtensionLink": "LINK",
"chromeScreenshareSources": ["window", "screen"],
"firefoxScreenshareSource": "window",
"cameraConstraints": {
"width": {
"max": 640
},
"height": {
"max": 480
}
},
"enableScreensharing": false,
"enableVideo": false,
"enableVideoStats": false,
"enableListenOnly": false
},
"acl": {
"viewer": {
"subscriptions": [
"users",
"cursor",
"screenshare",
"meetings",
"polls",
"chat",
"presentations",
"annotations",
"slides",
"captions",
"breakouts",
"voiceUsers",
"whiteboard-multi-user",
"presentation-pods",
"group-chat",
"group-chat-msg",
"users-settings"
],
"methods": [
"listenOnlyToggle",
"userLogout",
"setEmojiStatus",
"toggleSelfVoice",
"publishVote",
"sendChat",
"createGroupChat",
"destroyGroupChat",
"sendGroupChatMsg"
]
},
"moderator": {
"methods": [
"assignPresenter",
"removeUser",
"muteUser",
"unmuteUser",
"endMeeting",
"toggleVoice",
"clearPublicChatHistory",
"changeRole",
"ejectUserFromVoice",
"toggleRecording"
]
},
"presenter": {
"methods": [
"assignPresenter",
"switchSlide",
"modifyWhiteboardAccess",
"undoAnnotation",
"clearWhiteboard",
"moveCursor",
"sendAnnotation",
"removePresentation",
"setPresentation",
"zoomSlide",
"requestPresentationUploadToken",
"startPoll",
"stopPoll",
"publishPoll"
]
}
},
"poll": {
"max_custom": 5
},
"chat": {
"min_message_length": 1,
"max_message_length": 5000,
"grouping_messages_window": 10000,
"type_system": "SYSTEM_MESSAGE",
"type_public": "PUBLIC_ACCESS",
"type_private": "PRIVATE_ACCESS",
"system_userid": "SYSTEM_MESSAGE",
"system_username": "SYSTEM_MESSAGE",
"public_id": "public",
"public_group_id": "MAIN-PUBLIC-GROUP-CHAT",
"public_userid": "public_chat_userid",
"public_username": "public_chat_username",
"storage_key": "UNREAD_CHATS",
"path_route": "users/chat/",
"system_messages_keys": {
"chat_clear": "PUBLIC_CHAT_CLEAR"
}
},
"media": {
"WebRTCHangupRetryInterval": 2000,
"vertoServerAddress": "HOST",
"freeswitchProfilePassword": "1234",
"vertoPort": "8082",
"useSIPAudio": true,
"stunTurnServersFetchAddress": "/bigbluebutton/api/stuns",
"mediaTag": "#remote-media",
"callTransferTimeout": 5000,
"callHangupTimeout": 2000,
"callHangupMaximumRetries": 10,
"echoTestNumber": "9196"
},
"presentation": {
"defaultPresentationFile": "default.pdf",
"uploadEndpoint": "/bigbluebutton/presentation/upload",
"uploadSizeMin": 0,
"uploadSizeMax": 50000000,
"uploadValidMimeTypes": [
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.oasis.opendocument.text",
"application/rtf",
"text/plain",
"application/vnd.oasis.opendocument.spreadsheet",
"application/vnd.oasis.opendocument.presentation",
"application/vnd.oasis.opendocument.text",
"application/vnd.oasis.opendocument.graphics",
"application/vnd.oasis.opendocument.chart",
"application/vnd.oasis.opendocument.image",
"application/pdf",
"image/jpeg",
"image/png"
]
},
"user": {
"role_moderator": "MODERATOR",
"role_viewer": "VIEWER",
"role_presenter": "PRESENTER"
},
"whiteboard": {
"annotations": {
"status": {
"start": "DRAW_START",
"update": "DRAW_UPDATE",
"end": "DRAW_END"
}
},
"toolbar": {
"colors": [
{
"label": "black",
"value": "#000000"
},
{
"label": "white",
"value": "#ffffff"
},
{
"label": "red",
"value": "#ff0000"
},
{
"label": "orange",
"value": "#ff8800"
},
{
"label": "eletricLime",
"value": "#ccff00"
},
{
"label": "Lime",
"value": "#00ff00"
},
{
"label": "Cyan",
"value": "#00ffff"
},
{
"label": "dodgerBlue",
"value": "#0088ff"
},
{
"label": "blue",
"value": "#0000ff"
},
{
"label": "violet",
"value": "#8800ff"
},
{
"label": "magenta",
"value": "#ff00ff"
},
{
"label": "silver",
"value": "#c0c0c0"
}
],
"thickness": [
{
"value": 14
},
{
"value": 12
},
{
"value": 10
},
{
"value": 8
},
{
"value": 6
},
{
"value": 4
},
{
"value": 2
},
{
"value": 1
}
],
"font_sizes": [
{
"value": 36
},
{
"value": 32
},
{
"value": 28
},
{
"value": 24
},
{
"value": 20
},
{
"value": 16
}
],
"tools": [
{
"icon": "text_tool",
"value": "text"
},
{
"icon": "line_tool",
"value": "line"
},
{
"icon": "circle_tool",
"value": "ellipse"
},
{
"icon": "triangle_tool",
"value": "triangle"
},
{
"icon": "rectangle_tool",
"value": "rectangle"
},
{
"icon": "pen_tool",
"value": "pencil"
},
{
"icon": "hand",
"value": "hand"
}
]
}
},
"clientLog": {
"server": { "enabled": true, "level": "info" },
"console": { "enabled": false, "level": "debug" },
"external": { "enabled": false, "level": "info", "url": "https://LOG_HOST/html5Log", "method": "POST" }
}
},
"private": {
"app": {
"captionsChunkLength": 1000,
"pencilChunkLength": 100
},
"redis": {
"host": "127.0.0.1",
"post": "6379",
"timeout": 5000,
"debug": true,
"channels": {
"toAkkaApps": "to-akka-apps-redis-channel"
},
"subscribeTo": [
"to-html5-redis-channel",
"from-akka-apps-*"
],
"async": [
"from-akka-apps-wb-redis-channel"
],
"ignored": [
"CheckAlivePongSysMsg",
"DoLatencyTracerMsg"
]
},
"serverLog": {
"level": "info"
}
}
}

View File

@ -0,0 +1,310 @@
public:
app:
mobileFont: 16
desktopFont: 14
audioChatNotification: false
autoJoin: true
listenOnlyMode: true
forceListenOnly: false
skipCheck: false
clientTitle: BigBlueButton
appName: BigBlueButton HTML5 Client
bbbServerVersion: 2.0-rc
copyright: "©2018 BigBlueButton Inc."
html5ClientBuild: HTML5_CLIENT_VERSION
lockOnJoin: true
basename: "/html5client"
askForFeedbackOnLogout: false
defaultSettings:
application:
chatAudioAlerts: false
chatPushAlerts: false
fontSize: 16px
fallbackLocale: en
audio:
inputDeviceId: undefined
outputDeviceId: undefined
dataSaving:
viewParticipantsWebcams: true
viewScreenshare: true
cc:
backgroundColor: "#FFFFFF"
fontColor: "#000000"
enabled: false
fontFamily: Calibri
fontSize: 16px
takeOwnership: false
participants:
muteAll: false
lockAll: false
microphone: false
publicChat: false
privateChat: false
layout: false
shortcuts:
openOptions:
accesskey: O
descId: openOptions
toggleUserList:
accesskey: U
descId: toggleUserList
toggleMute:
accesskey: M
descId: toggleMute
joinAudio:
accesskey: J
descId: joinAudio
leaveAudio:
accesskey: L
descId: leaveAudio
togglePublicChat:
accesskey: P
descId: togglePublicChat
hidePrivateChat:
accesskey: H
descId: hidePrivateChat
closePrivateChat:
accesskey: G
descId: closePrivateChat
openActions:
accesskey: A
descId: openActions
openStatus:
accesskey: S
descId: openStatus
branding:
displayBrandingArea: false
allowHTML5Moderator: true
allowModeratorToUnmuteAudio: true
httpsConnection: false
connectionTimeout: 60000
showHelpButton: true
kurento:
wsUrl: HOST
chromeDefaultExtensionKey: akgoaoikmbmhcopjgakkcepdgdgkjfbc
chromeDefaultExtensionLink: https://chrome.google.com/webstore/detail/bigbluebutton-screenshare/akgoaoikmbmhcopjgakkcepdgdgkjfbc
chromeExtensionKey: KEY
chromeExtensionLink: LINK
chromeScreenshareSources:
- window
- screen
firefoxScreenshareSource: window
cameraConstraints:
width:
max: 640
height:
max: 480
enableScreensharing: false
enableVideo: false
enableVideoStats: false
enableListenOnly: false
acl:
viewer:
subscriptions:
- users
- cursor
- screenshare
- meetings
- polls
- chat
- presentations
- annotations
- slides
- captions
- breakouts
- voiceUsers
- whiteboard-multi-user
- presentation-pods
- group-chat
- group-chat-msg
- users-settings
methods:
- listenOnlyToggle
- userLogout
- setEmojiStatus
- toggleSelfVoice
- publishVote
- sendChat
- createGroupChat
- destroyGroupChat
- sendGroupChatMsg
moderator:
methods:
- assignPresenter
- removeUser
- muteUser
- unmuteUser
- endMeeting
- toggleVoice
- clearPublicChatHistory
- changeRole
- ejectUserFromVoice
- toggleRecording
presenter:
methods:
- assignPresenter
- switchSlide
- modifyWhiteboardAccess
- undoAnnotation
- clearWhiteboard
- moveCursor
- sendAnnotation
- removePresentation
- setPresentation
- zoomSlide
- requestPresentationUploadToken
poll:
max_custom: 5
chat:
min_message_length: 1
max_message_length: 5000
grouping_messages_window: 10000
type_system: SYSTEM_MESSAGE
type_public: PUBLIC_ACCESS
type_private: PRIVATE_ACCESS
system_userid: SYSTEM_MESSAGE
system_username: SYSTEM_MESSAGE
public_id: public
public_group_id: MAIN-PUBLIC-GROUP-CHAT
public_userid: public_chat_userid
public_username: public_chat_username
storage_key: UNREAD_CHATS
path_route: users/chat/
system_messages_keys:
chat_clear: PUBLIC_CHAT_CLEAR
media:
WebRTCHangupRetryInterval: 2000
vertoServerAddress: HOST
freeswitchProfilePassword: '1234'
vertoPort: '8082'
useSIPAudio: true
stunTurnServersFetchAddress: "/bigbluebutton/api/stuns"
mediaTag: "#remote-media"
callTransferTimeout: 5000
callHangupTimeout: 2000
callHangupMaximumRetries: 10
echoTestNumber: '9196'
presentation:
defaultPresentationFile: default.pdf
uploadEndpoint: "/bigbluebutton/presentation/upload"
uploadSizeMin: 0
uploadSizeMax: 50000000
uploadValidMimeTypes:
- application/vnd.ms-excel
- application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
- application/msword
- application/vnd.openxmlformats-officedocument.wordprocessingml.document
- application/vnd.ms-powerpoint
- application/vnd.openxmlformats-officedocument.presentationml.presentation
- application/vnd.oasis.opendocument.text
- application/rtf
- text/plain
- application/vnd.oasis.opendocument.spreadsheet
- application/vnd.oasis.opendocument.presentation
- application/vnd.oasis.opendocument.text
- application/vnd.oasis.opendocument.graphics
- application/vnd.oasis.opendocument.chart
- application/vnd.oasis.opendocument.image
- application/pdf
- image/jpeg
- image/png
user:
role_moderator: MODERATOR
role_viewer: VIEWER
role_presenter: PRESENTER
whiteboard:
annotations:
status:
start: DRAW_START
update: DRAW_UPDATE
end: DRAW_END
toolbar:
colors:
- label: black
value: "#000000"
- label: white
value: "#ffffff"
- label: red
value: "#ff0000"
- label: orange
value: "#ff8800"
- label: eletricLime
value: "#ccff00"
- label: Lime
value: "#00ff00"
- label: Cyan
value: "#00ffff"
- label: dodgerBlue
value: "#0088ff"
- label: blue
value: "#0000ff"
- label: violet
value: "#8800ff"
- label: magenta
value: "#ff00ff"
- label: silver
value: "#c0c0c0"
thickness:
- value: 14
- value: 12
- value: 10
- value: 8
- value: 6
- value: 4
- value: 2
- value: 1
font_sizes:
- value: 36
- value: 32
- value: 28
- value: 24
- value: 20
- value: 16
tools:
- icon: text_tool
value: text
- icon: line_tool
value: line
- icon: circle_tool
value: ellipse
- icon: triangle_tool
value: triangle
- icon: rectangle_tool
value: rectangle
- icon: pen_tool
value: pencil
- icon: hand
value: hand
clientLog:
server:
enabled: true
level: info
console:
enabled: false
level: debug
external:
enabled: false
level: info
url: https://LOG_HOST/html5Log
method: POST
private:
app:
captionsChunkLength: 1000
pencilChunkLength: 100
redis:
host: 127.0.0.1
post: '6379'
timeout: 5000
debug: true
channels:
toAkkaApps: to-akka-apps-redis-channel
subscribeTo:
- to-html5-redis-channel
- from-akka-apps-*
async:
- from-akka-apps-wb-redis-channel
ignored:
- CheckAlivePongSysMsg
- DoLatencyTracerMsg
serverLog:
level: info

View File

@ -109,7 +109,7 @@
"app.waitingMessage": "Disconnected. Trying to reconnect in {0} seconds...",
"app.navBar.settingsDropdown.optionsLabel": "Options",
"app.navBar.settingsDropdown.fullscreenLabel": "Make fullscreen",
"app.navBar.settingsDropdown.settingsLabel": "Open settings",
"app.navBar.settingsDropdown.settingsLabel": "Settings",
"app.navBar.settingsDropdown.aboutLabel": "About",
"app.navBar.settingsDropdown.leaveSessionLabel": "Logout",
"app.navBar.settingsDropdown.exitFullscreenLabel": "Exit fullscreen",

View File

@ -27,3 +27,5 @@ gem "trollop"
gem "open4"
gem "fastimage"
gem "absolute_time"
gem "jwt"
gem "java_properties"

View File

@ -4,6 +4,8 @@ GEM
absolute_time (1.0.0)
builder (3.2.3)
fastimage (2.1.0)
java_properties (0.0.4)
jwt (2.1.0)
mini_portile2 (2.3.0)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
@ -19,6 +21,8 @@ DEPENDENCIES
absolute_time
builder
fastimage
java_properties
jwt
nokogiri
open4
redis
@ -26,4 +30,4 @@ DEPENDENCIES
trollop
BUNDLED WITH
1.13.7
1.15.4

View File

@ -0,0 +1,89 @@
#!/usr/bin/ruby
require File.expand_path('../../lib/recordandplayback', __FILE__)
require 'trollop'
props = YAML::load(File.open(File.expand_path('../bigbluebutton.yml', __FILE__)))
log_dir = props['log_dir']
published_dir = props['published_dir']
unpublished_dir = "#{published_dir}/../unpublished"
opts = Trollop::options do
opt(:force, "Run script even if it has previously been run",
:default => false)
opt(:quiet, "Minimal output mode, for automated use",
:default => false)
end
log_file = "#{log_dir}/bbb-1.1-meeting-tag.log"
done_file = "#{props['recording_dir']}/status/bbb-1.1-meeting-tag.done"
logger = Logger.new(log_file)
logger.level = Logger::INFO
BigBlueButton.logger = logger
if File.exist?(done_file) and !opts.force
if !opts.quiet
puts "Script has previously been run, doing nothing"
puts "Use the --force option to override"
end
exit 0
end
def do_update(recording_dir, format_dir)
match = /([^\/]*)$/.match(recording_dir)
meeting_id = match[1]
match = /([^\/]*)$/.match(format_dir)
format = match[1]
BigBlueButton.logger.info("Processing #{format} recording #{meeting_id}")
xml_filename = "#{recording_dir}/metadata.xml"
doc = Nokogiri::XML(File.open(xml_filename)) { |x| x.noblanks }
return if ! doc.xpath("/recording/meeting").empty?
node = Nokogiri::XML::Node.new "meeting", doc
node["id"] = doc.at_xpath("/recording/id").text || ""
node["externalId"] = doc.at_xpath("/recording/meta/meetingId").text || ""
node["name"] = doc.at_xpath("/recording/meta/meetingName").text || ""
node["breakout"] = "false"
doc.at("/recording") << node
xml_file = File.new(xml_filename, "w")
xml_file.write(doc.to_xml(:indent => 2))
xml_file.close
end
BigBlueButton.logger.info("Updating meeting tag for 1.1.0")
puts "Updating meeting tag for 1.1.0..."
num_recordings = 0
BigBlueButton.logger.info("Checking recordings in #{published_dir}")
Dir.glob("#{published_dir}/*").each do |format_dir|
Dir.glob("#{format_dir}/*-*").each do |recording_dir|
print '.' if num_recordings % 10 == 0
num_recordings += 1
do_update(recording_dir, format_dir)
end
end
BigBlueButton.logger.info("Checking recordings in #{unpublished_dir}")
Dir.glob("#{unpublished_dir}/*").each do |format_dir|
Dir.glob("#{format_dir}/*-*").each do |recording_dir|
print '.' if num_recordings % 10 == 0
num_recordings += 1
do_update(recording_dir, format_dir)
end
end
puts "done"
puts "See the output in #{log_file} for details"
BigBlueButton.logger.info("Processed #{num_recordings} recordings")
IO.write(done_file, Time.now)

View File

@ -0,0 +1,93 @@
#!/usr/bin/ruby
# encoding: UTF-8
#
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
#
# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3.0 of the License, or (at your option)
# any later version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
#
require "trollop"
require 'net/http'
require "jwt"
require "java_properties"
require File.expand_path('../../../lib/recordandplayback', __FILE__)
logger = Logger.new("/var/log/bigbluebutton/post_publish.log", 'weekly' )
logger.level = Logger::INFO
BigBlueButton.logger = logger
opts = Trollop::options do
opt :meeting_id, "Meeting id to archive", :type => String
end
meeting_id = opts[:meeting_id]
processed_files = "/var/bigbluebutton/recording/process/presentation/#{meeting_id}"
meeting_metadata = BigBlueButton::Events.get_meeting_metadata("/var/bigbluebutton/recording/raw/#{meeting_id}/events.xml")
#
# Main code
#
BigBlueButton.logger.info("Recording Ready Notify for [#{meeting_id}] starts")
begin
callback_url = meeting_metadata.key?("bbb-recording-ready-url") ? meeting_metadata["bbb-recording-ready-url"].value : nil
# For compatibility with some 3rd party implementations, look up for bn-recording-ready-url or canvas-recording-ready, when bbb-recording-ready is not included.
callback_url ||= meeting_metadata.key?("bn-recording-ready-url") ? meeting_metadata["bn-recording-ready-url"].value : nil
callback_url ||= meeting_metadata.key?("canvas-recording-ready-url") ? meeting_metadata["canvas-recording-ready-url"].value : nil
unless callback_url.nil?
BigBlueButton.logger.info("Making callback for recording ready notification")
props = JavaProperties::Properties.new("/var/lib/tomcat7/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties")
secret = props[:securitySalt]
external_meeting_id = meeting_metadata["meetingId"].value
payload = { meeting_id: external_meeting_id, record_id: meeting_id }
payload_encoded = JWT.encode(payload, secret)
uri = URI.parse(callback_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
BigBlueButton.logger.info("Sending request to #{uri.scheme}://#{uri.host}#{uri.request_uri}")
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({ signed_parameters: payload_encoded })
response = http.request(request)
code = response.code.to_i
if code == 410
BigBlueButton.logger.info("Notified for deleted meeting: #{meeting_id}")
# TODO: should we automatically delete the recording here?
elsif code == 404
BigBlueButton.logger.info("404 error when notifying for recording: #{meeting_id}, ignoring")
elsif code < 200 || code >= 300
BigBlueButton.logger.info("Callback HTTP request failed: #{response.code} #{response.message} (code #{code})")
else
BigBlueButton.logger.info("Recording notifier successful: #{meeting_id} (code #{code})")
end
end
rescue => e
BigBlueButton.logger.info("Rescued")
BigBlueButton.logger.info(e.to_s)
end
BigBlueButton.logger.info("Recording Ready notify ends")
exit 0