diff --git a/bigbluebutton-html5/client/main.jsx b/bigbluebutton-html5/client/main.jsx
index 6b95921e6e..d5fb86231b 100755
--- a/bigbluebutton-html5/client/main.jsx
+++ b/bigbluebutton-html5/client/main.jsx
@@ -6,6 +6,7 @@ import logger from '/imports/startup/client/logger';
import Base from '/imports/startup/client/base';
import JoinHandler from '/imports/ui/components/join-handler/component';
import AuthenticatedHandler from '/imports/ui/components/authenticated-handler/component';
+import Subscriptions from '/imports/ui/components/subscriptions/component';
Meteor.startup(() => {
// Logs all uncaught exceptions to the client logger
@@ -24,9 +25,11 @@ Meteor.startup(() => {
// TODO make this a Promise
render(
-
+
-
+
+
+
,
document.getElementById('app'),
diff --git a/bigbluebutton-html5/imports/startup/client/base.jsx b/bigbluebutton-html5/imports/startup/client/base.jsx
index 1f56ae90a9..ce40367f08 100755
--- a/bigbluebutton-html5/imports/startup/client/base.jsx
+++ b/bigbluebutton-html5/imports/startup/client/base.jsx
@@ -10,23 +10,15 @@ import Settings from '/imports/ui/services/settings';
import AudioManager from '/imports/ui/services/audio-manager';
import logger from '/imports/startup/client/logger';
import Users from '/imports/api/users';
-import Annotations from '/imports/api/annotations';
-import AnnotationsLocal from '/imports/ui/components/whiteboard/service';
-import GroupChat from '/imports/api/group-chat';
-import mapUser from '/imports/ui/services/user/mapUser';
import { Session } from 'meteor/session';
import IntlStartup from './intl';
import Meetings from '../../api/meetings';
import AppService from '/imports/ui/components/app/service';
-import AnnotationsTextService from '/imports/ui/components/whiteboard/annotations/text/service';
import Breakouts from '/imports/api/breakouts';
import AudioService from '/imports/ui/components/audio/service';
import { FormattedMessage } from 'react-intl';
import { notify } from '/imports/ui/services/notification';
-const CHAT_CONFIG = Meteor.settings.public.chat;
-const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
-const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
const HTML = document.getElementsByTagName('html')[0];
let breakoutNotified = false;
@@ -35,7 +27,7 @@ const propTypes = {
subscriptionsReady: PropTypes.bool,
locale: PropTypes.string,
approved: PropTypes.bool,
- meetingHasEnded: PropTypes.bool,
+ meetingHasEnded: PropTypes.bool.isRequired,
meetingExist: PropTypes.bool,
};
@@ -44,7 +36,6 @@ const defaultProps = {
approved: undefined,
meetingExist: false,
subscriptionsReady: false,
- meetingHasEnded: false,
};
const fullscreenChangedEvents = [
@@ -73,7 +64,6 @@ class Base extends Component {
loading: false,
meetingExisted: false,
};
-
this.updateLoadingState = this.updateLoadingState.bind(this);
}
@@ -120,7 +110,7 @@ class Base extends Component {
// In case the meeting delayed to load
if (!subscriptionsReady || !meetingExist) return;
- if (approved && loading) this.updateLoadingState(false);
+ if (approved && loading && subscriptionsReady) this.updateLoadingState(false);
if (prevProps.ejected || ejected) {
Session.set('codeError', '403');
@@ -167,12 +157,12 @@ class Base extends Component {
const codeError = Session.get('codeError');
const {
ejected,
- subscriptionsReady,
meetingExist,
meetingHasEnded,
+ meetingIsBreakout,
+ subscriptionsReady,
} = this.props;
- const meetingIsBreakout = AppService.meetingIsBreakout();
if ((loading || !subscriptionsReady) && !meetingHasEnded && meetingExist) {
return ({loading});
}
@@ -219,16 +209,10 @@ class Base extends Component {
Base.propTypes = propTypes;
Base.defaultProps = defaultProps;
-const SUBSCRIPTIONS_NAME = [
- 'users', 'meetings', 'polls', 'presentations',
- 'slides', 'captions', 'voiceUsers', 'whiteboard-multi-user', 'screenshare',
- 'group-chat', 'presentation-pods', 'users-settings', 'guestUser', 'users-infos',
-];
-
const BaseContainer = withTracker(() => {
const { locale, animations } = Settings.application;
const { credentials, loggedIn } = Auth;
- const { meetingId, requesterUserId } = credentials;
+ const { meetingId } = credentials;
let breakoutRoomSubscriptionHandler;
let meetingModeratorSubscriptionHandler;
@@ -253,66 +237,7 @@ const BaseContainer = withTracker(() => {
let userSubscriptionHandler;
- const subscriptionErrorHandler = {
- onError: (error) => {
- logger.error({ logCode: 'startup_client_subscription_error' }, error);
- Session.set('codeError', error.error);
- },
- };
-
- const subscriptionsHandlers = SUBSCRIPTIONS_NAME
- .map(name => Meteor.subscribe(name, credentials, subscriptionErrorHandler));
-
- const subscriptionsReady = subscriptionsHandlers.every(handler => handler.ready())
- && loggedIn;
-
- const chats = GroupChat.find({
- $or: [
- {
- meetingId,
- access: PUBLIC_CHAT_TYPE,
- chatId: { $ne: PUBLIC_GROUP_CHAT_ID },
- },
- { meetingId, users: { $all: [requesterUserId] } },
- ],
- }).fetch();
-
- const chatIds = chats.map(chat => chat.chatId);
-
- const groupChatMessageHandler = Meteor.subscribe('group-chat-msg', credentials, chatIds, subscriptionErrorHandler);
const User = Users.findOne({ intId: credentials.requesterUserId });
- let responseDelay;
- let inactivityCheck;
-
- if (User) {
- const {
- responseDelay: userResponseDelay,
- inactivityCheck: userInactivityCheck,
- } = User;
- responseDelay = userResponseDelay;
- inactivityCheck = userInactivityCheck;
- const mappedUser = mapUser(User);
- // override meteor subscription to verify if is moderator
- userSubscriptionHandler = Meteor.subscribe('users', credentials, mappedUser.isModerator, subscriptionErrorHandler);
- breakoutRoomSubscriptionHandler = Meteor.subscribe('breakouts', credentials, mappedUser.isModerator, subscriptionErrorHandler);
- meetingModeratorSubscriptionHandler = Meteor.subscribe('meetings', credentials, mappedUser.isModerator, subscriptionErrorHandler);
- }
-
- const annotationsHandler = Meteor.subscribe('annotations', credentials, {
- onReady: () => {
- const activeTextShapeId = AnnotationsTextService.activeTextShapeId();
- AnnotationsLocal.remove({ id: { $ne: `${activeTextShapeId}-fake` } });
- Annotations.find({ id: { $ne: activeTextShapeId } }, { reactive: false }).forEach((a) => {
- try {
- AnnotationsLocal.insert(a);
- } catch (e) {
- // TODO
- }
- });
- annotationsHandler.stop();
- },
- ...subscriptionErrorHandler,
- });
Breakouts.find().observeChanges({
added() {
@@ -367,19 +292,17 @@ const BaseContainer = withTracker(() => {
approved,
ejected,
locale,
- subscriptionsReady,
- annotationsHandler,
- groupChatMessageHandler,
userSubscriptionHandler,
breakoutRoomSubscriptionHandler,
meetingModeratorSubscriptionHandler,
animations,
- responseDelay,
- inactivityCheck,
User,
meteorIsConnected: Meteor.status().connected,
meetingExist: !!meeting,
meetingHasEnded: !!meeting && meeting.meetingEnded,
+ meetingIsBreakout: AppService.meetingIsBreakout(),
+ subscriptionsReady: Session.get('subscriptionsReady'),
+ loggedIn,
};
})(Base);
diff --git a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx
new file mode 100644
index 0000000000..16177391ef
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx
@@ -0,0 +1,96 @@
+import React, { Component } from 'react';
+import { withTracker } from 'meteor/react-meteor-data';
+import Auth from '/imports/ui/services/auth';
+import logger from '/imports/startup/client/logger';
+import GroupChat from '/imports/api/group-chat';
+import Users from '/imports/api/users';
+import Annotations from '/imports/api/annotations';
+import AnnotationsTextService from '/imports/ui/components/whiteboard/annotations/text/service';
+import AnnotationsLocal from '/imports/ui/components/whiteboard/service';
+import mapUser from '/imports/ui/services/user/mapUser';
+
+const CHAT_CONFIG = Meteor.settings.public.chat;
+const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
+const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
+const SUBSCRIPTIONS = [
+ 'users', 'meetings', 'polls', 'presentations', 'slides', 'captions',
+ 'voiceUsers', 'whiteboard-multi-user', 'screenshare', 'group-chat',
+ 'presentation-pods', 'users-settings', 'guestUser', 'users-infos',
+];
+
+class Subscriptions extends Component {
+ componentDidUpdate() {
+ const { subscriptionsReady } = this.props;
+ if (subscriptionsReady) {
+ Session.set('subscriptionsReady', true);
+ }
+ }
+
+ render() {
+ const { children } = this.props;
+ return children;
+ }
+}
+
+export default withTracker(() => {
+ const { credentials } = Auth;
+ const { meetingId, requesterUserId } = credentials;
+
+ const subscriptionErrorHandler = {
+ onError: (error) => {
+ logger.error({ logCode: 'startup_client_subscription_error' }, error);
+ Session.set('codeError', error.error);
+ },
+ };
+
+ const subscriptionsHandlers = SUBSCRIPTIONS.map(name => Meteor.subscribe(name, credentials, subscriptionErrorHandler));
+
+ let groupChatMessageHandler = {};
+ let annotationsHandler = {};
+
+ const chats = GroupChat.find({
+ $or: [
+ {
+ meetingId,
+ access: PUBLIC_CHAT_TYPE,
+ chatId: { $ne: PUBLIC_GROUP_CHAT_ID },
+ },
+ { meetingId, users: { $all: [requesterUserId] } },
+ ],
+ }).fetch();
+
+ const chatIds = chats.map(chat => chat.chatId);
+ groupChatMessageHandler = Meteor.subscribe('group-chat-msg', credentials, chatIds, subscriptionErrorHandler);
+ subscriptionsHandlers.push(groupChatMessageHandler);
+ const User = Users.findOne({ intId: requesterUserId });
+
+ if (User) {
+ const mappedUser = mapUser(User);
+ Meteor.subscribe('users', credentials, mappedUser.isModerator, subscriptionErrorHandler);
+ Meteor.subscribe('breakouts', credentials, mappedUser.isModerator, subscriptionErrorHandler);
+ Meteor.subscribe('meetings', credentials, mappedUser.isModerator, subscriptionErrorHandler);
+ }
+
+ annotationsHandler = Meteor.subscribe('annotations', credentials, {
+ onReady: () => {
+ const activeTextShapeId = AnnotationsTextService.activeTextShapeId();
+ AnnotationsLocal.remove({ id: { $ne: `${activeTextShapeId}-fake` } });
+ },
+ ...subscriptionErrorHandler,
+ });
+
+ Annotations.find({ meetingId: Auth.meetingID }).observe({
+ added(doc) {
+ AnnotationsLocal.insert(doc);
+ },
+ });
+
+ subscriptionsHandlers.push(annotationsHandler);
+
+ const ready = subscriptionsHandlers.every(handler => handler.ready());
+
+ return {
+ subscriptionsReady: ready,
+ subscriptionsHandlers,
+ };
+})(Subscriptions);