Optimistic replies: fix duplicated statuses

This commit is contained in:
Alex Gleason 2021-10-09 21:12:21 -05:00
parent 03dbd5bfd2
commit 135b4c4d7b
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
4 changed files with 33 additions and 9 deletions

View file

@ -26,8 +26,8 @@ export function importAccounts(accounts) {
return { type: ACCOUNTS_IMPORT, accounts };
}
export function importStatus(status) {
return { type: STATUS_IMPORT, status };
export function importStatus(status, idempotencyKey) {
return { type: STATUS_IMPORT, status, idempotencyKey };
}
export function importStatuses(statuses) {
@ -60,8 +60,27 @@ export function importFetchedAccounts(accounts) {
return importAccounts(normalAccounts);
}
export function importFetchedStatus(status) {
return importFetchedStatuses([status]);
export function importFetchedStatus(status, idempotencyKey) {
return (dispatch, getState) => {
// Skip broken statuses
if (isBroken(status)) return;
const normalOldStatus = getState().getIn(['statuses', status.id]);
const expandSpoilers = getSettings(getState()).get('expandSpoilers');
const normalizedStatus = normalizeStatus(status, normalOldStatus, expandSpoilers);
dispatch(importStatus(normalizedStatus, idempotencyKey));
dispatch(importFetchedAccount(status.account));
if (status.reblog && status.reblog.id) {
dispatch(importFetchedStatus(status.reblog));
}
if (status.poll && status.poll.id) {
dispatch(importFetchedPoll(status.poll));
}
};
}
// Sometimes Pleroma can return an empty account,

View file

@ -48,7 +48,7 @@ export function createStatus(params, idempotencyKey) {
return api(getState).post('/api/v1/statuses', params, {
headers: { 'Idempotency-Key': idempotencyKey },
}).then(({ data: status }) => {
dispatch(importFetchedStatus(status));
dispatch(importFetchedStatus(status, idempotencyKey));
dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey });
return status;
}).catch(error => {

View file

@ -29,8 +29,6 @@ export function processTimelineUpdate(timeline, status, accept) {
const columnSettings = getSettings(getState()).get(timeline, ImmutableMap());
const shouldSkipQueue = shouldFilter(fromJS(status), columnSettings);
dispatch(importFetchedStatus(status));
if (ownStatus && hasPendingStatuses) {
// WebSockets push statuses without the Idempotency-Key,
// so if we have pending statuses, don't import it from here.
@ -38,6 +36,8 @@ export function processTimelineUpdate(timeline, status, accept) {
return;
}
dispatch(importFetchedStatus(status));
if (shouldSkipQueue) {
dispatch(updateTimeline(timeline, status.id, accept));
} else {

View file

@ -16,7 +16,8 @@ const initialState = ImmutableMap({
replies: ImmutableMap(),
});
const importStatus = (state, { id, in_reply_to_id }) => {
const importStatus = (state, status, idempotencyKey) => {
const { id, in_reply_to_id } = status;
if (!in_reply_to_id) return state;
return state.withMutations(state => {
@ -25,6 +26,10 @@ const importStatus = (state, { id, in_reply_to_id }) => {
state.updateIn(['replies', in_reply_to_id], ImmutableOrderedSet(), ids => {
return ids.add(id).sort();
});
if (idempotencyKey) {
deletePendingStatus(state, status, idempotencyKey);
}
});
};
@ -129,7 +134,7 @@ export default function replies(state = initialState, action) {
case STATUS_CREATE_SUCCESS:
return deletePendingStatus(state, action.status, action.idempotencyKey);
case STATUS_IMPORT:
return importStatus(state, action.status);
return importStatus(state, action.status, action.idempotencyKey);
case STATUSES_IMPORT:
return importStatuses(state, action.statuses);
default: