Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] VIDEO/JITSI multiple calls before video call #13855

Merged
merged 9 commits into from
Mar 26, 2019
151 changes: 79 additions & 72 deletions app/videobridge/client/views/videoFlexTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Template } from 'meteor/templating';
import { settings } from '../../../settings';
import { modal, TabBar } from '../../../ui-utils';
import { t } from '../../../utils';
import { Users, Rooms } from '../../../models';
import * as CONSTANTS from '../../constants';

Template.videoFlexTab.helpers({
openInNewWindow() {
Expand All @@ -14,11 +16,14 @@ Template.videoFlexTab.helpers({
Template.videoFlexTab.onCreated(function() {
this.tabBar = Template.currentData().tabBar;
});
Template.videoFlexTab.onDestroyed(function() {
return this.stop && this.stop();
});

Template.videoFlexTab.onRendered(function() {
this.api = null;

let timeOut = null;
const rid = Session.get('openedRoom');

const width = 'auto';
const height = 500;
Expand All @@ -40,6 +45,29 @@ Template.videoFlexTab.onRendered(function() {
TabBar.updateButton('video', { class: '' });
};

const stop = () => {
if (this.intervalHandler) {
Meteor.defer(() => this.api && this.api.dispose());
clearInterval(this.intervalHandler);
}
};

this.stop = stop;

const start = () => {
const update = () => {
const { jitsiTimeout } = Rooms.findOne({ _id: rid }, { fields: { jitsiTimeout: 1 }, reactive: false });

if (jitsiTimeout && (new Date() - new Date(jitsiTimeout) + CONSTANTS.TIMEOUT < CONSTANTS.DEBOUNCE)) {
return;
}
return Meteor.status().connected && Meteor.call('jitsi:updateTimeout', rid);
};
update();
this.intervalHandler = Meteor.setInterval(update, CONSTANTS.HEARTBEAT);
TabBar.updateButton('video', { class: 'red' });
};

modal.open({
title: t('Video_Conference'),
text: t('Start_video_call'),
Expand All @@ -52,86 +80,65 @@ Template.videoFlexTab.onRendered(function() {
if (!dismiss) {
return closePanel();
}
this.timeout = null;
this.intervalHandler = null;
this.autorun(() => {
if (settings.get('Jitsi_Enabled')) {
if (this.tabBar.getState() === 'opened') {
const roomId = Session.get('openedRoom');
if (!settings.get('Jitsi_Enabled')) {
return closePanel();
}

const domain = settings.get('Jitsi_Domain');
const jitsiRoom = settings.get('Jitsi_URL_Room_Prefix') + settings.get('uniqueID') + roomId;
const noSsl = !settings.get('Jitsi_SSL');
if (this.tabBar.getState() !== 'opened') {
TabBar.updateButton('video', { class: '' });
return stop();
}

if (jitsiRoomActive !== null && jitsiRoomActive !== jitsiRoom) {
jitsiRoomActive = null;
const domain = settings.get('Jitsi_Domain');
const jitsiRoom = settings.get('Jitsi_URL_Room_Prefix') + settings.get('uniqueID') + rid;
const noSsl = !settings.get('Jitsi_SSL');

closePanel();
if (jitsiRoomActive !== null && jitsiRoomActive !== jitsiRoom) {
jitsiRoomActive = null;

// Clean up and stop updating timeout.
Meteor.defer(() => this.api && this.api.dispose());
if (timeOut) {
clearInterval(timeOut);
}
} else {
jitsiRoomActive = jitsiRoom;

TabBar.updateButton('video', { class: 'red' });

if (settings.get('Jitsi_Open_New_Window')) {
Meteor.call('jitsi:updateTimeout', roomId);

timeOut = Meteor.setInterval(() => Meteor.call('jitsi:updateTimeout', roomId), 10 * 1000);
const newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }`, jitsiRoom);
const closeInterval = setInterval(() => {
if (newWindow.closed !== false) {
closePanel();
clearInterval(closeInterval);
clearInterval(timeOut);
}
}, 300);
if (newWindow) {
newWindow.focus();
}


// Lets make sure its loaded before we try to show it.
} else if (typeof JitsiMeetExternalAPI !== 'undefined') {

// Keep it from showing duplicates when re-evaluated on variable change.
if (!$('[id^=jitsiConference]').length) {
this.api = new JitsiMeetExternalAPI(domain, jitsiRoom, width, height, this.$('.video-container').get(0), configOverwrite, interfaceConfigOverwrite, noSsl);

/*
* Hack to send after frame is loaded.
* postMessage converts to events in the jitsi meet iframe.
* For some reason those aren't working right.
*/
Meteor.setTimeout(() => {
this.api.executeCommand('displayName', [Meteor.user().name]);
}, 5000);

Meteor.call('jitsi:updateTimeout', roomId);

timeOut = Meteor.setInterval(() => Meteor.call('jitsi:updateTimeout', roomId), 10 * 1000);
}

// Execute any commands that might be reactive. Like name changing.
this.api && this.api.executeCommand('displayName', [Meteor.user().name]);
closePanel();

return stop();
}

jitsiRoomActive = jitsiRoom;

if (settings.get('Jitsi_Open_New_Window')) {
start();
const newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }`, jitsiRoom);
if (newWindow) {
const closeInterval = setInterval(() => {
if (newWindow.closed === false) {
return;
}
}
} else {
TabBar.updateButton('video', { class: '' });

// Clean up and stop updating timeout.
if (timeOut) {
Meteor.defer(() => this.api && this.api.dispose());
clearInterval(timeOut);
}
closePanel();
stop();
clearInterval(closeInterval);
}, 300);
return newWindow.focus();
}

}

if (typeof JitsiMeetExternalAPI !== 'undefined') {
// Keep it from showing duplicates when re-evaluated on variable change.
const name = Users.findOne(Meteor.userId(), { fields: { name: 1 } });
if (!$('[id^=jitsiConference]').length) {
this.api = new JitsiMeetExternalAPI(domain, jitsiRoom, width, height, this.$('.video-container').get(0), configOverwrite, interfaceConfigOverwrite, noSsl);

/*
* Hack to send after frame is loaded.
* postMessage converts to events in the jitsi meet iframe.
* For some reason those aren't working right.
*/
Meteor.setTimeout(() => this.api.executeCommand('displayName', [name]), 5000);
return start();
}

// Execute any commands that might be reactive. Like name changing.
this.api && this.api.executeCommand('displayName', [name]);
}
});
});
});

3 changes: 3 additions & 0 deletions app/videobridge/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const TIMEOUT = 30 * 1000;
export const HEARTBEAT = TIMEOUT / 3;
export const DEBOUNCE = HEARTBEAT / 2;
22 changes: 15 additions & 7 deletions app/videobridge/server/methods/jitsiSetTimeout.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/tap:i18n';

import { Rooms, Messages } from '../../../models';
import { callbacks } from '../../../callbacks';
import * as CONSTANTS from '../../constants';
import { canAccessRoom } from '../../../authorization/server';

Meteor.methods({
'jitsi:updateTimeout': (rid) => {
Expand All @@ -11,28 +14,33 @@ Meteor.methods({
}

const room = Rooms.findOneById(rid);

if (!canAccessRoom(room, Meteor.user())) {
throw new Meteor.Error('error-not-allowerd', 'not allowed', { method: 'jitsi:updateTimeout' });
}

const currentTime = new Date().getTime();

const jitsiTimeout = new Date((room && room.jitsiTimeout) || currentTime).getTime();
const jitsiTimeout = room.jitsiTimeout && new Date(room.jitsiTimeout).getTime();

if (!jitsiTimeout || currentTime > jitsiTimeout - CONSTANTS.TIMEOUT / 2) {
Rooms.setJitsiTimeout(rid, new Date(currentTime + CONSTANTS.TIMEOUT));
}

if (jitsiTimeout <= currentTime) {
Rooms.setJitsiTimeout(rid, new Date(currentTime + 35 * 1000));
if (!jitsiTimeout || currentTime > jitsiTimeout) {
const message = Messages.createWithTypeRoomIdMessageAndUser('jitsi_call_started', rid, '', Meteor.user(), {
actionLinks : [
{ icon: 'icon-videocam', label: TAPi18n.__('Click_to_join'), method_id: 'joinJitsiCall', params: '' },
],
});
const room = Rooms.findOneById(rid);
message.msg = TAPi18n.__('Started_a_video_call');
message.mentions = [
{
_id:'here',
username:'here',
},
];
callbacks.run('afterSaveMessage', message, room);
} else if ((jitsiTimeout - currentTime) / 1000 <= 15) {
Rooms.setJitsiTimeout(rid, new Date(jitsiTimeout + 25 * 1000));
callbacks.run('afterSaveMessage', message, { ...room, jitsiTimeout: currentTime + CONSTANTS.TIMEOUT });
}
},
});