diff --git a/bigbluebutton-html5/imports/ui/components/cursor/service.js b/bigbluebutton-html5/imports/ui/components/cursor/service.js index 56746d56e6cef74e63637443b2922a59753ba51b..3a2efb7992b926fd8933f76d802343bcce4a8bc1 100755 --- a/bigbluebutton-html5/imports/ui/components/cursor/service.js +++ b/bigbluebutton-html5/imports/ui/components/cursor/service.js @@ -35,13 +35,31 @@ export function publishCursorUpdate(payload) { } export function initCursorStreamListener() { - logger.debug({ + logger.info({ logCode: 'init_cursor_stream_listener', + extraInfo: { meetingId: Auth.meetingID, userId: Auth.userID }, }, 'initCursorStreamListener called'); - if (!cursorStreamListener) { - cursorStreamListener = new Meteor.Streamer(`cursor-${Auth.meetingID}`, { retransmit: false }); + /** + * We create a promise to add the handlers after a ddp subscription stop. + * The problem was caused because we add handlers to stream before the onStop event happens, + * which set the handlers to undefined. + */ + cursorStreamListener = new Meteor.Streamer(`cursor-${Auth.meetingID}`, { retransmit: false }); + const startStreamHandlersPromise = new Promise((resolve) => { + const checkStreamHandlersInterval = setInterval(() => { + const streamHandlersSize = Object.values(Meteor.StreamerCentral.instances[`cursor-${Auth.meetingID}`].handlers) + .filter(el => el != undefined) + .length; + + if (!streamHandlersSize) { + resolve(clearInterval(checkStreamHandlersInterval)); + } + }, 250); + }); + + startStreamHandlersPromise.then(() => { logger.debug({ logCode: 'init_cursor_stream_listener', }, 'initCursorStreamListener called'); @@ -52,7 +70,7 @@ export function initCursorStreamListener() { updateCursor(userId, cursors[userId]); }); }); - } + }); } export default Cursor; diff --git a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx index 554b05d940856fc72c6096201f94a4cdeae1cfb8..80f4efc3037caa911f599f7b205102a99cbf1773 100755 --- a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx @@ -6,8 +6,7 @@ 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, { initAnnotationsStreamListener } from '/imports/ui/components/whiteboard/service'; -import { initCursorStreamListener } from '/imports/ui/components/cursor/service'; +import AnnotationsLocal from '/imports/ui/components/whiteboard/service'; const CHAT_CONFIG = Meteor.settings.public.chat; @@ -95,9 +94,6 @@ export default withTracker(() => { Meteor.subscribe('users', credentials, userIsModerator, subscriptionErrorHandler); Meteor.subscribe('breakouts', credentials, userIsModerator, subscriptionErrorHandler); Meteor.subscribe('meetings', credentials, userIsModerator, subscriptionErrorHandler); - logger.debug({ logCode: 'startup_client_subscription_init_streamers', extraInfo: { role: User.role } }, 'Calling init streamers functions'); - initAnnotationsStreamListener(); - initCursorStreamListener(); } const annotationsHandler = Meteor.subscribe('annotations', credentials, { diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js index 0a59888156256cfba9278ef1685471cb64a24801..f8712a3e36576d430bd50bb52fb8dc6b880848d9 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js @@ -99,9 +99,26 @@ function handleRemovedAnnotation({ } export function initAnnotationsStreamListener() { - if (!annotationsStreamListener) { - annotationsStreamListener = new Meteor.Streamer(`annotations-${Auth.meetingID}`, { retransmit: false }); + /** + * We create a promise to add the handlers after a ddp subscription stop. + * The problem was caused because we add handlers to stream before the onStop event happens, + * which set the handlers to undefined. + */ + annotationsStreamListener = new Meteor.Streamer(`annotations-${Auth.meetingID}`, { retransmit: false }); + + const startStreamHandlersPromise = new Promise((resolve) => { + const checkStreamHandlersInterval = setInterval(() => { + const streamHandlersSize = Object.values(Meteor.StreamerCentral.instances[`annotations-${Auth.meetingID}`].handlers) + .filter(el => el != undefined) + .length; + + if (!streamHandlersSize) { + resolve(clearInterval(checkStreamHandlersInterval)); + } + }, 250); + }); + startStreamHandlersPromise.then(() => { annotationsStreamListener.on('removed', handleRemovedAnnotation); annotationsStreamListener.on('added', ({ annotations }) => { @@ -110,7 +127,7 @@ export function initAnnotationsStreamListener() { .filter(({ annotation }) => !discardedList.includes(annotation.id)) .forEach(annotation => handleAddedAnnotation(annotation)); }); - } + }); } function increaseBrightness(realHex, percent) { diff --git a/bigbluebutton-html5/imports/ui/services/auth/index.js b/bigbluebutton-html5/imports/ui/services/auth/index.js index 9389a914f69c3516546a94e74e9c608e098aa4fa..69b0ecad531fd1929ae09ea4a9371df0a7ac10f6 100755 --- a/bigbluebutton-html5/imports/ui/services/auth/index.js +++ b/bigbluebutton-html5/imports/ui/services/auth/index.js @@ -6,6 +6,8 @@ import Storage from '/imports/ui/services/storage/session'; import Users from '/imports/api/users'; import logger from '/imports/startup/client/logger'; import { makeCall } from '/imports/ui/services/api'; +import { initAnnotationsStreamListener } from '/imports/ui/components/whiteboard/service'; +import { initCursorStreamListener } from '/imports/ui/components/cursor/service'; const CONNECTION_TIMEOUT = Meteor.settings.public.app.connectionTimeout; @@ -220,7 +222,7 @@ class Auth { const selector = { meetingId: this.meetingID, userId: this.userID }; const fields = { - intId: 1, ejected: 1, validated: 1, connectionStatus: 1, + intId: 1, ejected: 1, validated: 1, connectionStatus: 1, userId: 1, }; const User = Users.findOne(selector, { fields }); // Skip in case the user is not in the collection yet or is a dummy user @@ -239,6 +241,9 @@ class Auth { } if (User.validated === true && User.connectionStatus === 'online') { + logger.info({ logCode: 'auth_service_init_streamers', extraInfo: { userId: User.userId } }, 'Calling init streamers functions'); + initCursorStreamListener(); + initAnnotationsStreamListener(); computation.stop(); clearTimeout(validationTimeout); // setTimeout to prevent race-conditions with subscription