Multitab: Force sync at least every 500ms (#6914)

This commit is contained in:
zubiden 2026-05-05 13:46:25 +02:00 committed by Alexander Zinchuk
parent ee6f56ce7a
commit 0c32fede29
2 changed files with 46 additions and 19 deletions

View File

@ -379,9 +379,10 @@ export function sendApiMessage(
if (!chat) return undefined; if (!chat) return undefined;
// This is expected to arrive after `updateMessageSendSucceeded` which replaces the local ID, let isSendCompleted = false;
// so in most cases this will be simply ignored
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
if (isSendCompleted) return;
sendApiUpdate({ sendApiUpdate({
'@type': localMessage.isScheduled ? 'updateScheduledMessage' : 'updateMessage', '@type': localMessage.isScheduled ? 'updateScheduledMessage' : 'updateMessage',
id: localMessage.id, id: localMessage.id,
@ -392,6 +393,10 @@ export function sendApiMessage(
isFull: false, isFull: false,
}); });
}, FAST_SEND_TIMEOUT); }, FAST_SEND_TIMEOUT);
const cancelSendingStatusTimeout = () => {
isSendCompleted = true;
clearTimeout(timeout);
};
const randomId = generateRandomBigInt(); const randomId = generateRandomBigInt();
@ -408,7 +413,7 @@ export function sendApiMessage(
scheduledAt, scheduledAt,
scheduleRepeatPeriod, scheduleRepeatPeriod,
messagePriceInStars, messagePriceInStars,
}, randomId, localMessage, onProgress); }, randomId, localMessage, onProgress, cancelSendingStatusTimeout);
} }
const messagePromise = (async () => { const messagePromise = (async () => {
@ -564,8 +569,11 @@ export function sendApiMessage(
}); });
} }
cancelSendingStatusTimeout();
if (update) handleLocalMessageUpdate(localMessage, update); if (update) handleLocalMessageUpdate(localMessage, update);
} catch (error: any) { } catch (error: any) {
cancelSendingStatusTimeout();
if (error.errorMessage === 'PRIVACY_PREMIUM_REQUIRED') { if (error.errorMessage === 'PRIVACY_PREMIUM_REQUIRED') {
sendApiUpdate({ '@type': 'updateRequestUserUpdate', id: chat.id }); sendApiUpdate({ '@type': 'updateRequestUserUpdate', id: chat.id });
} }
@ -576,7 +584,6 @@ export function sendApiMessage(
localId: localMessage.id, localId: localMessage.id,
error: error.errorMessage, error: error.errorMessage,
}); });
clearTimeout(timeout);
} }
})(); })();
@ -595,6 +602,7 @@ const groupedUploads: Record<string, {
counter: number; counter: number;
singleMediaByIndex: Record<number, GramJs.InputSingleMedia>; singleMediaByIndex: Record<number, GramJs.InputSingleMedia>;
localMessages: Record<string, ApiMessage>; localMessages: Record<string, ApiMessage>;
cancelSendingStatusTimeouts: Record<string, NoneToVoidFunction>;
}> = {}; }> = {};
function sendGroupedMedia( function sendGroupedMedia(
@ -627,7 +635,8 @@ function sendGroupedMedia(
}, },
randomId: GramJs.long, randomId: GramJs.long,
localMessage: ApiMessage, localMessage: ApiMessage,
onProgress?: ApiOnProgress, onProgress: ApiOnProgress | undefined,
cancelSendingStatusTimeout: NoneToVoidFunction,
) { ) {
let groupIndex = -1; let groupIndex = -1;
if (!groupedUploads[groupedId]) { if (!groupedUploads[groupedId]) {
@ -635,6 +644,7 @@ function sendGroupedMedia(
counter: 0, counter: 0,
singleMediaByIndex: {}, singleMediaByIndex: {},
localMessages: {}, localMessages: {},
cancelSendingStatusTimeouts: {},
}; };
} }
@ -689,12 +699,13 @@ function sendGroupedMedia(
entities: entities ? entities.map(buildMtpMessageEntity) : undefined, entities: entities ? entities.map(buildMtpMessageEntity) : undefined,
}); });
groupedUploads[groupedId].localMessages[randomId.toString()] = localMessage; groupedUploads[groupedId].localMessages[randomId.toString()] = localMessage;
groupedUploads[groupedId].cancelSendingStatusTimeouts[randomId.toString()] = cancelSendingStatusTimeout;
if (Object.keys(groupedUploads[groupedId].singleMediaByIndex).length < groupedUploads[groupedId].counter) { if (Object.keys(groupedUploads[groupedId].singleMediaByIndex).length < groupedUploads[groupedId].counter) {
return; return;
} }
const { singleMediaByIndex, localMessages } = groupedUploads[groupedId]; const { singleMediaByIndex, localMessages, cancelSendingStatusTimeouts } = groupedUploads[groupedId];
delete groupedUploads[groupedId]; delete groupedUploads[groupedId];
const count = Object.values(singleMediaByIndex).length; const count = Object.values(singleMediaByIndex).length;
@ -713,7 +724,10 @@ function sendGroupedMedia(
shouldIgnoreUpdates: true, shouldIgnoreUpdates: true,
}); });
if (update) handleMultipleLocalMessagesUpdate(localMessages, update); if (!update) return;
Object.values(cancelSendingStatusTimeouts).forEach((cancel) => cancel());
handleMultipleLocalMessagesUpdate(localMessages, update);
})(); })();
return mediaQueue; return mediaQueue;

View File

@ -94,6 +94,7 @@ type BroadcastChannelInitApi = {
}; };
const MULTITAB_ESTABLISH_TIMEOUT = 800; const MULTITAB_ESTABLISH_TIMEOUT = 800;
const BROADCAST_DIFF_FALLBACK_TIMEOUT = 500;
export type TypedBroadcastChannel = { export type TypedBroadcastChannel = {
postMessage: (message: BroadcastChannelMessage) => void; postMessage: (message: BroadcastChannelMessage) => void;
@ -117,6 +118,28 @@ const channel = new BroadcastChannel(DATA_BROADCAST_CHANNEL_NAME) as TypedBroadc
let isBroadcastDiffScheduled = false; let isBroadcastDiffScheduled = false;
let lastBroadcastDiffGlobal: GlobalState | undefined; let lastBroadcastDiffGlobal: GlobalState | undefined;
let broadcastDiffFallbackTimeout: number | undefined;
function flushBroadcastDiff() {
if (!isBroadcastDiffScheduled) return;
if (broadcastDiffFallbackTimeout) {
clearTimeout(broadcastDiffFallbackTimeout);
broadcastDiffFallbackTimeout = undefined;
}
const diff = deepDiff(lastBroadcastDiffGlobal, currentGlobal);
if (typeof diff !== 'symbol') {
channel.postMessage({
type: 'globalDiffUpdate',
diff,
});
}
isBroadcastDiffScheduled = false;
lastBroadcastDiffGlobal = undefined;
}
function broadcastDiffOnIdle() { function broadcastDiffOnIdle() {
if (isBroadcastDiffScheduled) return; if (isBroadcastDiffScheduled) return;
@ -124,18 +147,8 @@ function broadcastDiffOnIdle() {
isBroadcastDiffScheduled = true; isBroadcastDiffScheduled = true;
lastBroadcastDiffGlobal = currentGlobal; lastBroadcastDiffGlobal = currentGlobal;
onFullyIdle(() => { onFullyIdle(flushBroadcastDiff);
const diff = deepDiff(lastBroadcastDiffGlobal, currentGlobal); broadcastDiffFallbackTimeout = window.setTimeout(flushBroadcastDiff, BROADCAST_DIFF_FALLBACK_TIMEOUT);
if (typeof diff !== 'symbol') {
channel.postMessage({
type: 'globalDiffUpdate',
diff,
});
}
isBroadcastDiffScheduled = false;
});
} }
export function unsubcribeFromMultitabBroadcastChannel() { export function unsubcribeFromMultitabBroadcastChannel() {