Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions app/api/server/v1/video-conference.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meteor } from 'meteor/meteor';

import { Rooms } from '../../../models';
import { Rooms } from '../../../models/server';
import { API } from '../api';

API.v1.addRoute('video-conference/jitsi.update-timeout', { authRequired: true }, {
Expand All @@ -10,13 +10,13 @@ API.v1.addRoute('video-conference/jitsi.update-timeout', { authRequired: true },
return API.v1.failure('The "roomId" parameter is required!');
}

const room = Rooms.findOneById(roomId);
const room = Rooms.findOneById(roomId, { fields: { _id: 1 } });
if (!room) {
return API.v1.failure('Room does not exist!');
}

Meteor.runAsUser(this.userId, () => Meteor.call('jitsi:updateTimeout', roomId));
const jitsiTimeout = Meteor.runAsUser(this.userId, () => Meteor.call('jitsi:updateTimeout', roomId));

return API.v1.success({ jitsiTimeout: Rooms.findOneById(roomId).jitsiTimeout });
return API.v1.success({ jitsiTimeout });
},
});
108 changes: 56 additions & 52 deletions app/videobridge/client/views/videoFlexTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { Template } from 'meteor/templating';
import { TimeSync } from 'meteor/mizzao:timesync';

import { settings } from '../../../settings';
import { modal, TabBar } from '../../../ui-utils';
import { t } from '../../../utils';
import { modal, TabBar, call } from '../../../ui-utils/client';
import { t } from '../../../utils/client';
import { Users, Rooms } from '../../../models';
import * as CONSTANTS from '../../constants';

Expand Down Expand Up @@ -57,22 +57,33 @@ Template.videoFlexTab.onRendered(function() {

this.stop = stop;

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

if (jitsiTimeout && (TimeSync.serverTime() - new Date(jitsiTimeout) + CONSTANTS.TIMEOUT < CONSTANTS.DEBOUNCE)) {
if (jitsiTimeout && (TimeSync.serverTime() - new Date(jitsiTimeout) + CONSTANTS.TIMEOUT < CONSTANTS.DEBOUNCE)) {
return;
}
if (Meteor.status().connected) {
return call('jitsi:updateTimeout', rid);
}
closePanel();
return this.stop();
};

const start = async () => {
try {
const jitsiTimeout = await update();
if (!jitsiTimeout) {
return;
}
if (Meteor.status().connected) {
return Meteor.call('jitsi:updateTimeout', rid);
}
this.intervalHandler = setInterval(update, CONSTANTS.HEARTBEAT);
TabBar.updateButton('video', { class: 'red' });
return jitsiTimeout;
} catch (error) {
console.error(error);
closePanel();
return this.stop();
};
update();
this.intervalHandler = setInterval(update, CONSTANTS.HEARTBEAT);
TabBar.updateButton('video', { class: 'red' });
throw error;
}
};

modal.open({
Expand Down Expand Up @@ -111,54 +122,47 @@ Template.videoFlexTab.onRendered(function() {
return stop();
}

let accessToken = null;
if (isEnabledTokenAuth) {
accessToken = await new Promise((resolve, reject) => {
Meteor.call('jitsi:generateAccessToken', rid, (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
});
}
const accessToken = isEnabledTokenAuth && await call('jitsi:generateAccessToken', rid);

jitsiRoomActive = jitsiRoom;

if (settings.get('Jitsi_Open_New_Window')) {
Tracker.nonreactive(() => start());
let queryString = '';
if (accessToken) {
queryString = `?jwt=${ accessToken }`;
}

const newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }${ queryString }`, jitsiRoom);
if (newWindow) {
const closeInterval = setInterval(() => {
if (newWindow.closed === false) {
return;
}
closePanel();
stop();
clearInterval(closeInterval);
}, 300);
return newWindow.focus();
}
Tracker.nonreactive(async () => {
await start();

const queryString = accessToken && `?jwt=${ accessToken }`;

const newWindow = window.open(`${ (noSsl ? 'http://' : 'https://') + domain }/${ jitsiRoom }${ queryString }`, jitsiRoom);
if (newWindow) {
const closeInterval = setInterval(() => {
if (newWindow.closed === false) {
return;
}
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, accessToken);

/*
* 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 Tracker.nonreactive(() => start());
Tracker.nonreactive(async () => {
await start();

this.api = new JitsiMeetExternalAPI(domain, jitsiRoom, width, height, this.$('.video-container').get(0), configOverwrite, interfaceConfigOverwrite, noSsl, accessToken);

/*
* 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);
});
}

// Execute any commands that might be reactive. Like name changing.
Expand Down
79 changes: 48 additions & 31 deletions app/videobridge/server/methods/jitsiSetTimeout.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,62 @@
import { Meteor } from 'meteor/meteor';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';

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

Meteor.methods({
'jitsi:updateTimeout': (rid) => {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'jitsi:updateTimeout' });
}

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 = 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 > jitsiTimeout) {
const message = Messages.createWithTypeRoomIdMessageAndUser('jitsi_call_started', rid, '', Meteor.user(), {
actionLinks: [
{ icon: 'icon-videocam', label: TAPi18n.__('Click_to_join'), method_id: 'joinJitsiCall', params: '' },
],
});
message.msg = TAPi18n.__('Started_a_video_call');
message.mentions = [
{
_id: 'here',
username: 'here',
},
];
callbacks.run('afterSaveMessage', message, { ...room, jitsiTimeout: currentTime + CONSTANTS.TIMEOUT });
const uid = Meteor.userId();

const user = Users.findOneById(uid, {
fields: {
username: 1,
type: 1,
},
});

try {
const room = canSendMessage(rid, { uid, username: user.username, type: user.type });

const currentTime = new Date().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 > jitsiTimeout) {
metrics.messagesSent.inc(); // TODO This line needs to be moved to it's proper place. See the comments on: https://github.com/RocketChat/Rocket.Chat/pull/5736

const message = Messages.createWithTypeRoomIdMessageAndUser('jitsi_call_started', rid, '', Meteor.user(), {
actionLinks: [
{ icon: 'icon-videocam', label: TAPi18n.__('Click_to_join'), method_id: 'joinJitsiCall', params: '' },
],
});
message.msg = TAPi18n.__('Started_a_video_call');
message.mentions = [
{
_id: 'here',
username: 'here',
},
];
callbacks.run('afterSaveMessage', message, { ...room, jitsiTimeout: currentTime + CONSTANTS.TIMEOUT });
}

return jitsiTimeout;
} catch (error) {
SystemLogger.error('Error starting video call:', error);

throw new Meteor.Error('error-starting-video-call', error.message);
}
},
});