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

Add ping-pong message to html5 client #7708

Merged
merged 5 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions bigbluebutton-html5/imports/api/ping-pong/index.js
@@ -0,0 +1,5 @@
import { Meteor } from 'meteor/meteor';

const PingPong = new Mongo.Collection('ping-pong');

export default PingPong;
2 changes: 2 additions & 0 deletions bigbluebutton-html5/imports/api/ping-pong/server/index.js
@@ -0,0 +1,2 @@
import './publishers';
import './methods';
6 changes: 6 additions & 0 deletions bigbluebutton-html5/imports/api/ping-pong/server/methods.js
@@ -0,0 +1,6 @@
import { Meteor } from 'meteor/meteor';
import ping from './methods/ping';

Meteor.methods({
ping,
});
21 changes: 21 additions & 0 deletions bigbluebutton-html5/imports/api/ping-pong/server/methods/ping.js
@@ -0,0 +1,21 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Users from '/imports/api/users';

export default function ping(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;

check(meetingId, String);
check(requesterUserId, String);
check(requesterToken, String);


return Users.upsert({
meetingId,
userId: requesterUserId,
}, {
$set: {
lastPing: Date.now(),
},
});
}
33 changes: 33 additions & 0 deletions bigbluebutton-html5/imports/api/ping-pong/server/publishers.js
@@ -0,0 +1,33 @@
import { Meteor } from 'meteor/meteor';
import Logger from '/imports/startup/server/logger';
import _ from 'lodash';

const COLLECTION_NAME = 'ping-pong';
const POLL_INTERVAL = 5000;

function pingPong(credentials) {
const { meetingId, requesterUserId } = credentials;
const id = _.uniqueId('pong-');
Logger.info(`Starting ping-pong publish for userId: ${requesterUserId}`);
const pongSender = (interval) => {
const payload = {
pong: {
message: 'pong',
time: Date.now(),
meetingId,
},
};
let fn = this.added.bind(this);
if (interval) fn = this.changed.bind(this);
fn(COLLECTION_NAME, id, payload);
};
pongSender();
this.ready();
const interval = Meteor.setInterval(() => pongSender(true), POLL_INTERVAL);

this.onStop(() => {
Meteor.clearInterval(interval);
});
}

Meteor.publish('ping-pong', pingPong);
@@ -1,7 +1,7 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import Users from '/imports/api/users';

import setConnectionStatus from '/imports/api/users/server/modifiers/setConnectionStatus';
import userJoin from '../methods/userJoin';

const clearOtherSessions = (sessionUserId, current = false) => {
Expand Down Expand Up @@ -54,6 +54,7 @@ export default function handleValidateAuthToken({ body }, meetingId) {
if (valid) {
const sessionUserId = `${meetingId}-${userId}`;
const currentConnectionId = User.connectionId ? User.connectionId : false;
setConnectionStatus(meetingId, userId);
clearOtherSessions(sessionUserId, currentConnectionId);
}

Expand Down
Expand Up @@ -3,6 +3,7 @@ import { check } from 'meteor/check';
import RedisPubSub from '/imports/startup/server/redis';
import Logger from '/imports/startup/server/logger';
import Users from '/imports/api/users';
import setConnectionStatus from '/imports/api/users/server/modifiers/setConnectionStatus';

export default function userLeaving(credentials, userId, connectionId) {
const REDIS_CONFIG = Meteor.settings.private.redis;
Expand Down Expand Up @@ -37,6 +38,6 @@ export default function userLeaving(credentials, userId, connectionId) {
};

Logger.info(`User '${userId}' is leaving meeting '${meetingId}'`);

setConnectionStatus(meetingId, userId, 'offline');
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
}
1 change: 1 addition & 0 deletions bigbluebutton-html5/imports/api/users/server/publishers.js
Expand Up @@ -70,6 +70,7 @@ function users(credentials, isModerator = false) {
const options = {
fields: {
authToken: false,
lastPing: false,
},
};

Expand Down
1 change: 0 additions & 1 deletion bigbluebutton-html5/imports/startup/client/base.jsx
Expand Up @@ -88,7 +88,6 @@ class Base extends Component {
meteorIsConnected,
subscriptionsReady,
} = this.props;

const {
loading,
meetingExisted,
Expand Down
27 changes: 25 additions & 2 deletions bigbluebutton-html5/imports/startup/server/index.js
@@ -1,16 +1,17 @@
import { Meteor } from 'meteor/meteor';
import { WebAppInternals } from 'meteor/webapp';
import Langmap from 'langmap';
import Users from '/imports/api/users';
import fs from 'fs';
import Users from '/imports/api/users';
import './settings';
import { lookup as lookupUserAgent } from 'useragent';
import Logger from './logger';
import Redis from './redis';
import setMinBrowserVersions from './minBrowserVersion';
import userLeaving from '/imports/api/users/server/methods/userLeaving';

const parse = Npm.require('url').parse;

const INTERVAL_TIME = 10000;
const AVAILABLE_LOCALES = fs.readdirSync('assets/app/locales');

Meteor.startup(() => {
Expand Down Expand Up @@ -43,6 +44,28 @@ Meteor.startup(() => {

setMinBrowserVersions();

Meteor.setInterval(() => {
const currentTime = Date.now();
Logger.info('Checking for inactive users');
const users = Users.find({
connectionStatus: 'online',
lastPing: {
$lt: (currentTime - INTERVAL_TIME), // get user who has not pinged in the last 10 seconds
},
}).fetch();
if (!users.length) return Logger.info('No inactive users');
Logger.info('Removing inactive users');
users.forEach((user) => {
const loginTimeSec = (currentTime - user.loginTime) / 1000;
const lastPingSec = (currentTime - user.lastPing) / 1000;
user.requesterUserId = user.userId;
return loginTimeSec >= 10
&& lastPingSec >= 10
capilkey marked this conversation as resolved.
Show resolved Hide resolved
&& userLeaving(user, user.userId, user.connectionId);
});
return Logger.info('All inactive user have been removed');
}, INTERVAL_TIME);

Logger.warn(`SERVER STARTED.\nENV=${env},\nnodejs version=${process.version}\nCDN=${CDN_URL}\n`, APP_CONFIG);
});

Expand Down
4 changes: 3 additions & 1 deletion bigbluebutton-html5/imports/ui/components/app/component.jsx
Expand Up @@ -18,6 +18,8 @@ import ChatAlertContainer from '../chat/alert/container';
import BannerBarContainer from '/imports/ui/components/banner-bar/container';
import WaitingNotifierContainer from '/imports/ui/components/waiting-users/alert/container';
import LockNotifier from '/imports/ui/components/lock-viewers/notify/container';
import PingPongContainer from '/imports/ui/components/ping-pong/container';

import MediaService from '/imports/ui/components/media/service';
import ManyWebcamsNotifier from '/imports/ui/components/video-provider/many-users-notify/container';
import { styles } from './styles';
Expand Down Expand Up @@ -96,7 +98,6 @@ const isLayeredView = window.matchMedia(`(max-width: ${LAYERED_BREAKPOINT}px)`);
class App extends Component {
constructor() {
super();

this.state = {
enableResize: !window.matchMedia(MOBILE_MEDIA).matches,
};
Expand Down Expand Up @@ -344,6 +345,7 @@ class App extends Component {
<ChatAlertContainer />
<WaitingNotifierContainer />
<LockNotifier />
<PingPongContainer />
<ManyWebcamsNotifier />
{customStyleUrl ? <link rel="stylesheet" type="text/css" href={customStyleUrl} /> : null}
{customStyle ? <link rel="stylesheet" type="text/css" href={`data:text/css;charset=UTF-8,${encodeURIComponent(customStyle)}`} /> : null}
Expand Down
22 changes: 22 additions & 0 deletions bigbluebutton-html5/imports/ui/components/ping-pong/container.jsx
@@ -0,0 +1,22 @@
import React from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import PingPong from '/imports/api/ping-pong';
import { makeCall } from '/imports/ui/services/api';

class PlaceHolderComponent extends React.Component {
shouldComponentUpdate() {
return false;
}

render() {
return null;
}
}

export default withTracker(() => {
PingPong.find({}).observe({
added: () => makeCall('ping'),
changed: () => makeCall('ping'),
});
return {};
})(PlaceHolderComponent);
Expand Up @@ -16,7 +16,7 @@ const SUBSCRIPTIONS = [
'users', 'meetings', 'polls', 'presentations', 'slides', 'captions',
'voiceUsers', 'whiteboard-multi-user', 'screenshare', 'group-chat',
'presentation-pods', 'users-settings', 'guestUser', 'users-infos', 'note',
'network-information',
'network-information', 'ping-pong',
];

class Subscriptions extends React.Component {
Expand All @@ -41,6 +41,7 @@ export default withTracker(() => {
subscriptionsReady: true,
};
}

const subscriptionErrorHandler = {
onError: (error) => {
logger.error({ logCode: 'startup_client_subscription_error' }, error);
Expand Down
1 change: 1 addition & 0 deletions bigbluebutton-html5/server/main.js
Expand Up @@ -24,6 +24,7 @@ import '/imports/api/users-infos/server';
import '/imports/api/note/server';
import '/imports/api/external-videos/server';
import '/imports/api/guest-users/server';
import '/imports/api/ping-pong/server';


// Commons
Expand Down