208 lines
6.5 KiB
TypeScript
208 lines
6.5 KiB
TypeScript
import {
|
|
addActionHandler, getGlobal, setGlobal, getActions,
|
|
} from '../../index';
|
|
|
|
import type { ApiChat, ApiMessage } from '../../../api/types';
|
|
import { MAIN_THREAD_ID } from '../../../api/types';
|
|
import type { Thread } from '../../types';
|
|
|
|
import {
|
|
DEBUG, MESSAGE_LIST_SLICE, SERVICE_NOTIFICATIONS_USER_ID,
|
|
} from '../../../config';
|
|
import { callApi } from '../../../api/gramjs';
|
|
import { buildCollectionByKey } from '../../../util/iteratees';
|
|
import {
|
|
updateUsers,
|
|
updateChats,
|
|
updateThreadInfos,
|
|
updateListedIds,
|
|
safeReplaceViewportIds,
|
|
addChatMessagesById,
|
|
updateThread,
|
|
} from '../../reducers';
|
|
import {
|
|
selectCurrentMessageList,
|
|
selectDraft,
|
|
selectChatMessage,
|
|
selectThreadInfo,
|
|
selectEditingId,
|
|
selectEditingDraft,
|
|
} from '../../selectors';
|
|
import { init as initFolderManager } from '../../../util/folderManager';
|
|
|
|
const RELEASE_STATUS_TIMEOUT = 15000; // 15 sec;
|
|
|
|
let releaseStatusTimeout: number | undefined;
|
|
|
|
addActionHandler('sync', () => {
|
|
if (DEBUG) {
|
|
// eslint-disable-next-line no-console
|
|
console.log('>>> START SYNC');
|
|
}
|
|
|
|
if (releaseStatusTimeout) {
|
|
clearTimeout(releaseStatusTimeout);
|
|
}
|
|
|
|
setGlobal({ ...getGlobal(), isSyncing: true });
|
|
|
|
// Workaround for `isSyncing = true` sometimes getting stuck for some reason
|
|
releaseStatusTimeout = window.setTimeout(() => {
|
|
setGlobal({ ...getGlobal(), isSyncing: false });
|
|
releaseStatusTimeout = undefined;
|
|
}, RELEASE_STATUS_TIMEOUT);
|
|
|
|
const { loadAllChats, preloadTopChatMessages } = getActions();
|
|
|
|
loadAllChats({
|
|
listType: 'active',
|
|
shouldReplace: true,
|
|
onReplace: async () => {
|
|
await loadAndReplaceMessages();
|
|
|
|
setGlobal({
|
|
...getGlobal(),
|
|
lastSyncTime: Date.now(),
|
|
isSyncing: false,
|
|
});
|
|
|
|
if (DEBUG) {
|
|
// eslint-disable-next-line no-console
|
|
console.log('>>> FINISH SYNC');
|
|
}
|
|
|
|
initFolderManager();
|
|
loadAllChats({ listType: 'archived', shouldReplace: true });
|
|
void callApi('fetchCurrentUser');
|
|
preloadTopChatMessages();
|
|
},
|
|
});
|
|
});
|
|
|
|
async function loadAndReplaceMessages() {
|
|
let areMessagesLoaded = false;
|
|
|
|
let global = getGlobal();
|
|
|
|
// Memoize drafts
|
|
const draftChatIds = Object.keys(global.messages.byChatId);
|
|
const draftsByChatId = draftChatIds.reduce<Record<string, Partial<Thread>>>((acc, chatId) => {
|
|
acc[chatId] = {};
|
|
acc[chatId].draft = selectDraft(global, chatId, MAIN_THREAD_ID);
|
|
acc[chatId].editingId = selectEditingId(global, chatId, MAIN_THREAD_ID);
|
|
acc[chatId].editingDraft = selectEditingDraft(global, chatId, MAIN_THREAD_ID);
|
|
|
|
return acc;
|
|
}, {});
|
|
|
|
const { chatId: currentChatId, threadId: currentThreadId } = selectCurrentMessageList(global) || {};
|
|
const currentChat = currentChatId ? global.chats.byId[currentChatId] : undefined;
|
|
if (currentChatId && currentChat) {
|
|
const result = await loadTopMessages(currentChat);
|
|
global = getGlobal();
|
|
const { chatId: newCurrentChatId } = selectCurrentMessageList(global) || {};
|
|
const threadInfo = currentThreadId && selectThreadInfo(global, currentChatId, currentThreadId);
|
|
|
|
if (result && newCurrentChatId === currentChatId) {
|
|
const currentMessageListInfo = global.messages.byChatId[currentChatId];
|
|
const localMessages = currentChatId === SERVICE_NOTIFICATIONS_USER_ID
|
|
? global.serviceNotifications.map(({ message }) => message)
|
|
: [];
|
|
const allMessages = ([] as ApiMessage[]).concat(result.messages, localMessages);
|
|
const byId = buildCollectionByKey(allMessages, 'id');
|
|
const listedIds = Object.keys(byId).map(Number);
|
|
|
|
global = {
|
|
...global,
|
|
messages: {
|
|
...global.messages,
|
|
byChatId: {},
|
|
},
|
|
};
|
|
|
|
global = addChatMessagesById(global, currentChatId, byId);
|
|
global = updateListedIds(global, currentChatId, MAIN_THREAD_ID, listedIds);
|
|
global = safeReplaceViewportIds(global, currentChatId, MAIN_THREAD_ID, listedIds);
|
|
|
|
if (currentThreadId && threadInfo && threadInfo.originChannelId) {
|
|
const { originChannelId } = threadInfo;
|
|
const currentMessageListInfoOrigin = global.messages.byChatId[originChannelId];
|
|
const resultOrigin = await loadTopMessages(global.chats.byId[originChannelId]);
|
|
if (resultOrigin) {
|
|
const byIdOrigin = buildCollectionByKey(resultOrigin.messages, 'id');
|
|
const listedIdsOrigin = Object.keys(byIdOrigin).map(Number);
|
|
|
|
global = {
|
|
...global,
|
|
messages: {
|
|
...global.messages,
|
|
byChatId: {
|
|
...global.messages.byChatId,
|
|
[threadInfo.originChannelId]: {
|
|
byId: byIdOrigin,
|
|
threadsById: {
|
|
[MAIN_THREAD_ID]: {
|
|
...(currentMessageListInfoOrigin?.threadsById[MAIN_THREAD_ID]),
|
|
listedIds: listedIdsOrigin,
|
|
viewportIds: listedIdsOrigin,
|
|
outlyingIds: undefined,
|
|
},
|
|
},
|
|
},
|
|
[currentChatId]: {
|
|
...global.messages.byChatId[currentChatId],
|
|
threadsById: {
|
|
...global.messages.byChatId[currentChatId].threadsById,
|
|
[currentThreadId]: {
|
|
...(currentMessageListInfo?.threadsById[currentThreadId]),
|
|
outlyingIds: undefined,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
global = updateChats(global, buildCollectionByKey(result.chats, 'id'));
|
|
global = updateUsers(global, buildCollectionByKey(result.users, 'id'));
|
|
global = updateThreadInfos(global, currentChatId, result.threadInfos);
|
|
|
|
areMessagesLoaded = true;
|
|
}
|
|
}
|
|
|
|
if (!areMessagesLoaded) {
|
|
global = {
|
|
...global,
|
|
messages: {
|
|
...global.messages,
|
|
byChatId: {},
|
|
},
|
|
};
|
|
}
|
|
|
|
// Restore drafts
|
|
Object.keys(draftsByChatId).forEach((chatId) => {
|
|
global = updateThread(global, chatId, MAIN_THREAD_ID, draftsByChatId[chatId]);
|
|
});
|
|
|
|
setGlobal(global);
|
|
|
|
const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;
|
|
if (audioChatId && audioMessageId && !selectChatMessage(global, audioChatId, audioMessageId)) {
|
|
getActions().closeAudioPlayer();
|
|
}
|
|
}
|
|
|
|
function loadTopMessages(chat: ApiChat) {
|
|
return callApi('fetchMessages', {
|
|
chat,
|
|
threadId: MAIN_THREAD_ID,
|
|
offsetId: chat.lastReadInboxMessageId,
|
|
addOffset: -(Math.round(MESSAGE_LIST_SLICE / 2) + 1),
|
|
limit: MESSAGE_LIST_SLICE,
|
|
});
|
|
}
|