From c6067dbccb988e76e6214acd78f89aca8532dda0 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 19 Oct 2021 11:25:43 -0500 Subject: [PATCH 1/2] v2 Media API: poll attachments for completion https://github.com/mastodon/mastodon/pull/13210 --- app/soapbox/actions/compose.js | 30 ++++++++++++++++++++++++------ app/soapbox/actions/media.js | 12 ++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/app/soapbox/actions/compose.js b/app/soapbox/actions/compose.js index c63069757..11d842315 100644 --- a/app/soapbox/actions/compose.js +++ b/app/soapbox/actions/compose.js @@ -11,7 +11,7 @@ import { defineMessages } from 'react-intl'; import { openModal, closeModal } from './modal'; import { getSettings } from './settings'; import { getFeatures } from 'soapbox/utils/features'; -import { uploadMedia } from './media'; +import { uploadMedia, fetchMedia, updateMedia } from './media'; import { isLoggedIn } from 'soapbox/utils/auth'; import { createStatus } from './statuses'; import snackbar from 'soapbox/actions/snackbar'; @@ -249,13 +249,14 @@ export function submitComposeFail(error) { export function uploadCompose(files) { return function(dispatch, getState) { if (!isLoggedIn(getState)) return; - const uploadLimit = getFeatures(getState().get('instance')).attachmentLimit; + const instance = getState().get('instance'); + const { attachmentLimit } = getFeatures(instance); const media = getState().getIn(['compose', 'media_attachments']); const progress = new Array(files.length).fill(0); let total = Array.from(files).reduce((a, v) => a + v.size, 0); - if (files.length + media.size > uploadLimit) { + if (files.length + media.size > attachmentLimit) { dispatch(showAlert(undefined, messages.uploadErrorLimit, 'error')); return; } @@ -263,7 +264,7 @@ export function uploadCompose(files) { dispatch(uploadComposeRequest()); for (const [i, f] of Array.from(files).entries()) { - if (media.size + i > uploadLimit - 1) break; + if (media.size + i > attachmentLimit - 1) break; // FIXME: Don't define function in loop /* eslint-disable no-loop-func */ @@ -279,8 +280,25 @@ export function uploadCompose(files) { }; return dispatch(uploadMedia(data, onUploadProgress)) - .then(({ data }) => dispatch(uploadComposeSuccess(data))); + .then(({ status, data }) => { + // If server-side processing of the media attachment has not completed yet, + // poll the server until it is, before showing the media attachment as uploaded + if (status === 200) { + dispatch(uploadComposeSuccess(data, f)); + } else if (status === 202) { + const poll = () => { + dispatch(fetchMedia(data.id)).then(({ status, data }) => { + if (status === 200) { + dispatch(uploadComposeSuccess(data, f)); + } else if (status === 206) { + setTimeout(() => poll(), 1000); + } + }).catch(error => dispatch(uploadComposeFail(error))); + }; + poll(); + } + }); }).catch(error => dispatch(uploadComposeFail(error))); /* eslint-enable no-loop-func */ } @@ -293,7 +311,7 @@ export function changeUploadCompose(id, params) { dispatch(changeUploadComposeRequest()); - api(getState).put(`/api/v1/media/${id}`, params).then(response => { + dispatch(updateMedia(id, params)).then(response => { dispatch(changeUploadComposeSuccess(response.data)); }).catch(error => { dispatch(changeUploadComposeFail(id, error)); diff --git a/app/soapbox/actions/media.js b/app/soapbox/actions/media.js index 1d5a540ce..3c71c91a4 100644 --- a/app/soapbox/actions/media.js +++ b/app/soapbox/actions/media.js @@ -3,6 +3,18 @@ import { getFeatures } from 'soapbox/utils/features'; const noOp = () => {}; +export function fetchMedia(mediaId) { + return (dispatch, getState) => { + return api(getState).get(`/api/v1/media/${mediaId}`); + }; +} + +export function updateMedia(mediaId, params) { + return (dispatch, getState) => { + return api(getState).put(`/api/v1/media/${mediaId}`, params); + }; +} + export function uploadMediaV1(data, onUploadProgress = noOp) { return (dispatch, getState) => { return api(getState).post('/api/v1/media', data, { From 343a210d968ef2e7c86642a582b2f0dbc9ae1538 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 19 Oct 2021 11:28:48 -0500 Subject: [PATCH 2/2] v2 Media API: disable for Pleroma (use v1) --- app/soapbox/utils/features.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/soapbox/utils/features.js b/app/soapbox/utils/features.js index f81a87d65..058eeec5b 100644 --- a/app/soapbox/utils/features.js +++ b/app/soapbox/utils/features.js @@ -29,7 +29,8 @@ export const getFeatures = createSelector([ trends: v.software === MASTODON && gte(v.compatVersion, '3.0.0'), mediaV2: any([ v.software === MASTODON && gte(v.compatVersion, '3.1.3'), - v.software === PLEROMA && gte(v.version, '2.1.0'), + // Even though Pleroma supports these endpoints, it has disadvantages + // v.software === PLEROMA && gte(v.version, '2.1.0'), ]), directTimeline: any([ v.software === MASTODON && lt(v.compatVersion, '3.0.0'),