2017-10-12 10:00:28 +08:00
|
|
|
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-11-28 20:26:00 +08:00
|
|
|
import _ from 'lodash';
|
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
|
2017-11-28 20:26:00 +08:00
|
|
|
.find({
|
|
|
|
'conversion.error': false,
|
|
|
|
})
|
2017-05-04 00:36:16 +08:00
|
|
|
.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,
|
2017-09-26 04:49:54 +08:00
|
|
|
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-11-28 01:44:45 +08:00
|
|
|
const observePresentationConversion = (meetingId, filename, onConversion) =>
|
|
|
|
new Promise((resolve) => {
|
|
|
|
const conversionTimeout = setTimeout(() => {
|
|
|
|
onConversion({
|
|
|
|
done: true,
|
|
|
|
error: true,
|
|
|
|
status: 'TIMEOUT',
|
|
|
|
});
|
|
|
|
}, CONVERSION_TIMEOUT);
|
|
|
|
|
|
|
|
const didValidate = (doc) => {
|
|
|
|
clearTimeout(conversionTimeout);
|
|
|
|
resolve(doc);
|
|
|
|
};
|
|
|
|
|
|
|
|
Tracker.autorun((c) => {
|
|
|
|
const query = Presentations.find({ meetingId });
|
2017-09-27 03:45:33 +08:00
|
|
|
|
2017-11-28 01:44:45 +08:00
|
|
|
query.observe({
|
|
|
|
changed: (newDoc) => {
|
|
|
|
if (newDoc.name !== filename) return;
|
2017-09-27 03:45:33 +08:00
|
|
|
|
2017-11-28 01:44:45 +08:00
|
|
|
onConversion(newDoc.conversion);
|
|
|
|
|
|
|
|
if (newDoc.conversion.done) {
|
|
|
|
c.stop();
|
|
|
|
didValidate(newDoc);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
2017-09-27 03:45:33 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-11-28 01:44:45 +08:00
|
|
|
const uploadAndConvertPresentation = (file, meetingID, endpoint, onUpload, onProgress, onConversion) => {
|
2017-06-07 20:28:41 +08:00
|
|
|
const data = new FormData();
|
2017-09-30 01:44:18 +08:00
|
|
|
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)
|
2017-11-28 01:44:45 +08:00
|
|
|
.then(() => observePresentationConversion(meetingID, file.name, onConversion))
|
2017-09-27 03:45:33 +08:00
|
|
|
// Trap the error so we can have parallel upload
|
|
|
|
.catch((error) => {
|
2017-11-28 01:44:45 +08:00
|
|
|
onUpload({ error: true, done: true, status: error.code });
|
|
|
|
return Promise.resolve();
|
2017-09-27 03:45:33 +08:00
|
|
|
});
|
2017-05-04 00:36:16 +08:00
|
|
|
};
|
|
|
|
|
2017-09-30 01:44:18 +08:00
|
|
|
const uploadAndConvertPresentations = (presentationsToUpload, meetingID, uploadEndpoint) =>
|
2017-11-28 01:44:45 +08:00
|
|
|
Promise.all(presentationsToUpload.map(p =>
|
|
|
|
uploadAndConvertPresentation(p.file, meetingID, uploadEndpoint, p.onUpload, p.onProgress, p.onConversion)));
|
2017-05-04 04:51:17 +08:00
|
|
|
|
2017-09-30 01:44:18 +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) => {
|
2017-11-28 20:26:00 +08:00
|
|
|
const presentationsToUpload = newState.filter(p => !p.upload.done);
|
|
|
|
const presentationsToRemove = oldState.filter(p => !_.find(newState, ['id', p.id]));
|
|
|
|
|
|
|
|
let currentPresentation = newState.find(p => p.isCurrent);
|
2017-11-28 01:44:45 +08:00
|
|
|
|
|
|
|
return uploadAndConvertPresentations(presentationsToUpload, Auth.meetingID, uploadEndpoint)
|
|
|
|
.then((presentations) => {
|
|
|
|
if (!presentations.length && !currentPresentation) return Promise.resolve();
|
|
|
|
|
|
|
|
// Update the presentation with their new ids
|
|
|
|
presentations.forEach((p, i) => {
|
|
|
|
if (p === undefined) return;
|
|
|
|
presentationsToUpload[i].onDone(p.id);
|
|
|
|
});
|
|
|
|
|
|
|
|
return Promise.resolve(presentations);
|
|
|
|
})
|
|
|
|
.then((presentations) => {
|
2017-12-16 02:49:47 +08:00
|
|
|
if (currentPresentation === undefined) {
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
2017-11-28 01:44:45 +08:00
|
|
|
// If its a newly uploaded presentation we need to get it from promise result
|
|
|
|
if (!currentPresentation.conversion.done) {
|
|
|
|
const currentIndex = presentationsToUpload.findIndex(p => p === currentPresentation);
|
|
|
|
currentPresentation = presentations[currentIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip setting as current if error happened
|
2017-12-16 02:49:47 +08:00
|
|
|
if (currentPresentation.conversion.error) {
|
2017-11-28 01:44:45 +08:00
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
return setPresentation(currentPresentation.id);
|
|
|
|
})
|
|
|
|
.then(removePresentations.bind(null, presentationsToRemove));
|
2017-05-04 00:36:16 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
export default {
|
|
|
|
getPresentations,
|
|
|
|
persistPresentationChanges,
|
|
|
|
};
|