Merge remote-tracking branch 'upstream/master' into dropdown

This commit is contained in:
Jaeeun Cho 2016-08-24 08:13:44 -07:00
commit a838926485
50 changed files with 244 additions and 202 deletions

View File

@ -3,3 +3,14 @@ app/build/
npm-debug.log
node_modules/
.meteor/dev_bundle
private/config/server/*
!private/config/server/redis.yaml
!private/config/server/shell.yaml
private/config/development/server/*
!private/config/development/server/log.yaml
private/config/production/server/*
!private/config/production/server/log.yaml
!private/config/production/server/shell.yaml

3
bigbluebutton-html5/.meteor/packages Normal file → Executable file
View File

@ -3,14 +3,13 @@
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
4commerce:env-settings
standard-app-packages@1.0.9
arunoda:npm@0.2.6
amplify
blaze@2.1.8
francocatena:status
mrt:external-file-loader@0.1.4
brentjanderson:winston-client@0.0.4
duongthienduc:meteor-winston
mizzao:timesync
clinical:nightwatch
cfs:power-queue

View File

@ -1,3 +1,4 @@
4commerce:env-settings@1.2.0
aldeed:simple-schema@1.5.3
allow-deny@1.0.5
amplify@1.0.0
@ -10,7 +11,6 @@ binary-heap@1.0.9
blaze@2.1.8
blaze-tools@1.0.9
boilerplate-generator@1.0.9
brentjanderson:winston-client@0.2.1
caching-compiler@1.1.7
caching-html-compiler@1.0.6
callback-hook@1.0.9
@ -28,7 +28,6 @@ ddp-common@1.2.6
ddp-server@1.3.10
deps@1.0.12
diff-sequence@1.0.6
duongthienduc:meteor-winston@1.0.0
ecmascript@0.5.8
ecmascript-runtime@0.3.14
ejson@1.0.12
@ -39,7 +38,6 @@ html-tools@1.0.10
htmljs@1.0.10
http@1.2.9
id-map@1.0.8
infinitedg:winston@0.7.3
jquery@1.11.9
launch-screen@1.0.12
livedata@1.0.18
@ -47,6 +45,7 @@ logging@1.1.15
mdg:validation-error@0.5.1
meteor@1.2.17
meteor-platform@1.2.6
meteorblackbelt:underscore-deep@0.0.4
meteorspark:util@0.2.0
minifier-css@1.2.14
minifier-js@1.2.14
@ -58,6 +57,7 @@ modules-runtime@0.7.6
mongo@1.1.11
mongo-id@1.0.5
mrt:external-file-loader@0.1.4
mrt:redis@0.1.3
nathantreid:css-modules@2.2.2
nathantreid:css-modules-import-path-helpers@0.1.4
npm-mongo@1.5.46
@ -85,6 +85,7 @@ templating@1.2.14
templating-tools@1.0.4
tmeasday:check-npm-versions@0.3.1
tracker@1.1.0
udondan:yml@3.2.2_1
ui@1.0.11
underscore@1.0.9
url@1.0.10

View File

@ -6,26 +6,23 @@ module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
// importing the Meteor settings:
var SETTINGS_DEV = require('./settings-development.json');
var SETTINGS_PROD = require('./settings-production.json');
var SHELL_CONFIG = require('./private/config/server/shell.yaml');
var PROD_SHELL_CONFIG = require('./private/config/production/server/shell.yaml');
// root URL in development/production:
var devRootURL = (SETTINGS_DEV.rootURL == undefined)
var rootURL = (SHELL_CONFIG.shell.rootURL == undefined)
? 'http://127.0.0.1/html5client'
: SETTINGS_DEV.rootURL;
var prodRootURL = (SETTINGS_PROD.rootURL == undefined)
? 'http://127.0.0.1/html5client'
: SETTINGS_PROD.rootURL;
: SHELL_CONFIG.shell.rootURL;
// command line string containing the Meteor's home directory in development/production:
var devHomeStr = (SETTINGS_DEV.home == undefined) ? '' : ('HOME=' + SETTINGS_DEV.home + ' ');
var prodHomeStr = (SETTINGS_PROD.home == undefined) ? '' : ('HOME=' + SETTINGS_PROD.home + ' ');
// command line string containing the Meteor's home directory in production:
var prodHomeStr = (PROD_SHELL_CONFIG.shell.home == undefined) ? ''
: ('HOME=' + PROD_SHELL_CONFIG.shell.home + ' ');
// final commands:
var METEOR_DEV_COMMAND = devHomeStr + 'ROOT_URL=' +
devRootURL + ' meteor --settings settings-development.json';
var METEOR_DEV_COMMAND = 'ROOT_URL=' +
rootURL + ' NODE_ENV=development' + ' meteor';
var METEOR_PROD_COMMAND = prodHomeStr + 'ROOT_URL=' +
prodRootURL + ' meteor --settings settings-production.json';
rootURL + ' NODE_ENV=production' + ' meteor';
// configure Grunt
grunt.initConfig({
@ -66,7 +63,7 @@ module.exports = function (grunt) {
command: METEOR_DEV_COMMAND,
},
start_meteor_production: {
command: METEOR_DEV_COMMAND,
command: METEOR_PROD_COMMAND,
},
},

View File

@ -1,85 +0,0 @@
// TODO: should be split on server and client side
// // Global configurations file
let clientConfig = {};
// Default global variables
clientConfig.appName = 'BigBlueButton HTML5 Client';
clientConfig.bbbServerVersion = '1.0-beta';
clientConfig.copyrightYear = '2015';
clientConfig.html5ClientBuild = 'NNNN';
clientConfig.defaultWelcomeMessage =
'Welcome to %%CONFNAME%%!\r\rFor help on using BigBlueButton see ' +
'these (short) <a href="event:http://www.bigbluebutton.org/content/videos"><u>tutorial ' +
'videos</u></a>.\r\rTo join the audio bridge click the gear icon (upper-right hand corner). ' +
' Use a headset to avoid causing background noise for others.\r\r\r';
const tempString = 'This server is running a build of ' +
"<a href='http://docs.bigbluebutton.org/1.0/10overview.html' target='_blank'><u>BigBlueButton";
clientConfig.defaultWelcomeMessageFooter = `${tempString} ` +
`${clientConfig.bbbServerVersion}</u></a>.`;
clientConfig.maxUsernameLength = 30;
clientConfig.maxChatLength = 140;
clientConfig.lockOnJoin = true;
//// Application configurations
clientConfig.app = {};
//default font sizes for mobile / desktop
clientConfig.app.mobileFont = 16;
clientConfig.app.desktopFont = 14;
// Will offer the user to join the audio when entering the meeting
clientConfig.app.autoJoinAudio = false;
clientConfig.app.listenOnly = false;
clientConfig.app.skipCheck = false;
// Flag for HTTPS. True by default
clientConfig.app.httpsConnection = true;
// The amount of time the client will wait before making another call to
// successfully hangup the WebRTC conference call
clientConfig.media = {};
clientConfig.media.WebRTCHangupRetryInterval = 2000;
// specifies whether to use SIP.js for audio over mod_verto
clientConfig.media.useSIPAudio = true;
// Configs for redis
const redisConfig = {
host: '127.0.0.1',
post: '6379',
timeout: 5000,
channels: {
fromBBBApps: 'bigbluebutton:from-bbb-apps:*',
toBBBApps: {
pattern: 'bigbluebutton:to-bbb-apps:*',
chat: 'bigbluebutton:to-bbb-apps:chat',
captions: 'bigbluebutton:to-bbb-apps:caption',
meeting: 'bigbluebutton:to-bbb-apps:meeting',
presentation: 'bigbluebutton:to-bbb-apps:presentation',
users: 'bigbluebutton:to-bbb-apps:users',
voice: 'bigbluebutton:to-bbb-apps:voice',
whiteboard: 'bigbluebutton:to-bbb-apps:whiteboard',
polling: 'bigbluebutton:to-bbb-apps:polling',
},
},
};
export { clientConfig, redisConfig };

View File

@ -3,7 +3,6 @@ import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import { translateHTML5ToFlash } from '/imports/api/common/server/helpers';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
import RegexWebUrl from '/imports/utils/regex-weburl';
@ -37,6 +36,8 @@ Meteor.methods({
// requesterUserId: the userId of the user sending chat
// requesterToken: the authToken of the requester
sendChatMessagetoServer(credentials, chatObject) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
let message;
@ -70,7 +71,7 @@ Meteor.methods({
};
message = appendMessageHeader(eventName, message);
logger.info('publishing chat to redis');
publish(redisConfig.channels.toBBBApps.chat, message);
publish(REDIS_CONFIG.channels.toBBBApps.chat, message);
}
},
});

View File

@ -1,13 +1,12 @@
import Chat from '/imports/api/chat';
import { logger } from '/imports/startup/server/logger';
const BREAK_TAG = '<br/>';
import { BREAK_LINE } from '/imports/utils/lineEndings.js';
const parseMessage = (message) => {
message = message || '';
// Replace \r and \n to <br/>
message = message.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + BREAK_TAG + '$2');
message = message.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + BREAK_LINE + '$2');
// Replace flash links to html valid ones
message = message.split(`<a href='event:`).join(`<a target="_blank" href='`);

View File

@ -12,6 +12,7 @@ import { clearCaptionsCollection }
from '/imports/api/captions/server/modifiers/clearCaptionsCollection';
import { logger } from '/imports/startup/server/logger';
import { redisPubSub } from '/imports/startup/server';
import { BREAK_LINE, CARRIAGE_RETURN, NEW_LINE } from '/imports/utils/lineEndings.js';
export function appendMessageHeader(eventName, messageObj) {
let header;

View File

@ -1,10 +1,11 @@
import { initializeCursor } from '/imports/api/cursor/server/modifiers/initializeCursor';
import Meetings from '/imports/api/meetings';
import { logger } from '/imports/startup/server/logger';
import {clientConfig} from '/config';
export function addMeetingToCollection(meetingId, name, intendedForRecording,
voiceConf, duration, callback) {
const APP_CONFIG = Meteor.settings.public.app;
//check if the meeting is already in the collection
Meetings.upsert({
meetingId: meetingId,
@ -20,7 +21,7 @@ export function addMeetingToCollection(meetingId, name, intendedForRecording,
disablePrivateChat: false,
disableCam: false,
disableMic: false,
lockOnJoin: clientConfig.lockOnJoin,
lockOnJoin: APP_CONFIG.lockOnJoin,
lockedLayout: false,
disablePublicChat: false,
lockOnJoinConfigurable: false, // TODO

View File

@ -2,9 +2,11 @@ import Users from '/imports/api/users';
import Meetings from '/imports/api/meetings';
import Auth from '/imports/ui/services/auth';
import {callServer} from '/imports/ui/services/api';
import {clientConfig} from '/config';
import {vertoExitAudio, vertoJoinListenOnly, vertoJoinMicrophone} from '/imports/api/verto';
const APP_CONFIG = Meteor.settings.public.app;
const MEDIA_CONFIG = Meteor.settings.public.media;
let triedHangup = false;
function getVoiceBridge() {
@ -18,8 +20,9 @@ function amIListenOnly() {
// Periodically check the status of the WebRTC call, when a call has been established attempt to
// hangup, retry if a call is in progress, send the leave voice conference message to BBB
function exitAudio(afterExitCall) {
if (!clientConfig.media.useSIPAudio) {
if (!MEDIA_CONFIG.useSIPAudio) {
vertoExitAudio();
return;
} else {
@ -52,14 +55,14 @@ function exitAudio(afterExitCall) {
triedHangup = true;
if (afterExitCall) {
afterExitCall(this, clientConfig.app.listenOnly);
afterExitCall(this, APP_CONFIG.listenOnly);
}
} else {
console.log('RETRYING hangup on WebRTC call in ' +
`${clientConfig.media.WebRTCHangupRetryInterval} ms`);
`${MEDIA_CONFIG.WebRTCHangupRetryInterval} ms`);
// try again periodically
setTimeout(checkToHangupCall, clientConfig.media.WebRTCHangupRetryInterval);
setTimeout(checkToHangupCall, MEDIA_CONFIG.WebRTCHangupRetryInterval);
}
})
@ -74,7 +77,7 @@ function exitAudio(afterExitCall) {
function joinVoiceCallSIP(options) {
const extension = getVoiceBridge();
console.log(options);
if (clientConfig.media.useSIPAudio) {
if (MEDIA_CONFIG.useSIPAudio) {
// create voice call params
const joinCallback = function (message) {
@ -104,7 +107,7 @@ function joinVoiceCallSIP(options) {
function joinListenOnly() {
callServer('listenOnlyRequestToggle', true);
if (clientConfig.media.useSIPAudio) {
if (MEDIA_CONFIG.useSIPAudio) {
joinVoiceCallSIP({ isListenOnly: true });
} else {
vertoJoinListenOnly();
@ -112,7 +115,7 @@ function joinListenOnly() {
}
function joinMicrophone() {
if (clientConfig.media.useSIPAudio) {
if (MEDIA_CONFIG.useSIPAudio) {
joinVoiceCallSIP({ isListenOnly: false });
} else {
vertoJoinMicrophone();

View File

@ -3,10 +3,10 @@ import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import Polls from '/imports/api/polls';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
Meteor.methods({
publishVoteMessage(credentials, pollId, pollAnswerId) { //TODO discuss location
const REDIS_CONFIG = Meteor.settings.redis;
if (isAllowedTo('subscribePoll', credentials)) {
const { meetingId, requesterUserId, requesterToken } = credentials;
const eventName = 'vote_poll_user_request_message';
@ -42,7 +42,7 @@ Meteor.methods({
});
message = appendMessageHeader(eventName, message);
logger.info('publishing Poll response to redis');
return publish(redisConfig.channels.toBBBApps.polling, message);
return publish(REDIS_CONFIG.channels.toBBBApps.polling, message);
}
}
},

View File

@ -3,10 +3,10 @@ import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import Presentations from '/imports/api/presentations';
import Slides from '/imports/api/slides';
import { redisConfig } from '/config';
Meteor.methods({
switchSlideMessage(credentials, requestedSlideNum) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
const currentPresentationDoc = Presentations.findOne({
@ -36,7 +36,7 @@ Meteor.methods({
};
message = appendMessageHeader('go_to_slide', message);
return publish(redisConfig.channels.toBBBApps.presentation, message);
return publish(REDIS_CONFIG.channels.toBBBApps.presentation, message);
}
}
}

View File

@ -8,7 +8,6 @@ import { addSlideToCollection } from '/imports/api/slides/server/modifiers/addSl
import Slides from '/imports/api/slides';
import Presentations from '/imports/api/presentations';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
eventEmitter.on('presentation_page_resized_message', function (arg) {
const payload = arg.payload;
@ -106,6 +105,8 @@ eventEmitter.on('presentation_shared_message', function (arg) {
});
eventEmitter.on('get_presentation_info_reply', function (arg) {
const REDIS_CONFIG = Meteor.settings.redis;
if (inReplyToHTML5Client(arg)) {
const payload = arg.payload;
const meetingId = payload.meeting_id;
@ -136,7 +137,7 @@ eventEmitter.on('get_presentation_info_reply', function (arg) {
};
if (!!whiteboardId && !!meetingId) {
message = appendMessageHeader('request_whiteboard_annotation_history_request', message);
publish(redisConfig.channels.toBBBApps.whiteboard, message);
publish(REDIS_CONFIG.channels.toBBBApps.whiteboard, message);
} else {
logger.info('did not have enough information to send a user_leaving_request');
}
@ -146,4 +147,3 @@ eventEmitter.on('get_presentation_info_reply', function (arg) {
return arg.callback();
});

View File

@ -1,8 +1,8 @@
import sizeOf from 'image-size';
import Slides from '/imports/api/slides';
import { clientConfig } from '/config';
export function addSlideToCollection(meetingId, presentationId, slideObject) {
const APP_CONFIG = Meteor.settings.public.app;
const url = Npm.require('url');
const imageUri = slideObject.svg_uri != null ? slideObject.svg_uri : slideObject.png_uri;
@ -50,7 +50,7 @@ export function addSlideToCollection(meetingId, presentationId, slideObject) {
};
// HTTPS connection
if (clientConfig.app.httpsConnection) {
if (APP_CONFIG.httpsConnection) {
const https = Npm.require('https');
https.get(options, Meteor.bindEnvironment(function (response) {

View File

@ -1,6 +1,5 @@
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader, publish } from '/imports/api/common/server/helpers';
import { redisConfig } from '/config';
Meteor.methods({
//meetingId: the meeting where the user is
@ -8,6 +7,7 @@ Meteor.methods({
//requesterUserId: the userid of the user that wants to kick
//authToken: the authToken of the user that wants to kick
kickUser(credentials, toKickUserId) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
let message;
if (isAllowedTo('kickUser', credentials)) {
@ -19,7 +19,7 @@ Meteor.methods({
},
};
message = appendMessageHeader('eject_user_from_meeting_request_message', message);
return publish(redisConfig.channels.toBBBApps.users, message);
return publish(REDIS_CONFIG.channels.toBBBApps.users, message);
}
},
});

View File

@ -3,7 +3,6 @@ import { appendMessageHeader, publish } from '/imports/api/common/server/helpers
import Meetings from '/imports/api/meetings';
import Users from '/imports/api/users';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
Meteor.methods({
// meetingId: the meetingId of the meeting the user is in
@ -11,6 +10,7 @@ Meteor.methods({
// requesterUserId: the userId of the requester
// requesterToken: the authToken of the requester
listenOnlyRequestToggle(credentials, isJoining) {
const REDIS_CONFIG = Meteor.settings.redis;
let username;
let voiceConf;
const { meetingId, requesterUserId, requesterToken } = credentials;
@ -45,7 +45,7 @@ Meteor.methods({
`publishing a user listenOnly toggleRequest ${isJoining} ` +
`request for ${requesterUserId}`
);
publish(redisConfig.channels.toBBBApps.meeting, message);
publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
}
} else {
if (isAllowedTo('leaveListenOnly', credentials)) {
@ -62,7 +62,7 @@ Meteor.methods({
`publishing a user listenOnly toggleRequest ${isJoining} ` +
`request for ${requesterUserId}`
);
publish(redisConfig.channels.toBBBApps.meeting, message);
publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
}
}
},

View File

@ -3,7 +3,6 @@ import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import { updateVoiceUser } from '/imports/api/users/server/modifiers/updateVoiceUser';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
Meteor.methods({
// meetingId: the meetingId of the meeting the user[s] is in
@ -11,6 +10,7 @@ Meteor.methods({
// requesterUserId: the userId of the requester
// requesterToken: the authToken of the requester
muteUser(credentials, toMuteUserId) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
const action = function () {
if (toMuteUserId === requesterUserId) {
@ -31,7 +31,7 @@ Meteor.methods({
};
message = appendMessageHeader('mute_user_request_message', message);
logger.info(`publishing a user mute request for ${toMuteUserId}`);
publish(redisConfig.channels.toBBBApps.users, message);
publish(REDIS_CONFIG.channels.toBBBApps.users, message);
updateVoiceUser(meetingId, {
web_userid: toMuteUserId,
talking: false,

View File

@ -1,7 +1,6 @@
import { publish } from '/imports/api/common/server/helpers';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import { redisConfig } from '/config';
Meteor.methods({
//meetingId: the meeting where the user is
@ -13,6 +12,7 @@ Meteor.methods({
credentials,
newPresenterId,
newPresenterName) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterSetPresenter, requesterToken } = credentials;
let message;
if (isAllowedTo('setPresenter', credentials)) {
@ -26,7 +26,7 @@ Meteor.methods({
};
message = appendMessageHeader('assign_presenter_request_message', message);
return publish(redisConfig.channels.toBBBApps.users, message);
return publish(REDIS_CONFIG.channels.toBBBApps.users, message);
}
},
});

View File

@ -3,7 +3,6 @@ import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import { updateVoiceUser } from '/imports/api/users/server/modifiers/updateVoiceUser';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
Meteor.methods({
// meetingId: the meetingId of the meeting the user[s] is in
@ -11,6 +10,7 @@ Meteor.methods({
// requesterUserId: the userId of the requester
// requesterToken: the authToken of the requester
unmuteUser(credentials, toMuteUserId) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
const action = function () {
if (toMuteUserId === requesterUserId) {
@ -31,7 +31,7 @@ Meteor.methods({
};
message = appendMessageHeader('mute_user_request_message', message);
logger.info(`publishing a user unmute request for ${toMuteUserId}`);
publish(redisConfig.channels.toBBBApps.users, message);
publish(REDIS_CONFIG.channels.toBBBApps.users, message);
updateVoiceUser(meetingId, {
web_userid: toMuteUserId,
talking: false,

View File

@ -1,10 +1,10 @@
import { publish } from '/imports/api/common/server/helpers';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { appendMessageHeader } from '/imports/api/common/server/helpers';
import { redisConfig } from '/config';
Meteor.methods({
userSetEmoji(credentials, toRaiseUserId, status) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
let message;
if (isAllowedTo('setEmojiStatus', credentials)) {
@ -19,7 +19,7 @@ Meteor.methods({
message = appendMessageHeader('user_emoji_status_message', message);
// publish to pubsub
publish(redisConfig.channels.toBBBApps.users, message);
publish(REDIS_CONFIG.channels.toBBBApps.users, message);
}
},
});

View File

@ -1,11 +1,11 @@
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
import { createDummyUser } from '/imports/api/users/server/modifiers/createDummyUser';
import { publish } from '/imports/api/common/server/helpers';
Meteor.methods({
// Construct and send a message to bbb-web to validate the user
validateAuthToken(credentials) {
const REDIS_CONFIG = Meteor.settings.redis;
const { meetingId, requesterUserId, requesterToken } = credentials;
logger.info('sending a validate_auth_token with', {
userid: requesterUserId,
@ -26,7 +26,7 @@ Meteor.methods({
};
if ((requesterToken != null) && (requesterUserId != null) && (meetingId != null)) {
createDummyUser(meetingId, requesterUserId, requesterToken);
return publish(redisConfig.channels.toBBBApps.meeting, message);
return publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
} else {
return logger.info('did not have enough information to send a validate_auth_token message');
}

View File

@ -2,12 +2,12 @@ import { publish } from '/imports/api/common/server/helpers';
import Meetings from '/imports/api/meetings';
import Users from '/imports/api/users';
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
// Corresponds to a valid action on the HTML clientside
// After authorization, publish a user_leaving_request in redis
// params: meetingid, userid as defined in BBB-App
export function requestUserLeaving(meetingId, userId) {
const REDIS_CONFIG = Meteor.settings.redis;
let voiceConf;
const userObject = Users.findOne({
meetingId: meetingId,
@ -41,7 +41,7 @@ export function requestUserLeaving(meetingId, userId) {
name: 'user_disconnected_from_global_audio',
},
};
publish(redisConfig.channels.toBBBApps.meeting, listenOnlyMessage);
publish(REDIS_CONFIG.channels.toBBBApps.meeting, listenOnlyMessage);
}
// remove user from meeting
@ -56,7 +56,7 @@ export function requestUserLeaving(meetingId, userId) {
},
};
logger.info(`sending a user_leaving_request for ${meetingId}:${userId}`);
return publish(redisConfig.channels.toBBBApps.users, message);
return publish(REDIS_CONFIG.channels.toBBBApps.users, message);
} else {
return logger.info('did not have enough information to send a user_leaving_request');
}

View File

@ -2,15 +2,13 @@ import Chat from '/imports/api/chat';
import Users from '/imports/api/users';
import Meetings from '/imports/api/meetings';
import { logger } from '/imports/startup/server/logger';
import { clientConfig } from '/config';
const BREAK_TAG = '<br/>';
import { BREAK_LINE } from '/imports/utils/lineEndings.js';
const parseMessage = (message) => {
message = message || '';
// Replace \r and \n to <br/>
message = message.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + BREAK_TAG + '$2');
message = message.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + BREAK_LINE + '$2');
// Replace flash links to html valid ones
message = message.split(`<a href='event:`).join(`<a target="_blank" href='`);
@ -20,6 +18,7 @@ const parseMessage = (message) => {
};
export function userJoined(meetingId, user, callback) {
const APP_CONFIG = Meteor.settings.public.app;
let welcomeMessage;
const userId = user.userid;
const userObject = Users.findOne({
@ -87,11 +86,11 @@ export function userJoined(meetingId, user, callback) {
meetingId: meetingId,
});
if (meetingObject != null) {
welcomeMessage = clientConfig.defaultWelcomeMessage.replace(/%%CONFNAME%%/,
welcomeMessage = APP_CONFIG.defaultWelcomeMessage.replace(/%%CONFNAME%%/,
meetingObject.meetingName);
}
welcomeMessage = welcomeMessage + clientConfig.defaultWelcomeMessageFooter;
welcomeMessage = welcomeMessage + APP_CONFIG.defaultWelcomeMessageFooter;
// add the welcome message if it's not there already OR update time_of_joining
return Chat.upsert({

View File

@ -1,7 +1,6 @@
import {getInStorage} from '/imports/ui/components/app/service';
import Users from '/imports/api/users';
import Auth from '/imports/ui/services/auth';
import { clientConfig } from '/config';
import { getVoiceBridge } from '/imports/api/phone';
function createVertoUserName() {

View File

@ -10,7 +10,8 @@ import ChatContainer from '/imports/ui/components/chat/container';
import UserListContainer from '/imports/ui/components/user-list/container';
const browserHistory = useRouterHistory(createHistory)({
basename: '/html5client',
// Name displayed in the brower URL
basename: Meteor.settings.public.app.basename,
});
export const renderRoutes = () => (

View File

@ -98,7 +98,7 @@ const logRedisMessage = function (eventName, json) {
// For DEVELOPMENT purposes only
// Dynamic shapes' updates will slow down significantly
if (Meteor.settings.public.mode == 'development') {
if (Meteor.settings.runtime.env == 'development') {
logger.info(`redis incoming message ${eventName} `, {
message: json,
});

View File

@ -1,21 +1,24 @@
import { logger } from '/imports/startup/server/logger';
import { redisConfig } from '/config';
import { myQueue } from '/imports/startup/server';
import { indexOf, publish } from '/imports/api/common/server/helpers';
import redis from 'redis';
export class RedisPubSub {
constructor() {
const REDIS_CONFIG = Meteor.settings.redis;
logger.info('constructor RedisPubSub');
this.pubClient = redis.createClient();
this.subClient = redis.createClient();
logger.info(`Subscribing message on channel: ${redisConfig.channels.fromBBBApps}`);
logger.info(`Subscribing message on channel: ${REDIS_CONFIG.channels.fromBBBApps}`);
this.subClient.on('psubscribe', Meteor.bindEnvironment(this._onSubscribe));
this.subClient.on('pmessage', Meteor.bindEnvironment(this._addToQueue));
this.subClient.psubscribe(redisConfig.channels.fromBBBApps);
this.subClient.psubscribe(REDIS_CONFIG.channels.fromBBBApps);
}
_onSubscribe(channel, count) {
const REDIS_CONFIG = Meteor.settings.redis;
let message;
logger.info(`Subscribed to ${channel}`);
@ -26,7 +29,7 @@ export class RedisPubSub {
},
payload: {}, // I need this, otherwise bbb-apps won't recognize the message
};
return publish(redisConfig.channels.toBBBApps.meeting, message);
return publish(REDIS_CONFIG.channels.toBBBApps.meeting, message);
}
_addToQueue(pattern, channel, jsonMsg) {
@ -41,7 +44,7 @@ export class RedisPubSub {
// For DEVELOPMENT purposes only
// Dynamic shapes' updates will slow down significantly
if (Meteor.settings.public.mode == 'development') {
if (Meteor.settings.runtime.env == 'development') {
logger.info(`Q ${eventName} ${myQueue.total()}`);
}

View File

@ -3,13 +3,16 @@ import '/server/server';
import { RedisPubSub } from '/imports/startup/server/RedisPubSub';
import { EventQueue } from '/imports/startup/server/EventQueue';
import { clearCollections } from '/imports/api/common/server/helpers';
import { clientConfig } from '/config';
Meteor.startup(function () {
redisPubSub = new RedisPubSub();
clearCollections();
const APP_CONFIG = Meteor.settings.public.app;
let determineConnectionType = function () {
let baseConnection = 'HTTP';
if (clientConfig.app.httpsConnection) {
if (APP_CONFIG.httpsConnection) {
baseConnection += ('S');
}
@ -31,4 +34,4 @@ export const myQueue = new EventQueue();
export const eventEmitter = new (Npm.require('events').EventEmitter);
export const redisPubSub = new RedisPubSub();
export let redisPubSub = {};

44
bigbluebutton-html5/imports/startup/server/logger.js Normal file → Executable file
View File

@ -1,15 +1,33 @@
// Setting up a logger
const log = {};
if (process != null && process.env != null && process.env.NODE_ENV == 'production') {
log.path = '/var/log/bigbluebutton/html5/html5client.log';
} else {
log.path = `${process.env.PWD}/log/development.log`;
}
import { Meteor } from 'meteor/meteor';
import Winston from 'winston';
export let logger = new Winston.Logger({
transports: [
new Winston.transports.Console(), new Winston.transports.File({
filename: log.path,
}),
],
let Logger = new Winston.Logger();
// Write logs to console
Logger.add(Winston.transports.Console, {
prettyPrint: true,
humanReadableUnhandledException: true,
colorize: true,
});
Meteor.startup(() => {
const LOG_CONFIG = Meteor.settings.log || {};
let filename = LOG_CONFIG.filename;
// Determine file to write logs to
if (filename) {
if (Meteor.settings.runtime.env === 'development') {
const path = Npm.require('path');
filename = path.join(process.env.PWD, filename);
}
Logger.add(Winston.transports.File, {
filename: filename,
prettyPrint: true,
});
}
});
export default Logger;
export let logger = Logger;

View File

@ -2,7 +2,8 @@ import React, { Component, PropTypes } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import { createContainer } from 'meteor/react-meteor-data';
const PUBLIC_CHAT_KEY = 'public';
const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_KEY = CHAT_CONFIG.public_id;
import Chat from './component';
import ChatService from './service';

View File

@ -7,15 +7,16 @@ import UnreadMessages from '/imports/ui/services/unread-messages';
import { callServer } from '/imports/ui/services/api';
const GROUPING_MESSAGES_WINDOW = 60000;
const CHAT_CONFIG = Meteor.settings.public.chat;
const GROUPING_MESSAGES_WINDOW = CHAT_CONFIG.grouping_messages_window;
const SYSTEM_CHAT_TYPE = 'SYSTEM_MESSAGE';
const PUBLIC_CHAT_TYPE = 'PUBLIC_CHAT';
const PRIVATE_CHAT_TYPE = 'PRIVATE_CHAT';
const SYSTEM_CHAT_TYPE = CHAT_CONFIG.type_system;
const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
const PRIVATE_CHAT_TYPE = CHAT_CONFIG.type_private;
const PUBLIC_CHAT_ID = 'public';
const PUBLIC_CHAT_USERID = 'public_chat_userid';
const PUBLIC_CHAT_USERNAME = 'public_chat_username';
const PUBLIC_CHAT_ID = CHAT_CONFIG.public_id;
const PUBLIC_CHAT_USERID = CHAT_CONFIG.public_userid;
const PUBLIC_CHAT_USERNAME = CHAT_CONFIG.public_username;
const ScrollCollection = new Mongo.Collection(null);

View File

@ -6,7 +6,8 @@ import { withRouter } from 'react-router';
import { Link } from 'react-router';
import cx from 'classnames';
const PRIVATE_CHAT_PATH = 'users/chat/';
const CHAT_CONFIG = Meteor.settings.public.chat;
const PRIVATE_CHAT_PATH = CHAT_CONFIG.path_route;
const propTypes = {
chat: React.PropTypes.shape({

View File

@ -5,9 +5,11 @@ import UnreadMessages from '/imports/ui/services/unread-messages';
import { callServer } from '/imports/ui/services/api';
const ROLE_MODERATOR = 'MODERATOR';
const CHAT_CONFIG = Meteor.settings.public.chat;
const USER_CONFIG = Meteor.settings.public.user;
const ROLE_MODERATOR = USER_CONFIG.role_moderator;
const EMOJI_STATUSES = ['raiseHand', 'happy', 'smile', 'neutral', 'sad', 'confused', 'away'];
const PRIVATE_CHAT_TYPE = 'PRIVATE_CHAT';
const PRIVATE_CHAT_TYPE = CHAT_CONFIG.type_private;
/* TODO: Same map is done in the chat/service we should share this someway */

View File

@ -4,8 +4,9 @@ import Storage from '/imports/ui/services/storage/session';
import Auth from '/imports/ui/services/auth';
import Chats from '/imports/api/chat';
const PUBLIC_CHAT_USERID = 'public_chat_userid';
const STORAGE_KEY = 'UNREAD_CHATS';
const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_USERID = CHAT_CONFIG.public_userid;
const STORAGE_KEY = CHAT_CONFIG.storage_key;
class UnreadMessagesTracker {
constructor() {

View File

@ -0,0 +1,11 @@
// Used in Flash and HTML to show a legitimate break in the line
const BREAK_LINE = '<br/>';
// Soft return in HTML to signify a broken line without
// displaying the escaped '<br/>' line break text
const CARRIAGE_RETURN = '\r';
// Handle this the same as carriage return, in case text copied has this
const NEW_LINE = '\n';
export { BREAK_LINE, CARRIAGE_RETURN, NEW_LINE };

View File

@ -23,6 +23,7 @@
"react-dom": "~15.3.1",
"react-intl": "~2.1.3",
"react-modal": "~1.4.0",
"winston": "^2.2.0",
"react-router": "~2.7.0",
"redis": "^2.6.2",
"underscore": "~1.8.3"

View File

@ -0,0 +1,4 @@
# Application configurations
app:
# Flag for HTTPS.
httpsConnection: false

View File

@ -0,0 +1,2 @@
log:
filename: '/log/development.log'

View File

@ -0,0 +1,4 @@
# Application configurations
app:
# Flag for HTTPS.
httpsConnection: true

View File

@ -0,0 +1,2 @@
log:
filename: '/var/log/bigbluebutton/html5/html5client.log'

View File

@ -0,0 +1,2 @@
shell:
home: "/usr/share/meteor"

View File

@ -0,0 +1,25 @@
# Application configurations
app:
# Default font sizes for mobile / desktop
mobileFont: 16
desktopFont: 14
# Will offer the user to join the audio when entering the meeting
autoJoinAudio: false
listenOnly: false
skipCheck: false
# Flag for HTTPS - true on production
httpsConnection: false
# Default global variables
appName: "BigBlueButton HTML5 Client"
bbbServerVersion: "1.0"
copyrightYear: "2015"
html5ClientBuild: "NNNN"
defaultWelcomeMessage: Welcome to %%CONFNAME%%!\r\rFor help on using BigBlueButton see these (short) <a href="event:http://www.bigbluebutton.org/content/videos"><u>tutorial videos</u></a>.\r\rTo join the audio bridge click the gear icon (upper-right hand corner). Use a headset to avoid causing background noise for others.\r\r\r
lockOnJoin: true
defaultWelcomeMessageFooter: This server is running a build of <a href="http://docs.bigbluebutton.org/1.0/10overview.html" target="_blank"><u>BigBlueButton 1.0</u></a>.
# Name displayed in the brower URL
basename: '/html5client'

View File

@ -0,0 +1,15 @@
# Chat service configurations
chat:
grouping_messages_window: 60000
# Chat types
type_system: 'SYSTEM_MESSAGE'
type_public: 'PUBLIC_CHAT'
type_private: 'PRIVATE_CHAT'
# Chat ids and names
public_id: 'public'
public_userid: 'public_chat_userid'
public_username: 'public_chat_username'
# Keys
storage_key: 'UNREAD_CHATS'
# Chat paths
path_route: 'users/chat/'

View File

@ -0,0 +1,10 @@
# Media configurations
media:
WebRTCHangupRetryInterval: 2000
# IP address of FreeSWITCH server for use of mod_verto and WebRTC deshsharing
vertoServerAddress: "HOST"
# Allows a caller to access a FreeSWITCH dialplan
freeswitchProfilePassword: "1234" # TODO: Remove once Danny's submitted PULL
vertoPort: "8082"
# specifies whether to use SIP.js for audio over mod_verto
useSIPAudio: true

View File

@ -0,0 +1,2 @@
user:
role_moderator: 'MODERATOR'

View File

@ -0,0 +1,16 @@
redis:
host: '127.0.0.1'
post: '6379'
timeout: 5000
channels:
fromBBBApps: 'bigbluebutton:from-bbb-apps:*'
toBBBApps:
pattern: 'bigbluebutton:to-bbb-apps:*'
chat: 'bigbluebutton:to-bbb-apps:chat'
captions: 'bigbluebutton:to-bbb-apps:caption'
meeting: 'bigbluebutton:to-bbb-apps:meeting'
presentation: 'bigbluebutton:to-bbb-apps:presentation'
users: 'bigbluebutton:to-bbb-apps:users'
voice: 'bigbluebutton:to-bbb-apps:voice'
whiteboard: 'bigbluebutton:to-bbb-apps:whiteboard'
polling: 'bigbluebutton:to-bbb-apps:polling'

View File

@ -0,0 +1,2 @@
shell:
rootURL: "http://127.0.0.1/html5client"

View File

@ -1,6 +0,0 @@
{
"public": {
"mode": "development"
},
"rootURL": "http://127.0.0.1/html5client"
}

View File

@ -1,7 +0,0 @@
{
"public": {
"mode": "production"
},
"rootURL": "http://127.0.0.1/html5client",
"home": "/usr/share/meteor"
}

View File

@ -2,3 +2,5 @@
# the idea is that this way we prevent test runs (for whenever needed)
JASMINE_SERVER_UNIT=0 JASMINE_SERVER_INTEGRATION=0 JASMINE_CLIENT_INTEGRATION=0 JASMINE_BROWSER=PhantomJS JASMINE_MIRROR_PORT=3000 ROOT_URL=http://127.0.0.1/html5client meteor
# ROOT_URL_PATH_PREFIX=html5client meteor
# Change to start meteor in production or development mode
NODE_ENV=development