Merged 2.0 and 1.1 meetings api

This commit is contained in:
Oleksandr Zhurbenko 2017-10-11 15:17:42 -07:00
parent 48d4736c71
commit eb75c6d9fb
29 changed files with 123 additions and 480 deletions

View File

@ -1 +1,12 @@
export default new Mongo.Collection('meetings');
import { Meteor } from 'meteor/meteor';
const Meetings = new Mongo.Collection('meetings2x');
if (Meteor.isServer) {
// types of queries for the meetings:
// 1. meetingId
Meetings._ensureIndex({ meetingId: 1 });
}
export default Meetings;

View File

@ -1,17 +1,12 @@
import RedisPubSub from '/imports/startup/server/redis';
import handleMeetingDestruction from './handlers/meetingDestruction';
import handleRecordingStatusChange from './handlers/recordingStatusChange';
import handlePermissionSettingsChange from './handlers/permissionSettingsChange';
import RedisPubSub from '/imports/startup/server/redis2x';
import handleMeetingCreation from './handlers/meetingCreation';
import handleGetAllMeetings from './handlers/getAllMeetings';
import handleStunTurnReply from './handlers/stunTurnReply';
import handleMeetingEnd from './handlers/meetingEnd';
import handleMeetingLocksChange from './handlers/meetingLockChange';
import handleUserLockChange from './handlers/userLockChange';
RedisPubSub.on('meeting_destroyed_event', handleMeetingDestruction);
RedisPubSub.on('meeting_ended_message', handleMeetingDestruction);
RedisPubSub.on('end_and_kick_all_message', handleMeetingDestruction);
RedisPubSub.on('disconnect_all_users_message', handleMeetingDestruction);
RedisPubSub.on('recording_status_changed_message', handleRecordingStatusChange);
RedisPubSub.on('new_permission_settings', handlePermissionSettingsChange);
RedisPubSub.on('meeting_created_message', handleMeetingCreation);
RedisPubSub.on('get_all_meetings_reply_message', handleGetAllMeetings);
RedisPubSub.on('send_stun_turn_info_reply_message', handleStunTurnReply);
RedisPubSub.on('MeetingCreatedEvtMsg', handleMeetingCreation);
RedisPubSub.on('SyncGetMeetingInfoRespMsg', handleGetAllMeetings);
RedisPubSub.on('MeetingEndingEvtMsg', handleMeetingEnd);
RedisPubSub.on('LockSettingsInMeetingChangedEvtMsg', handleMeetingLocksChange);
RedisPubSub.on('UserLockedInMeetingEvtMsg', handleUserLockChange);

View File

@ -1,36 +1,5 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import Meetings from '/imports/api/1.1/meetings';
import addMeeting from '../modifiers/addMeeting';
import removeMeeting from '../modifiers/removeMeeting';
import handleMeetingCreation from './meetingCreation';
export default function handleGetAllMeetings({ payload }) {
let meetings = payload.meetings;
check(meetings, Array);
// We need to map the meetings payload because for some reason this payload
// is different than the `meeting_created_message` one
meetings = meetings.map(m => ({
meeting_id: m.meetingID,
name: m.meetingName,
recorded: m.recorded,
voice_conf: m.voiceBridge,
duration: m.duration,
}));
const meetingsIds = meetings.map(m => m.meeting_id);
const meetingsToRemove = Meetings.find({
meetingId: { $nin: meetingsIds },
}).fetch();
meetingsToRemove.forEach(meeting => removeMeeting(meeting.meetingId));
const meetingsAdded = [];
meetings.forEach((meeting) => {
meetingsAdded.push(addMeeting(meeting));
});
return meetingsAdded;
export default function handleGetAllMeetings({ body }) {
return handleMeetingCreation({ body });
}

View File

@ -1,11 +1,9 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import addMeeting from '../modifiers/addMeeting';
export default function handleMeetingCreation({ payload }) {
const meetingId = payload.meeting_id;
export default function handleMeetingCreation({ body }) {
const meeting = body.props;
check(meeting, Object);
check(meetingId, String);
return addMeeting(payload);
return addMeeting(meeting);
}

View File

@ -1,11 +0,0 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import removeMeeting from '../modifiers/removeMeeting';
export default function handleMeetingDestruction({ payload }) {
const meetingId = payload.meeting_id;
check(meetingId, String);
return removeMeeting(meetingId);
}

View File

@ -1,53 +0,0 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import Meetings from '/imports/api/1.1/meetings';
import { Meteor } from 'meteor/meteor';
import lockAllViewersMic from '/imports/api/1.1/users/server/modifiers/lockAllViewersMic';
export default function handlePermissionSettingsChange({ payload }) {
const meetingId = payload.meeting_id;
const permissions = payload.permissions;
check(meetingId, String);
check(permissions, Object);
const selector = {
meetingId,
};
const Meeting = Meetings.findOne(selector);
if (!Meeting) {
throw new Meteor.Error('meeting-not-found', `Meeting id=${meetingId} was not found`);
}
const modifier = {
$set: {
roomLockSettings: {
disablePrivateChat: permissions.disablePrivateChat,
disableCam: permissions.disableCam,
disableMic: permissions.disableMic,
lockOnJoin: permissions.lockOnJoin,
lockedLayout: permissions.lockedLayout,
disablePublicChat: permissions.disablePublicChat,
lockOnJoinConfigurable: permissions.lockOnJoinConfigurable,
},
},
};
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Updating meeting permissions: ${err}`);
}
if (permissions.disableMic) {
lockAllViewersMic(meetingId);
}
if (numChanged) {
return Logger.info(`Updated meeting permissions id=${meetingId}`);
}
};
return Meetings.update(selector, modifier, cb);
}

View File

@ -1,36 +0,0 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import Meetings from '/imports/api/1.1/meetings';
export default function handleRecordingStatusChange({ payload }) {
const meetingId = payload.meeting_id;
const intendedForRecording = payload.recorded;
const currentlyBeingRecorded = payload.recording;
check(meetingId, String);
check(intendedForRecording, Boolean);
check(currentlyBeingRecorded, Boolean);
const selector = {
meetingId,
intendedForRecording,
};
const modifier = {
$set: {
currentlyBeingRecorded,
},
};
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Updating meeting recording status: ${err}`);
}
if (numChanged) {
return Logger.info(`Updated meeting recording status id=${meetingId}`);
}
};
return Meetings.update(selector, modifier, cb);
}

View File

@ -1,33 +0,0 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import Meetings from '/imports/api/1.1/meetings';
export default function handleStunTurnReply({ payload }) {
const meetingId = payload.meeting_id;
const { stuns, turns } = payload;
check(meetingId, String);
const selector = {
meetingId,
};
const modifier = {
$set: {
stuns,
turns,
},
};
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Updating meeting stuns/turns: ${err}`);
}
if (numChanged) {
return Logger.info(`Updated meeting stuns/turns id=${meetingId}`);
}
};
return Meetings.update(selector, modifier, cb);
}

View File

View File

@ -1,4 +1,7 @@
import { Meteor } from 'meteor/meteor';
import mapToAcl from '/imports/startup/mapToAcl';
import endMeeting from './methods/endMeeting';
Meteor.methods({
});
Meteor.methods(mapToAcl(['methods.endMeeting'], {
endMeeting,
}));

View File

@ -1,53 +1,92 @@
import flat from 'flat';
import { check } from 'meteor/check';
import Meetings from '/imports/api/1.1/meetings';
import Meetings from '/imports/api/2.0/meetings';
import Logger from '/imports/startup/server/logger';
import initializeCursor from '/imports/api/1.1/cursor/server/modifiers/initializeCursor';
export default function addMeeting(meeting) {
const APP_CONFIG = Meteor.settings.public.app;
const meetingId = meeting.meeting_id;
const meetingId = meeting.meetingProp.intId;
check(meeting, Object);
check(meetingId, String);
check(meeting, {
breakoutProps: {
sequence: Number,
breakoutRooms: Array,
parentId: String,
},
meetingProp: {
intId: String,
extId: String,
isBreakout: Boolean,
name: String,
},
usersProp: {
webcamsOnlyForModerator: Boolean,
guestPolicy: String,
maxUsers: Number,
},
durationProps: {
createdTime: Number,
duration: Number,
createdDate: String,
maxInactivityTimeoutMinutes: Number,
warnMinutesBeforeMax: Number,
meetingExpireIfNoUserJoinedInMinutes: Number,
meetingExpireWhenLastUserLeftInMinutes: Number,
},
welcomeProp: {
welcomeMsg: String,
modOnlyMessage: String,
welcomeMsgTemplate: String,
},
recordProp: {
allowStartStopRecording: Boolean,
autoStartRecording: Boolean,
record: Boolean,
},
password: {
viewerPass: String,
moderatorPass: String,
},
voiceProp: {
voiceConf: String,
dialNumber: String,
telVoice: String,
},
screenshareProps: {
red5ScreenshareIp: String,
red5ScreenshareApp: String,
screenshareConf: String,
},
metadataProp: Object,
});
const selector = {
meetingId,
};
const modifier = {
$set: {
meetingId,
meetingName: meeting.name,
intendedForRecording: meeting.recorded,
currentlyBeingRecorded: false,
voiceConf: meeting.voice_conf,
duration: meeting.duration,
roomLockSettings: {
disablePrivateChat: false,
disableCam: false,
disableMic: false,
lockOnJoin: APP_CONFIG.lockOnJoin,
lockedLayout: false,
disablePublicChat: false,
lockOnJoinConfigurable: false,
},
},
$set: Object.assign(
{ meetingId },
flat(meeting, { safe: true }),
),
};
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Adding meeting to collection: ${err}`);
Logger.error(`Adding meeting to collection: ${err}`);
return;
}
initializeCursor(meetingId);
const { insertedId } = numChanged;
if (insertedId) {
return Logger.info(`Added meeting id=${meetingId}`);
Logger.info(`Added meeting2x id=${meetingId}`);
}
if (numChanged) {
return Logger.info(`Upserted meeting id=${meetingId}`);
Logger.info(`Upserted meeting2x id=${meetingId}`);
}
};

View File

@ -1,29 +0,0 @@
import Meetings from '/imports/api/1.1/chat';
import Logger from '/imports/startup/server/logger';
import removeMeeting from './removeMeeting';
import clearUsers from '/imports/api/1.1/users/server/modifiers/clearUsers';
import clearChats from '/imports/api/1.1/chat/server/modifiers/clearChats';
import clearBreakouts from '/imports/api/1.1/breakouts/server/modifiers/clearBreakouts';
import clearShapes from '/imports/api/1.1/shapes/server/modifiers/clearShapes';
import clearSlides from '/imports/api/1.1/slides/server/modifiers/clearSlides';
import clearPolls from '/imports/api/1.1/polls/server/modifiers/clearPolls';
import clearCursor from '/imports/api/1.1/cursor/server/modifiers/clearCursor';
import clearCaptions from '/imports/api/1.1/captions/server/modifiers/clearCaptions';
import clearPresentations from '/imports/api/1.1/presentations/server/modifiers/clearPresentations';
export default function clearMeetings() {
return Meetings.remove({}, (err) => {
clearCaptions();
clearChats();
clearCursor();
clearPresentations();
clearBreakouts();
clearPolls();
clearShapes();
clearSlides();
clearUsers();
return Logger.info('Cleared Meetings (all)');
});
}

View File

@ -1,41 +1,30 @@
import { check } from 'meteor/check';
import Meetings from '/imports/api/1.1/meetings';
import Meetings from '/imports/api/2.0/meetings';
import Logger from '/imports/startup/server/logger';
import clearUsers from '/imports/api/1.1/users/server/modifiers/clearUsers';
import clearChats from '/imports/api/1.1/chat/server/modifiers/clearChats';
import clearShapes from '/imports/api/1.1/shapes/server/modifiers/clearShapes';
import clearSlides from '/imports/api/1.1/slides/server/modifiers/clearSlides';
import clearPolls from '/imports/api/1.1/polls/server/modifiers/clearPolls';
import clearCursor from '/imports/api/1.1/cursor/server/modifiers/clearCursor';
import clearCaptions from '/imports/api/1.1/captions/server/modifiers/clearCaptions';
import clearPresentations from '/imports/api/1.1/presentations/server/modifiers/clearPresentations';
import clearUsers from '/imports/api/2.0/users/server/modifiers/clearUsers';
import clearChats from '/imports/api/2.0/chat/server/modifiers/clearChats';
import clearBreakouts from '/imports/api/2.0/breakouts/server/modifiers/clearBreakouts';
import clearAnnotations from '/imports/api/2.0/annotations/server/modifiers/clearAnnotations';
import clearSlides from '/imports/api/2.0/slides/server/modifiers/clearSlides';
import clearPolls from '/imports/api/2.0/polls/server/modifiers/clearPolls';
import clearCursor from '/imports/api/2.0/cursor/server/modifiers/clearCursor';
import clearCaptions from '/imports/api/2.0/captions/server/modifiers/clearCaptions';
import clearPresentations from '/imports/api/2.0/presentations/server/modifiers/clearPresentations';
import clearVoiceUsers from '/imports/api/2.0/voice-users/server/modifiers/clearVoiceUsers';
export default function removeMeeting(meetingId) {
check(meetingId, String);
return Meetings.remove({ meetingId }, () => {
clearCaptions(meetingId);
clearChats(meetingId);
clearCursor(meetingId);
clearPresentations(meetingId);
clearBreakouts(meetingId);
clearPolls(meetingId);
clearAnnotations(meetingId);
clearSlides(meetingId);
clearUsers(meetingId);
clearVoiceUsers(meetingId);
const selector = {
meetingId,
};
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Removing meeting from collection: ${err}`);
}
if (numChanged) {
clearCaptions(meetingId);
clearChats(meetingId);
clearCursor(meetingId);
clearPresentations(meetingId);
clearPolls(meetingId);
clearShapes(meetingId);
clearSlides(meetingId);
clearUsers(meetingId);
return Logger.info(`Removed meeting id=${meetingId}`);
}
};
return Meetings.remove(selector, cb);
return Logger.info(`Cleared Meetings with id ${meetingId}`);
});
}

View File

@ -1,6 +1,6 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Meetings from '/imports/api/1.1/meetings';
import Meetings from '/imports/api/2.0/meetings';
import Logger from '/imports/startup/server/logger';
import mapToAcl from '/imports/startup/mapToAcl';
@ -11,7 +11,7 @@ function meetings(credentials) {
check(requesterUserId, String);
check(requesterToken, String);
Logger.info(`Publishing meeting=${meetingId} ${requesterUserId} ${requesterToken}`);
Logger.info(`Publishing meeting2x =${meetingId} ${requesterUserId} ${requesterToken}`);
return Meetings.find({
meetingId,
@ -23,5 +23,5 @@ function publish(...args) {
return mapToAcl('subscriptions.meetings', boundMeetings)(args);
}
Meteor.publish('meetings', publish);
Meteor.publish('meetings2x', publish);

View File

@ -1,12 +0,0 @@
import { Meteor } from 'meteor/meteor';
const Meetings = new Mongo.Collection('meetings2x');
if (Meteor.isServer) {
// types of queries for the meetings:
// 1. meetingId
Meetings._ensureIndex({ meetingId: 1 });
}
export default Meetings;

View File

@ -1,12 +0,0 @@
import RedisPubSub from '/imports/startup/server/redis2x';
import handleMeetingCreation from './handlers/meetingCreation';
import handleGetAllMeetings from './handlers/getAllMeetings';
import handleMeetingEnd from './handlers/meetingEnd';
import handleMeetingLocksChange from './handlers/meetingLockChange';
import handleUserLockChange from './handlers/userLockChange';
RedisPubSub.on('MeetingCreatedEvtMsg', handleMeetingCreation);
RedisPubSub.on('SyncGetMeetingInfoRespMsg', handleGetAllMeetings);
RedisPubSub.on('MeetingEndingEvtMsg', handleMeetingEnd);
RedisPubSub.on('LockSettingsInMeetingChangedEvtMsg', handleMeetingLocksChange);
RedisPubSub.on('UserLockedInMeetingEvtMsg', handleUserLockChange);

View File

@ -1,5 +0,0 @@
import handleMeetingCreation from './meetingCreation';
export default function handleGetAllMeetings({ body }) {
return handleMeetingCreation({ body });
}

View File

@ -1,9 +0,0 @@
import { check } from 'meteor/check';
import addMeeting from '../modifiers/addMeeting';
export default function handleMeetingCreation({ body }) {
const meeting = body.props;
check(meeting, Object);
return addMeeting(meeting);
}

View File

@ -1,3 +0,0 @@
import './eventHandlers';
import './methods';
import './publishers';

View File

@ -1,7 +0,0 @@
import { Meteor } from 'meteor/meteor';
import mapToAcl from '/imports/startup/mapToAcl';
import endMeeting from './methods/endMeeting';
Meteor.methods(mapToAcl(['methods.endMeeting'], {
endMeeting,
}));

View File

@ -1,94 +0,0 @@
import flat from 'flat';
import { check } from 'meteor/check';
import Meetings from '/imports/api/2.0/meetings';
import Logger from '/imports/startup/server/logger';
import initializeCursor from '/imports/api/1.1/cursor/server/modifiers/initializeCursor';
export default function addMeeting(meeting) {
const meetingId = meeting.meetingProp.intId;
check(meetingId, String);
check(meeting, {
breakoutProps: {
sequence: Number,
breakoutRooms: Array,
parentId: String,
},
meetingProp: {
intId: String,
extId: String,
isBreakout: Boolean,
name: String,
},
usersProp: {
webcamsOnlyForModerator: Boolean,
guestPolicy: String,
maxUsers: Number,
},
durationProps: {
createdTime: Number,
duration: Number,
createdDate: String,
maxInactivityTimeoutMinutes: Number,
warnMinutesBeforeMax: Number,
meetingExpireIfNoUserJoinedInMinutes: Number,
meetingExpireWhenLastUserLeftInMinutes: Number,
},
welcomeProp: {
welcomeMsg: String,
modOnlyMessage: String,
welcomeMsgTemplate: String,
},
recordProp: {
allowStartStopRecording: Boolean,
autoStartRecording: Boolean,
record: Boolean,
},
password: {
viewerPass: String,
moderatorPass: String,
},
voiceProp: {
voiceConf: String,
dialNumber: String,
telVoice: String,
},
screenshareProps: {
red5ScreenshareIp: String,
red5ScreenshareApp: String,
screenshareConf: String,
},
metadataProp: Object,
});
const selector = {
meetingId,
};
const modifier = {
$set: Object.assign(
{ meetingId },
flat(meeting, { safe: true }),
),
};
const cb = (err, numChanged) => {
if (err) {
Logger.error(`Adding meeting to collection: ${err}`);
return;
}
initializeCursor(meetingId);
const { insertedId } = numChanged;
if (insertedId) {
Logger.info(`Added meeting2x id=${meetingId}`);
}
if (numChanged) {
Logger.info(`Upserted meeting2x id=${meetingId}`);
}
};
return Meetings.upsert(selector, modifier, cb);
}

View File

@ -1,30 +0,0 @@
import Meetings from '/imports/api/2.0/meetings';
import Logger from '/imports/startup/server/logger';
import clearUsers from '/imports/api/2.0/users/server/modifiers/clearUsers';
import clearChats from '/imports/api/2.0/chat/server/modifiers/clearChats';
import clearBreakouts from '/imports/api/2.0/breakouts/server/modifiers/clearBreakouts';
import clearAnnotations from '/imports/api/2.0/annotations/server/modifiers/clearAnnotations';
import clearSlides from '/imports/api/2.0/slides/server/modifiers/clearSlides';
import clearPolls from '/imports/api/2.0/polls/server/modifiers/clearPolls';
import clearCursor from '/imports/api/2.0/cursor/server/modifiers/clearCursor';
import clearCaptions from '/imports/api/2.0/captions/server/modifiers/clearCaptions';
import clearPresentations from '/imports/api/2.0/presentations/server/modifiers/clearPresentations';
import clearVoiceUsers from '/imports/api/2.0/voice-users/server/modifiers/clearVoiceUsers';
export default function removeMeeting(meetingId) {
return Meetings.remove({ meetingId }, () => {
clearCaptions(meetingId);
clearChats(meetingId);
clearCursor(meetingId);
clearPresentations(meetingId);
clearBreakouts(meetingId);
clearPolls(meetingId);
clearAnnotations(meetingId);
clearSlides(meetingId);
clearUsers(meetingId);
clearVoiceUsers(meetingId);
return Logger.info(`Cleared Meetings with id ${meetingId}`);
});
}

View File

@ -1,27 +0,0 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Meetings from '/imports/api/2.0/meetings';
import Logger from '/imports/startup/server/logger';
import mapToAcl from '/imports/startup/mapToAcl';
function meetings(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
check(requesterUserId, String);
check(requesterToken, String);
Logger.info(`Publishing meeting2x =${meetingId} ${requesterUserId} ${requesterToken}`);
return Meetings.find({
meetingId,
});
}
function publish(...args) {
const boundMeetings = meetings.bind(this);
return mapToAcl('subscriptions.meetings', boundMeetings)(args);
}
Meteor.publish('meetings2x', publish);