bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js

136 lines
4.3 KiB
JavaScript
Raw Normal View History

import Presentations from '/imports/api/presentations';
2017-05-04 00:36:16 +08:00
import Auth from '/imports/ui/services/auth';
2017-09-27 03:45:33 +08:00
import { makeCall } from '/imports/ui/services/api';
2017-05-04 00:36:16 +08:00
2017-09-27 03:45:33 +08:00
const CONVERSION_TIMEOUT = 300000;
// fetch doens't support progress. So we use xhr which support progress.
2017-09-08 02:18:14 +08:00
const futch = (url, opts = {}, onProgress) => new Promise((res, rej) => {
const xhr = new XMLHttpRequest();
xhr.open(opts.method || 'get', url);
Object.keys(opts.headers || {})
.forEach(k => xhr.setRequestHeader(k, opts.headers[k]));
xhr.onload = (e) => {
if (e.target.status !== 200) {
return rej({ code: e.target.status, message: e.target.statusText });
}
return res(e.target.responseText);
};
xhr.onerror = rej;
if (xhr.upload && onProgress) {
xhr.upload.addEventListener('progress', onProgress, false);
}
xhr.send(opts.body);
});
2017-05-04 00:36:16 +08:00
const getPresentations = () =>
Presentations
.find()
.fetch()
2017-09-08 02:18:14 +08:00
.map(presentation => ({
2017-09-27 03:45:33 +08:00
id: presentation.id,
2017-09-08 02:18:14 +08:00
filename: presentation.name,
isCurrent: presentation.current || false,
2017-09-08 02:18:14 +08:00
upload: { done: true, error: false },
conversion: presentation.conversion || { done: true, error: false },
2017-05-04 00:36:16 +08:00
}));
2017-09-27 03:45:33 +08:00
const observePresentationConversion = (meetingId, filename) => new Promise((resolve, reject) => {
const conversionTimeout = setTimeout(() => {
reject({
filename,
message: 'Conversion timeout.',
});
}, CONVERSION_TIMEOUT);
const didValidate = (doc) => {
2017-09-27 03:45:33 +08:00
clearTimeout(conversionTimeout);
resolve(doc);
2017-09-27 03:45:33 +08:00
};
Tracker.autorun((c) => {
/* FIXME: With two presentations with the same name this will not work as expected */
const query = Presentations.find({ meetingId });
2017-09-27 03:45:33 +08:00
query.observe({
changed: (newDoc) => {
if (newDoc.name !== filename) return;
if (newDoc.conversion.done) {
2017-09-27 03:45:33 +08:00
c.stop();
didValidate(newDoc);
2017-09-27 03:45:33 +08:00
}
},
});
});
});
const uploadAndConvertPresentation = (file, meetingID, endpoint, onError, onProgress) => {
const data = new FormData();
data.append('presentation_name', file.name);
data.append('Filename', file.name);
2017-05-04 00:36:16 +08:00
data.append('fileUpload', file);
data.append('conference', meetingID);
data.append('room', meetingID);
2017-09-23 04:45:31 +08:00
// TODO: Theres no way to set a presentation as downloadable.
data.append('is_downloadable', false);
2017-05-04 00:36:16 +08:00
2017-09-08 02:18:14 +08:00
const opts = {
2017-05-04 00:36:16 +08:00
method: 'POST',
body: data,
2017-09-08 02:18:14 +08:00
};
2017-09-27 03:45:33 +08:00
return futch(endpoint, opts, onProgress)
.then(() => observePresentationConversion(meetingID, file.name))
2017-09-27 03:45:33 +08:00
// Trap the error so we can have parallel upload
.catch((error) => {
onError(error);
return observePresentationConversion(meetingID, file.name);
2017-09-27 03:45:33 +08:00
});
2017-05-04 00:36:16 +08:00
};
const uploadAndConvertPresentations = (presentationsToUpload, meetingID, uploadEndpoint) =>
2017-05-04 04:51:17 +08:00
Promise.all(
presentationsToUpload.map(p =>
uploadAndConvertPresentation(p.file, meetingID, uploadEndpoint, p.onError, p.onProgress)),
2017-05-04 04:51:17 +08:00
);
const setPresentation = presentationID => makeCall('setPresentation', presentationID);
2017-09-27 03:45:33 +08:00
const removePresentation = presentationID => makeCall('removePresentation', presentationID);
2017-05-04 04:51:17 +08:00
const removePresentations = presentationsToRemove =>
Promise.all(presentationsToRemove.map(p => removePresentation(p.id)));
2017-05-04 00:36:16 +08:00
const persistPresentationChanges = (oldState, newState, uploadEndpoint) => {
const presentationsToUpload = newState.filter(_ => !oldState.includes(_));
2017-05-04 04:51:17 +08:00
const presentationsToRemove = oldState.filter(_ => !newState.includes(_));
const currentPresentation = newState.find(_ => _.isCurrent);
2017-05-04 00:36:16 +08:00
return new Promise((resolve, reject) =>
uploadAndConvertPresentations(presentationsToUpload, Auth.meetingID, uploadEndpoint)
.then((presentations) => {
if (!presentations.length && !currentPresentation) return Promise.resolve();
// If its a newly uploaded presentation we need to get its id from promise result
const currentPresentationId =
currentPresentation.id !== currentPresentation.filename ?
currentPresentation.id :
presentations[presentationsToUpload.findIndex(_ => _ === currentPresentation)].id;
return setPresentation(currentPresentationId);
})
2017-09-23 04:45:31 +08:00
.then(removePresentations.bind(null, presentationsToRemove))
.then(resolve)
.catch(reject),
2017-05-04 00:36:16 +08:00
);
};
export default {
getPresentations,
persistPresentationChanges,
};