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 }; return { type: ACCOUNTS_IMPORT, accounts };
} }
export function importStatus(status) { export function importStatus(status, idempotencyKey) {
return { type: STATUS_IMPORT, status }; return { type: STATUS_IMPORT, status, idempotencyKey };
} }
export function importStatuses(statuses) { export function importStatuses(statuses) {
@ -60,8 +60,27 @@ export function importFetchedAccounts(accounts) {
return importAccounts(normalAccounts); return importAccounts(normalAccounts);
} }
export function importFetchedStatus(status) { export function importFetchedStatus(status, idempotencyKey) {
return importFetchedStatuses([status]); 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, // 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, { return api(getState).post('/api/v1/statuses', params, {
headers: { 'Idempotency-Key': idempotencyKey }, headers: { 'Idempotency-Key': idempotencyKey },
}).then(({ data: status }) => { }).then(({ data: status }) => {
dispatch(importFetchedStatus(status)); dispatch(importFetchedStatus(status, idempotencyKey));
dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey }); dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey });
return status; return status;
}).catch(error => { }).catch(error => {

View File

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

View File

@ -16,7 +16,8 @@ const initialState = ImmutableMap({
replies: 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; if (!in_reply_to_id) return state;
return state.withMutations(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 => { state.updateIn(['replies', in_reply_to_id], ImmutableOrderedSet(), ids => {
return ids.add(id).sort(); 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: case STATUS_CREATE_SUCCESS:
return deletePendingStatus(state, action.status, action.idempotencyKey); return deletePendingStatus(state, action.status, action.idempotencyKey);
case STATUS_IMPORT: case STATUS_IMPORT:
return importStatus(state, action.status); return importStatus(state, action.status, action.idempotencyKey);
case STATUSES_IMPORT: case STATUSES_IMPORT:
return importStatuses(state, action.statuses); return importStatuses(state, action.statuses);
default: default: