Update Manager: Various fixes

This commit is contained in:
Alexander Zinchuk 2023-07-27 11:48:11 +02:00
parent 5c52c1ea5c
commit 38b0336bdb
11 changed files with 105 additions and 24 deletions

View File

@ -30,7 +30,12 @@ import {
} from '../helpers';
import { ChatAbortController } from '../ChatAbortController';
import {
updateChannelState, getDifference, init as initUpdatesManager, processUpdate, reset as resetUpdatesManager,
updateChannelState,
getDifference,
init as initUpdatesManager,
processUpdate,
reset as resetUpdatesManager,
scheduleGetChannelDifference,
} from '../updateManager';
const DEFAULT_USER_AGENT = 'Unknown UserAgent';
@ -482,3 +487,7 @@ export function setAllowHttpTransport(allowHttpTransport: boolean) {
export function setShouldDebugExportedSenders(value: boolean) {
client.setShouldDebugExportedSenders(value);
}
export function requestChannelDifference(channelId: string) {
scheduleGetChannelDifference(channelId);
}

View File

@ -1,6 +1,6 @@
export {
destroy, disconnect, downloadMedia, fetchCurrentUser, repairFileReference, abortChatRequests, abortRequestGroup,
setForceHttpTransport, setShouldDebugExportedSenders, setAllowHttpTransport,
setForceHttpTransport, setShouldDebugExportedSenders, setAllowHttpTransport, requestChannelDifference,
} from './client';
export {

View File

@ -6,7 +6,7 @@ import { UpdateConnectionState, UpdateServerTimeOffset } from '../../lib/gramjs/
import { DEBUG } from '../../config';
import localDb from './localDb';
import SortedQueue from '../../util/SortedQueue';
import { dispatchUserAndChatUpdates, requestSync, updater } from './updater';
import { dispatchUserAndChatUpdates, sendUpdate, updater } from './updater';
import { addEntitiesToLocalDb } from './helpers';
import { buildInputEntity } from './gramjsBuilders';
import { buildApiPeerId } from './apiBuilders/peers';
@ -17,8 +17,8 @@ export type State = {
pts: number;
qts: number;
};
type SeqUpdate = GramJs.Updates | GramJs.UpdatesCombined;
type PtsUpdate = GramJs.TypeUpdate & { pts: number };
type SeqUpdate = (GramJs.Updates | GramJs.UpdatesCombined) & { _isFromDifference?: true };
type PtsUpdate = GramJs.TypeUpdate & { pts: number } & { _isFromDifference?: true };
const COMMON_BOX_QUEUE_ID = '0';
const CHANNEL_DIFFERENCE_LIMIT = 1000;
@ -49,7 +49,7 @@ export function applyState(state: State) {
localDb.commonBoxState.qts = state.qts;
}
export function processUpdate(update: Update) {
export function processUpdate(update: Update, isFromDifference?: boolean) {
if (update instanceof UpdateConnectionState) {
if (update.state === UpdateConnectionState.connected && isInited) {
scheduleGetDifference();
@ -70,6 +70,11 @@ export function processUpdate(update: Update) {
}
if (update instanceof GramJs.Updates || update instanceof GramJs.UpdatesCombined) {
if (isFromDifference) {
// eslint-disable-next-line no-underscore-dangle
(update as SeqUpdate)._isFromDifference = true;
}
saveSeqUpdate(update);
return;
}
@ -79,6 +84,10 @@ export function processUpdate(update: Update) {
getChannelDifference(getUpdateChannelId(update));
return;
}
if (isFromDifference) {
// eslint-disable-next-line no-underscore-dangle
(update as PtsUpdate)._isFromDifference = true;
}
savePtsUpdate(update);
return;
}
@ -165,7 +174,8 @@ function popSeqQueue() {
const localSeq = localDb.commonBoxState.seq;
const seqStart = 'seqStart' in update ? update.seqStart : update.seq;
if (seqStart === 0) {
// eslint-disable-next-line no-underscore-dangle
if (seqStart === 0 || (update._isFromDifference && seqStart >= localSeq + 1)) {
applyUpdate(update);
} else if (seqStart === localSeq + 1) {
clearTimeout(seqTimeout);
@ -198,7 +208,10 @@ function popPtsQueue(channelId: string) {
return;
}
if (pts === localPts + ptsCount) {
// eslint-disable-next-line no-underscore-dangle
if (update._isFromDifference && pts >= localPts + ptsCount) {
applyUpdate(update);
} else if (pts === localPts + ptsCount) {
clearTimeout(PTS_TIMEOUTS.get(channelId));
PTS_TIMEOUTS.delete(channelId);
@ -216,7 +229,7 @@ function popPtsQueue(channelId: string) {
popPtsQueue(channelId);
}
function scheduleGetChannelDifference(channelId: string) {
export function scheduleGetChannelDifference(channelId: string) {
if (PTS_TIMEOUTS.has(channelId)) return;
const timeout = setTimeout(async () => {
@ -258,6 +271,11 @@ export async function getDifference() {
return;
}
sendUpdate({
'@type': 'updateFetchingDifference',
isFetching: true,
});
const response = await invoke(new GramJs.updates.GetDifference({
pts: localDb.commonBoxState.pts,
date: localDb.commonBoxState.date,
@ -275,6 +293,10 @@ export async function getDifference() {
if (response instanceof GramJs.updates.DifferenceEmpty) {
localDb.commonBoxState.seq = response.seq;
localDb.commonBoxState.date = response.date;
sendUpdate({
'@type': 'updateFetchingDifference',
isFetching: false,
});
return;
}
@ -285,7 +307,13 @@ export async function getDifference() {
if (response instanceof GramJs.updates.DifferenceSlice) {
getDifference();
return;
}
sendUpdate({
'@type': 'updateFetchingDifference',
isFetching: false,
});
}
async function getChannelDifference(channelId: string) {
@ -336,7 +364,9 @@ async function getChannelDifference(channelId: string) {
function forceSync() {
reset();
requestSync();
sendUpdate({
'@type': 'requestSync',
});
loadRemoteState();
}
@ -389,7 +419,7 @@ function processDifference(
dispatchUserAndChatUpdates(difference.chats);
difference.otherUpdates.forEach((update) => {
processUpdate(update);
processUpdate(update, true);
});
}

View File

@ -1,7 +1,7 @@
import type { GroupCallConnectionData } from '../../lib/secret-sauce';
import { Api as GramJs, connection } from '../../lib/gramjs';
import type {
ApiMessage, ApiMessageExtendedMediaPreview, ApiUpdateConnectionStateType, OnApiUpdate,
ApiMessage, ApiMessageExtendedMediaPreview, ApiUpdate, ApiUpdateConnectionStateType, OnApiUpdate,
} from '../types';
import { DEBUG, GENERAL_TOPIC_ID } from '../../config';
@ -117,10 +117,8 @@ export function dispatchUserAndChatUpdates(entities: (GramJs.TypeUser | GramJs.T
});
}
export function requestSync() {
onUpdate({
'@type': 'requestSync',
});
export function sendUpdate(update: ApiUpdate) {
onUpdate(update);
}
export function updater(update: Update) {

View File

@ -615,6 +615,11 @@ export type ApiUpdateMessageTranslations = {
toLanguageCode: string;
};
export type ApiUpdateFetchingDifference = {
'@type': 'updateFetchingDifference';
isFetching: boolean;
};
export type ApiRequestReconnectApi = {
'@type': 'requestReconnectApi';
};
@ -649,7 +654,7 @@ export type ApiUpdate = (
ApiUpdatePhoneCallConnectionState | ApiUpdateBotMenuButton | ApiUpdateTranscribedAudio | ApiUpdateUserEmojiStatus |
ApiUpdateMessageExtendedMedia | ApiUpdateConfig | ApiUpdateTopicNotifyExceptions | ApiUpdatePinnedTopic |
ApiUpdatePinnedTopicsOrder | ApiUpdateTopic | ApiUpdateTopics | ApiUpdateRecentEmojiStatuses |
ApiUpdateRecentReactions | ApiRequestReconnectApi | ApiRequestSync
ApiUpdateRecentReactions | ApiRequestReconnectApi | ApiRequestSync | ApiUpdateFetchingDifference
);
export type OnApiUpdate = (update: ApiUpdate) => void;

View File

@ -93,7 +93,7 @@ type StateProps =
hasPasscode?: boolean;
canSetPasscode?: boolean;
}
& Pick<GlobalState, 'connectionState' | 'isSyncing' | 'archiveSettings'>
& Pick<GlobalState, 'connectionState' | 'isSyncing' | 'isFetchingDifference' | 'archiveSettings'>
& Pick<TabState, 'canInstall'>;
const CLEAR_DATE_SEARCH_PARAM = { date: undefined };
@ -121,6 +121,7 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
animationLevel,
connectionState,
isSyncing,
isFetchingDifference,
isMessageListOpen,
isConnectionStatusMinimized,
areChatsLoaded,
@ -154,7 +155,12 @@ const LeftMainHeader: FC<OwnProps & StateProps> = ({
const archivedUnreadChatsCount = useFolderManagerForUnreadCounters()[ARCHIVED_FOLDER_ID]?.chatsCount || 0;
const { connectionStatus, connectionStatusText, connectionStatusPosition } = useConnectionStatus(
lang, connectionState, isSyncing, isMessageListOpen, isConnectionStatusMinimized, !areChatsLoaded,
lang,
connectionState,
isSyncing || isFetchingDifference,
isMessageListOpen,
isConnectionStatusMinimized,
!areChatsLoaded,
);
const handleLockScreenHotkey = useLastCallback((e: KeyboardEvent) => {
@ -485,7 +491,7 @@ export default memo(withGlobal<OwnProps>(
query: searchQuery, fetchingStatus, chatId, date,
} = tabState.globalSearch;
const {
currentUserId, connectionState, isSyncing, archiveSettings,
currentUserId, connectionState, isSyncing, archiveSettings, isFetchingDifference,
} = global;
const { isConnectionStatusMinimized, animationLevel } = global.settings.byKey;
@ -499,6 +505,7 @@ export default memo(withGlobal<OwnProps>(
animationLevel,
connectionState,
isSyncing,
isFetchingDifference,
isMessageListOpen: Boolean(selectCurrentMessageList(global)),
isConnectionStatusMinimized,
isCurrentUserPremium: selectIsCurrentUserPremium(global),

View File

@ -105,7 +105,8 @@ type StateProps = {
shouldSkipHistoryAnimations?: boolean;
currentTransitionKey: number;
connectionState?: GlobalState['connectionState'];
isSyncing?: GlobalState['isSyncing'];
isSyncing?: boolean;
isFetchingDifference?: boolean;
};
const MiddleHeader: FC<OwnProps & StateProps> = ({
@ -132,6 +133,7 @@ const MiddleHeader: FC<OwnProps & StateProps> = ({
currentTransitionKey,
connectionState,
isSyncing,
isFetchingDifference,
getCurrentPinnedIndexes,
getLoadingPinnedId,
onFocusPinnedMessage,
@ -319,7 +321,7 @@ const MiddleHeader: FC<OwnProps & StateProps> = ({
}
}, [shouldUseStackedToolsClass, canRevealTools, canToolsCollideWithChatInfo, isRightColumnShown]);
const { connectionStatusText } = useConnectionStatus(lang, connectionState, isSyncing, true);
const { connectionStatusText } = useConnectionStatus(lang, connectionState, isSyncing || isFetchingDifference, true);
function renderInfo() {
if (messageListType === 'thread') {
@ -524,6 +526,7 @@ export default memo(withGlobal<OwnProps>(
currentTransitionKey: Math.max(0, messageLists.length - 1),
connectionState: global.connectionState,
isSyncing: global.isSyncing,
isFetchingDifference: global.isFetchingDifference,
hasButtonInHeader: canStartBot || canRestartBot || canSubscribe || shouldSendJoinRequest,
};

View File

@ -179,6 +179,12 @@ addActionHandler('signOut', async (global, actions, payload): Promise<void> => {
}
});
addActionHandler('requestChannelDifference', (global, actions, payload): ActionReturnType => {
const { chatId } = payload;
void callApi('requestChannelDifference', chatId);
});
addActionHandler('reset', (global, actions): ActionReturnType => {
clearStoredSession();
clearEncryptedSession();

View File

@ -23,6 +23,8 @@ import { clearWebTokenAuth } from '../../../util/routing';
import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { updateTabState } from '../../reducers/tabs';
import { setServerTimeOffset } from '../../../util/serverTime';
import { isChatChannel, isChatSuperGroup } from '../../helpers';
import { unique } from '../../../util/iteratees';
addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
switch (update['@type']) {
@ -59,7 +61,6 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
break;
case 'requestReconnectApi':
global = getGlobal();
global = { ...global, isSynced: false };
setGlobal(global);
@ -74,6 +75,11 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
actions.sync();
break;
case 'updateFetchingDifference':
global = { ...global, isFetchingDifference: update.isFetching };
setGlobal(global);
break;
case 'error': {
Object.values(global.byTabId).forEach(({ id: tabId }) => {
const paymentShippingError = getShippingError(update.error);
@ -216,6 +222,19 @@ function onUpdateConnectionState<T extends GlobalState>(
};
setGlobal(global);
const channelStackIds = Object.values(global.byTabId)
.flatMap((tab) => tab.messageLists)
.map((messageList) => messageList.chatId)
.filter((chatId) => {
const chat = global.chats.byId[chatId];
return isChatChannel(chat) || isChatSuperGroup(chat);
});
if (connectionState === 'connectionStateReady' && channelStackIds.length) {
unique(channelStackIds).forEach((chatId) => {
actions.requestChannelDifference({ chatId });
});
}
if (connectionState === 'connectionStateBroken') {
actions.signOut({ forceInitApi: true });
}

View File

@ -590,6 +590,7 @@ export type GlobalState = {
isSyncing?: boolean;
isUpdateAvailable?: boolean;
isSynced?: boolean;
isFetchingDifference?: boolean;
leftColumnWidth?: number;
lastIsChatInfoShown?: boolean;
initialUnreadNotifications?: number;
@ -1592,6 +1593,9 @@ export interface ActionPayloads {
// Initial
signOut: { forceInitApi?: boolean } | undefined;
requestChannelDifference: {
chatId: string;
};
// Misc
setInstallPrompt: { canInstall: boolean } & WithTabId;

View File

@ -18,7 +18,7 @@ type ConnectionStatusPosition =
export default function useConnectionStatus(
lang: LangFn,
connectionState: GlobalState['connectionState'],
isSyncing: GlobalState['isSyncing'],
isSyncing: boolean | undefined,
hasMiddleHeader: boolean,
isMinimized?: boolean,
isDisabled?: boolean,