From 06c6a844432f5cd065a3ca548dc07a621ba4024c Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Sat, 24 Apr 2021 21:06:24 +0400 Subject: [PATCH] Refactor updates switch to map --- src/config/database.ts | 2 +- src/helpers/eventListenerBase.ts | 8 + src/lib/appManagers/apiUpdatesManager.ts | 21 +- src/lib/appManagers/appChatsManager.ts | 187 ++- src/lib/appManagers/appDialogsManager.ts | 21 +- src/lib/appManagers/appDraftsManager.ts | 10 +- src/lib/appManagers/appMessagesManager.ts | 1356 ++++++++--------- .../appManagers/appNotificationsManager.ts | 14 +- src/lib/appManagers/appPeersManager.ts | 11 +- src/lib/appManagers/appPollsManager.ts | 24 +- src/lib/appManagers/appPrivacyManager.ts | 14 +- src/lib/appManagers/appProfileManager.ts | 92 +- src/lib/appManagers/appStickersManager.ts | 15 +- src/lib/appManagers/appUsersManager.ts | 125 +- src/lib/appManagers/appWebPagesManager.ts | 10 +- src/lib/cacheStorage.ts | 10 +- src/lib/rootScope.ts | 9 +- src/lib/storage.ts | 2 +- src/lib/storages/filters.ts | 75 +- 19 files changed, 973 insertions(+), 1033 deletions(-) diff --git a/src/config/database.ts b/src/config/database.ts index 65256202..1f05cb59 100644 --- a/src/config/database.ts +++ b/src/config/database.ts @@ -7,7 +7,7 @@ import { IDBStore } from "../lib/idb"; import Modes from "./modes"; -export type DatabaseStoreName = 'session' | 'stickerSets'; +export type DatabaseStoreName = 'session' | 'stickerSets' | 'users' | 'chats' | 'messages' | 'dialogs'; export type DatabaseStore = Omit & {name: DatabaseStoreName}; const Database = { name: 'tweb' + (Modes.test ? '_test' : ''), diff --git a/src/helpers/eventListenerBase.ts b/src/helpers/eventListenerBase.ts index c2a14a1c..cb3f82ae 100644 --- a/src/helpers/eventListenerBase.ts +++ b/src/helpers/eventListenerBase.ts @@ -86,6 +86,14 @@ export default class EventListenerBase l.callback === callback); diff --git a/src/lib/appManagers/apiUpdatesManager.ts b/src/lib/appManagers/apiUpdatesManager.ts index 99c844b0..c91af595 100644 --- a/src/lib/appManagers/apiUpdatesManager.ts +++ b/src/lib/appManagers/apiUpdatesManager.ts @@ -12,6 +12,7 @@ //import apiManager from '../mtproto/apiManager'; import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug'; import { copy } from '../../helpers/object'; +import { Update } from '../../layer'; import { logger, LogLevels } from '../logger'; import apiManager from '../mtproto/mtprotoworker'; import rootScope from '../rootScope'; @@ -53,7 +54,7 @@ export class ApiUpdatesManager { private log = logger('UPDATES', LogLevels.error | LogLevels.log | LogLevels.warn | LogLevels.debug); private debug = DEBUG; - public popPendingSeqUpdate() { + private popPendingSeqUpdate() { const state = this.updatesState; const nextSeq = state.seq + 1; const pendingUpdatesData = state.pendingSeqUpdates[nextSeq]; @@ -87,7 +88,7 @@ export class ApiUpdatesManager { return true; } - public popPendingPtsUpdate(channelId: number) { + private popPendingPtsUpdate(channelId: number) { const curState = channelId ? this.getChannelState(channelId) : this.updatesState; if(!curState.pendingPtsUpdates.length) { return false; @@ -119,6 +120,8 @@ export class ApiUpdatesManager { curState.pts = goodPts; for(let i = 0; i <= goodIndex; ++i) { const update = curState.pendingPtsUpdates[i]; + + // @ts-ignore this.saveUpdate(update); } curState.pendingPtsUpdates.splice(0, goodIndex + 1); @@ -208,7 +211,7 @@ export class ApiUpdatesManager { } }; - public getDifference(first = false): Promise { + private getDifference(first = false): Promise { // this.trace('Get full diff') const updatesState = this.updatesState; let wasSyncing = updatesState.syncLoading; @@ -298,7 +301,7 @@ export class ApiUpdatesManager { return promise; } - public getChannelDifference(channelId: number): Promise { + private getChannelDifference(channelId: number): Promise { const channelState = this.getChannelState(channelId); const wasSyncing = channelState.syncLoading; if(!wasSyncing) { @@ -328,6 +331,8 @@ export class ApiUpdatesManager { if(differenceResult._ === 'updates.channelDifferenceTooLong') { this.debug && this.log('channel diff too long', differenceResult); delete this.channelStates[channelId]; + + // @ts-ignore this.saveUpdate({_: 'updateChannelReload', channel_id: channelId}); return; } @@ -399,7 +404,7 @@ export class ApiUpdatesManager { return false; } - public getChannelState(channelId: number, pts?: number) { + private getChannelState(channelId: number, pts?: number) { if(this.channelStates[channelId] === undefined) { this.addChannelState(channelId, pts); } @@ -407,7 +412,7 @@ export class ApiUpdatesManager { return this.channelStates[channelId]; } - public processUpdate(update: any, options: Partial<{ + private processUpdate(update: any, options: Partial<{ date: number, seq: number, seqStart: number/* , @@ -570,8 +575,8 @@ export class ApiUpdatesManager { } } - public saveUpdate(update: any) { - rootScope.broadcast('apiUpdate', update); + public saveUpdate(update: Update) { + rootScope.dispatchEvent(update._, update as any); } public attach() { diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts index 3e40855b..52944a5b 100644 --- a/src/lib/appManagers/appChatsManager.ts +++ b/src/lib/appManagers/appChatsManager.ts @@ -12,7 +12,7 @@ import { MOUNT_CLASS_TO } from "../../config/debug"; import { numberThousandSplitter } from "../../helpers/number"; import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object"; -import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipant, ChatParticipants, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer"; +import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer"; import { i18n, LangPackKey } from "../langPack"; import apiManagerProxy from "../mtproto/mtprotoworker"; import apiManager from '../mtproto/mtprotoworker'; @@ -42,112 +42,105 @@ export class AppChatsManager { public typingsInPeer: {[peerId: number]: UserTyping[]} = {}; constructor() { - rootScope.on('apiUpdate', (update) => { - // console.log('on apiUpdate', update) - switch(update._) { - case 'updateChannel': { - const channelId = update.channel_id; - //console.log('updateChannel:', update); - rootScope.broadcast('channel_settings', {channelId}); - break; + rootScope.addMultipleEventsListeners({ + updateChannel: (update) => { + const channelId = update.channel_id; + //console.log('updateChannel:', update); + rootScope.broadcast('channel_settings', {channelId}); + }, + + updateChannelParticipant: (update) => { + apiManagerProxy.clearCache('channels.getParticipants', (params) => { + return (params.channel as InputChannel.inputChannel).channel_id === update.channel_id; + }); + }, + + updateChatDefaultBannedRights: (update) => { + const chatId = -appPeersManager.getPeerId(update.peer); + const chat: Chat = this.getChat(chatId); + if(chat._ !== 'chatEmpty') { + (chat as Chat.chat).default_banned_rights = update.default_banned_rights; + rootScope.broadcast('chat_update', chatId); } + }, - case 'updateChannelParticipant': { - apiManagerProxy.clearCache('channels.getParticipants', (params) => { - return (params.channel as InputChannel.inputChannel).channel_id === update.channel_id; - }); - break; - } + updateUserTyping: this.onUpdateUserTyping, + updateChatUserTyping: this.onUpdateUserTyping, + updateChannelUserTyping: this.onUpdateUserTyping + }); - case 'updateChatDefaultBannedRights': { - const chatId = -appPeersManager.getPeerId(update.peer); - const chat: Chat = this.getChat(chatId); - if(chat._ !== 'chatEmpty') { - (chat as Chat.chat).default_banned_rights = update.default_banned_rights; - rootScope.broadcast('chat_update', chatId); - } + appStateManager.getState().then((state) => { + this.chats = state.chats; + }); + } - break; - } + private onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => { + const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id); + if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') { + return; + } + + const peerId = update._ === 'updateUserTyping' ? + fromId : + -((update as Update.updateChatUserTyping).chat_id || (update as Update.updateChannelUserTyping).channel_id); + const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []); + let typing = typings.find(t => t.userId === fromId); + + const cancelAction = () => { + delete typing.timeout; + //typings.findAndSplice(t => t === typing); + const idx = typings.indexOf(typing); + if(idx !== -1) { + typings.splice(idx, 1); + } - case 'updateUserTyping': - case 'updateChatUserTyping': - case 'updateChannelUserTyping': { - const fromId = (update as Update.updateUserTyping).user_id || appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id); - if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') { - break; - } - - const peerId = update._ === 'updateUserTyping' ? - fromId : - -((update as Update.updateChatUserTyping).chat_id || (update as Update.updateChannelUserTyping).channel_id); - const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []); - let typing = typings.find(t => t.userId === fromId); - - const cancelAction = () => { - delete typing.timeout; - //typings.findAndSplice(t => t === typing); - const idx = typings.indexOf(typing); - if(idx !== -1) { - typings.splice(idx, 1); - } - - rootScope.broadcast('peer_typings', {peerId, typings}); - - if(!typings.length) { - delete this.typingsInPeer[peerId]; - } - }; - - if(typing && typing.timeout !== undefined) { - clearTimeout(typing.timeout); - } + rootScope.broadcast('peer_typings', {peerId, typings}); - if(update.action._ === 'sendMessageCancelAction') { - if(!typing) { - break; - } - - cancelAction(); - break; - } else { - if(!typing) { - typing = { - userId: fromId - }; - - typings.push(typing); - } - - //console.log('updateChatUserTyping', update, typings); - - typing.action = update.action; - - if(!appUsersManager.hasUser(fromId)) { - if(update._ === 'updateChatUserTyping') { - if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) { - appProfileManager.getChatFull(update.chat_id); - } - } - - //return; - } - - appUsersManager.forceUserOnline(fromId); - - typing.timeout = window.setTimeout(cancelAction, 6000); - rootScope.broadcast('peer_typings', {peerId, typings}); - } + if(!typings.length) { + delete this.typingsInPeer[peerId]; + } + }; + + if(typing && typing.timeout !== undefined) { + clearTimeout(typing.timeout); + } + + if(update.action._ === 'sendMessageCancelAction') { + if(!typing) { + return; + } + + cancelAction(); + return; + } else { + if(!typing) { + typing = { + userId: fromId + }; + + typings.push(typing); + } - break; + //console.log('updateChatUserTyping', update, typings); + + typing.action = update.action; + + if(!appUsersManager.hasUser(fromId)) { + if(update._ === 'updateChatUserTyping') { + if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) { + appProfileManager.getChatFull(update.chat_id); + } } + + //return; } - }); + + appUsersManager.forceUserOnline(fromId); - appStateManager.getState().then((state) => { - this.chats = state.chats; - }); - } + typing.timeout = window.setTimeout(cancelAction, 6000); + rootScope.broadcast('peer_typings', {peerId, typings}); + } + }; public saveApiChats(apiChats: any[]) { apiChats.forEach(chat => this.saveApiChat(chat)); diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 43f2f70a..f1f54221 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -22,7 +22,7 @@ import appMessagesManager, { Dialog } from "./appMessagesManager"; import {MyDialogFilter as DialogFilter} from "../storages/filters"; import appPeersManager from './appPeersManager'; import appStateManager from "./appStateManager"; -import appUsersManager, { User } from "./appUsersManager"; +import appUsersManager from "./appUsersManager"; import Button from "../../components/button"; import SetTransition from "../../components/singleTransition"; import sessionStorage from '../sessionStorage'; @@ -32,11 +32,9 @@ import ProgressivePreloader from "../../components/preloader"; import App from "../../config/app"; import DEBUG, { MOUNT_CLASS_TO } from "../../config/debug"; import appNotificationsManager from "./appNotificationsManager"; -import { InputNotifyPeer } from "../../layer"; import PeerTitle from "../../components/peerTitle"; import { i18n } from "../langPack"; import findUpTag from "../../helpers/dom/findUpTag"; -import appChatsManager from "./appChatsManager"; export type DialogDom = { avatarEl: AvatarElement, @@ -301,19 +299,14 @@ export class AppDialogsManager { (window as any).addElement = add; } */ - rootScope.on('user_update', (e) => { - const userId = e; - const user = appUsersManager.getUser(userId); - const dialog = appMessagesManager.getDialogByPeerId(user.id)[0]; + rootScope.on('user_update', (userId) => { //console.log('updating user:', user, dialog); - - if(dialog && !appUsersManager.isBot(dialog.peerId) && dialog.peerId !== rootScope.myId) { + + const dom = this.getDialogDom(userId); + if(dom && !appUsersManager.isBot(userId) && userId !== rootScope.myId) { + const user = appUsersManager.getUser(userId); const online = user.status?._ === 'userStatusOnline'; - const dom = this.getDialogDom(dialog.peerId); - - if(dom) { - dom.avatarEl.classList.toggle('is-online', online); - } + dom.avatarEl.classList.toggle('is-online', online); } }); diff --git a/src/lib/appManagers/appDraftsManager.ts b/src/lib/appManagers/appDraftsManager.ts index 37c186e4..92152d25 100644 --- a/src/lib/appManagers/appDraftsManager.ts +++ b/src/lib/appManagers/appDraftsManager.ts @@ -38,13 +38,11 @@ export class AppDraftsManager { }); }); - rootScope.on('apiUpdate', (update) => { - if(update._ !== 'updateDraftMessage') { - return + rootScope.addMultipleEventsListeners({ + updateDraftMessage: (update) => { + const peerID = appPeersManager.getPeerId(update.peer); + this.saveDraft(peerID, (update as any).threadId, update.draft, {notify: true}); } - - const peerID = appPeersManager.getPeerId(update.peer); - this.saveDraft(peerID, (update as any).threadId, update.draft, {notify: true}); }); } diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 64a55934..da00dd94 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -174,7 +174,7 @@ export class AppMessagesManager { public newMessagesToHandle: {[peerId: string]: Set} = {}; public newDialogsHandlePromise = 0; public newDialogsToHandle: {[peerId: string]: {reload: true} | Dialog} = {}; - public newUpdatesAfterReloadToHandle: {[peerId: string]: Set} = {}; + public newUpdatesAfterReloadToHandle: {[peerId: string]: Set} = {}; private notificationsHandlePromise = 0; private notificationsToHandle: {[peerId: string]: { @@ -207,10 +207,58 @@ export class AppMessagesManager { constructor() { this.dialogsStorage = new DialogsStorage(this, appChatsManager, appPeersManager, serverTimeManager); - this.filtersStorage = new FiltersStorage(this, appPeersManager, appUsersManager, appNotificationsManager, /* apiManager, */ rootScope); + this.filtersStorage = new FiltersStorage(this, appPeersManager, appUsersManager, appNotificationsManager, apiUpdatesManager, /* apiManager, */ rootScope); - rootScope.on('apiUpdate', (e) => { - this.handleUpdate(e); + rootScope.addMultipleEventsListeners({ + updateMessageID: this.onUpdateMessageId, + + updateNewDiscussionMessage: this.onUpdateNewMessage, + updateNewMessage: this.onUpdateNewMessage, + updateNewChannelMessage: this.onUpdateNewMessage, + + updateDialogUnreadMark: this.onUpdateDialogUnreadMark, + + updateFolderPeers: this.onUpdateFolderPeers, + + updateDialogPinned: this.onUpdateDialogPinned, + + updatePinnedDialogs: this.onUpdatePinnedDialogs, + + updateEditMessage: this.onUpdateEditMessage, + updateEditChannelMessage: this.onUpdateEditMessage, + + updateReadChannelDiscussionInbox: this.onUpdateReadHistory, + updateReadChannelDiscussionOutbox: this.onUpdateReadHistory, + updateReadHistoryInbox: this.onUpdateReadHistory, + updateReadHistoryOutbox: this.onUpdateReadHistory, + updateReadChannelInbox: this.onUpdateReadHistory, + updateReadChannelOutbox: this.onUpdateReadHistory, + + updateChannelReadMessagesContents: this.onUpdateReadMessagesContents, + updateReadMessagesContents: this.onUpdateReadMessagesContents, + + updateChannelAvailableMessages: this.onUpdateChannelAvailableMessages, + + updateDeleteMessages: this.onUpdateDeleteMessages, + updateDeleteChannelMessages: this.onUpdateDeleteMessages, + + updateChannel: this.onUpdateChannel, + + // @ts-ignore + updateChannelReload: this.onUpdateChannelReload, + + updateChannelMessageViews: this.onUpdateChannelMessageViews, + + updateServiceNotification: this.onUpdateServiceNotification, + + updatePinnedMessages: this.onUpdatePinnedMessages, + updatePinnedChannelMessages: this.onUpdatePinnedMessages, + + updateNotifySettings: this.onUpdateNotifySettings, + + updateNewScheduledMessage: this.onUpdateNewScheduledMessage, + + updateDeleteScheduledMessages: this.onUpdateDeleteScheduledMessages }); // ! Invalidate notify settings, can optimize though @@ -2900,7 +2948,7 @@ export class AppMessagesManager { }).then(bool => { if(bool) { const pFlags: Update.updateDialogPinned['pFlags'] = pinned ? {pinned} : {}; - this.handleUpdate({ + this.onUpdateDialogPinned({ _: 'updateDialogPinned', peer: appPeersManager.getDialogPeer(peerId), folder_id: filterId, @@ -2921,7 +2969,7 @@ export class AppMessagesManager { }).then(bool => { if(bool) { const pFlags: Update.updateDialogUnreadMark['pFlags'] = unread ? {unread} : {}; - this.handleUpdate({ + this.onUpdateDialogUnreadMark({ _: 'updateDialogUnreadMark', peer: appPeersManager.getDialogPeer(peerId), pFlags @@ -3059,7 +3107,7 @@ export class AppMessagesManager { if(this.newUpdatesAfterReloadToHandle[peerId] !== undefined) { for(const update of this.newUpdatesAfterReloadToHandle[peerId]) { - this.handleUpdate(update); + apiUpdatesManager.saveUpdate(update); } delete this.newUpdatesAfterReloadToHandle[peerId]; @@ -3927,810 +3975,762 @@ export class AppMessagesManager { this.notificationsToHandle = {}; }; - public handleUpdate(update: Update) { - /* if(DEBUG) { - this.log.debug('handleUpdate', update._, update); - } */ + private onUpdateMessageId = (update: Update.updateMessageID) => { + const randomId = update.random_id; + const pendingData = this.pendingByRandomId[randomId]; + //this.log('AMM updateMessageID:', update, pendingData); + if(pendingData) { + const {peerId, tempId, threadId, storage} = pendingData; + //const mid = update.id; + const mid = this.generateMessageId(update.id); + const message = this.getMessageFromStorage(storage, mid); + if(!message.deleted) { + [this.getHistoryStorage(peerId), threadId ? this.getHistoryStorage(peerId, threadId) : undefined] + .filter(Boolean) + .forEach(storage => { + storage.history.delete(tempId); + }); - switch(update._) { - case 'updateMessageID': { - const randomId = update.random_id; - const pendingData = this.pendingByRandomId[randomId]; - //this.log('AMM updateMessageID:', update, pendingData); - if(pendingData) { - const {peerId, tempId, threadId, storage} = pendingData; - //const mid = update.id; - const mid = this.generateMessageId(update.id); - const message = this.getMessageFromStorage(storage, mid); - if(!message.deleted) { - [this.getHistoryStorage(peerId), threadId ? this.getHistoryStorage(peerId, threadId) : undefined] - .filter(Boolean) - .forEach(storage => { - storage.history.delete(tempId); - }); + this.finalizePendingMessageCallbacks(storage, tempId, mid); + } else { + this.pendingByMessageId[mid] = randomId; + } + } + }; - this.finalizePendingMessageCallbacks(storage, tempId, mid); - } else { - this.pendingByMessageId[mid] = randomId; - } + private onUpdateNewMessage = (update: Update.updateNewDiscussionMessage | Update.updateNewMessage | Update.updateNewChannelMessage) => { + const message = update.message as MyMessage; + const peerId = this.getMessagePeer(message); + const storage = this.getMessagesStorage(peerId); + const foundDialog = this.getDialogByPeerId(peerId); + + // * local update + const isLocalThreadUpdate = update._ === 'updateNewDiscussionMessage'; + + // * temporary save the message for info (peerId, reply mids...) + this.saveMessages([message], {storage: {}}); + + const threadKey = this.getThreadKey(message); + const threadId = threadKey ? +threadKey.split('_')[1] : undefined; + if(threadId && !isLocalThreadUpdate && this.threadsStorage[peerId] && this.threadsStorage[peerId][threadId]) { + const update = { + _: 'updateNewDiscussionMessage', + message + } as Update.updateNewDiscussionMessage; + + this.onUpdateNewMessage(update); + } + + if(!foundDialog.length && !isLocalThreadUpdate) { + let good = true; + if(peerId < 0) { + const chat = appChatsManager.getChat(-peerId); + if(chat._ === 'channelForbidden' + || chat._ === 'chatForbidden' + || (chat as Chat.chat).pFlags.left + || (chat as Chat.chat).pFlags.kicked + || (chat as Chat.chat).pFlags.deactivated) { + good = false; } - - break; } - case 'updateNewDiscussionMessage': - case 'updateNewMessage': - case 'updateNewChannelMessage': { - const message = update.message as MyMessage; - const peerId = this.getMessagePeer(message); - const storage = this.getMessagesStorage(peerId); - const foundDialog = this.getDialogByPeerId(peerId); - - // * local update - const isLocalThreadUpdate = update._ === 'updateNewDiscussionMessage'; - - // * temporary save the message for info (peerId, reply mids...) - this.saveMessages([message], {storage: {}}); - - const threadKey = this.getThreadKey(message); - const threadId = threadKey ? +threadKey.split('_')[1] : undefined; - if(threadId && !isLocalThreadUpdate && this.threadsStorage[peerId] && this.threadsStorage[peerId][threadId]) { - const update = { - _: 'updateNewDiscussionMessage', - message - } as Update.updateNewDiscussionMessage; - - this.handleUpdate(update); + if(good) { + const set = this.newUpdatesAfterReloadToHandle[peerId] ?? (this.newUpdatesAfterReloadToHandle[peerId] = new Set()); + if(set.has(update)) { + this.log.error('here we go again', peerId); + return; } - if(!foundDialog.length && !isLocalThreadUpdate) { - let good = true; - if(peerId < 0) { - const chat = appChatsManager.getChat(-peerId); - if(chat._ === 'channelForbidden' - || chat._ === 'chatForbidden' - || (chat as Chat.chat).pFlags.left - || (chat as Chat.chat).pFlags.kicked - || (chat as Chat.chat).pFlags.deactivated) { - good = false; - } - } - - if(good) { - const set = this.newUpdatesAfterReloadToHandle[peerId] ?? (this.newUpdatesAfterReloadToHandle[peerId] = new Set()); - if(set.has(update)) { - this.log.error('here we go again', peerId); - break; - } - - this.newDialogsToHandle[peerId] = {reload: true}; - this.scheduleHandleNewDialogs(); - this.newUpdatesAfterReloadToHandle[peerId].add(update); - } + this.newDialogsToHandle[peerId] = {reload: true}; + this.scheduleHandleNewDialogs(); + this.newUpdatesAfterReloadToHandle[peerId].add(update); + } - break; - } + return; + } - /* if(update._ === 'updateNewChannelMessage') { - const chat = appChatsManager.getChat(-peerId); - if(chat.pFlags && (chat.pFlags.left || chat.pFlags.kicked)) { - break; - } - } */ + /* if(update._ === 'updateNewChannelMessage') { + const chat = appChatsManager.getChat(-peerId); + if(chat.pFlags && (chat.pFlags.left || chat.pFlags.kicked)) { + return; + } + } */ - this.saveMessages([message], {storage}); - // this.log.warn(dT(), 'message unread', message.mid, message.pFlags.unread) + this.saveMessages([message], {storage}); + // this.log.warn(dT(), 'message unread', message.mid, message.pFlags.unread) - /* if((message as Message.message).grouped_id) { - this.log('updateNewMessage', message); - } */ + /* if((message as Message.message).grouped_id) { + this.log('updateNewMessage', message); + } */ - const pendingMessage = this.checkPendingMessage(message); - const historyStorage = this.getHistoryStorage(peerId, isLocalThreadUpdate ? threadId : undefined); + const pendingMessage = this.checkPendingMessage(message); + const historyStorage = this.getHistoryStorage(peerId, isLocalThreadUpdate ? threadId : undefined); - if(!isLocalThreadUpdate) { - this.updateMessageRepliesIfNeeded(message); - } + if(!isLocalThreadUpdate) { + this.updateMessageRepliesIfNeeded(message); + } - if(historyStorage.history.findSlice(message.mid)) { - return false; - } + if(historyStorage.history.findSlice(message.mid)) { + return false; + } - const history = historyStorage.history.slice; - const topMsgId = history[0]; - history.unshift(message.mid); - if(message.mid < topMsgId) { - //this.log.error('this should\'nt have happenned!', message, history); - history.sort((a, b) => { - return b - a; - }); - } - - if(historyStorage.count !== null) { - historyStorage.count++; - } + const history = historyStorage.history.slice; + const topMsgId = history[0]; + history.unshift(message.mid); + if(message.mid < topMsgId) { + //this.log.error('this should\'nt have happenned!', message, history); + history.sort((a, b) => { + return b - a; + }); + } - if(this.mergeReplyKeyboard(historyStorage, message)) { - rootScope.broadcast('history_reply_markup', {peerId}); - } - - if(message.fromId > 0 && !message.pFlags.out && message.from_id) { - appUsersManager.forceUserOnline(message.fromId, message.date); - } + if(historyStorage.count !== null) { + historyStorage.count++; + } - if(!pendingMessage) { - if(this.newMessagesToHandle[peerId] === undefined) { - this.newMessagesToHandle[peerId] = new Set(); - } - - this.newMessagesToHandle[peerId].add(message.mid); - if(!this.newMessagesHandlePromise) { - this.newMessagesHandlePromise = window.setTimeout(this.handleNewMessages, 0); - } - } + if(this.mergeReplyKeyboard(historyStorage, message)) { + rootScope.broadcast('history_reply_markup', {peerId}); + } - if(isLocalThreadUpdate) { - break; - } - - const dialog = foundDialog[0]; - const inboxUnread = !message.pFlags.out && message.pFlags.unread; - if(dialog) { - this.setDialogTopMessage(message, dialog); - if(inboxUnread) { - dialog.unread_count++; - } - } + if(message.fromId > 0 && !message.pFlags.out && message.from_id) { + appUsersManager.forceUserOnline(message.fromId, message.date); + } - if(inboxUnread/* && ($rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) */) { - const notifyPeer = message.peerId; - let notifyPeerToHandle = this.notificationsToHandle[notifyPeer]; - if(notifyPeerToHandle === undefined) { - notifyPeerToHandle = this.notificationsToHandle[notifyPeer] = { - fwdCount: 0, - fromId: 0 - }; - } + if(!pendingMessage) { + if(this.newMessagesToHandle[peerId] === undefined) { + this.newMessagesToHandle[peerId] = new Set(); + } - if(notifyPeerToHandle.fromId !== message.fromId) { - notifyPeerToHandle.fromId = message.fromId; - notifyPeerToHandle.fwdCount = 0; - } + this.newMessagesToHandle[peerId].add(message.mid); + if(!this.newMessagesHandlePromise) { + this.newMessagesHandlePromise = window.setTimeout(this.handleNewMessages, 0); + } + } - if((message as Message.message).fwd_from) { - notifyPeerToHandle.fwdCount++; - } + if(isLocalThreadUpdate) { + return; + } + + const dialog = foundDialog[0]; + const inboxUnread = !message.pFlags.out && message.pFlags.unread; + if(dialog) { + this.setDialogTopMessage(message, dialog); + if(inboxUnread) { + dialog.unread_count++; + } + } - notifyPeerToHandle.topMessage = message; + if(inboxUnread/* && ($rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) */) { + const notifyPeer = message.peerId; + let notifyPeerToHandle = this.notificationsToHandle[notifyPeer]; + if(notifyPeerToHandle === undefined) { + notifyPeerToHandle = this.notificationsToHandle[notifyPeer] = { + fwdCount: 0, + fromId: 0 + }; + } - if(!this.notificationsHandlePromise) { - this.notificationsHandlePromise = window.setTimeout(this.handleNotifications, 0); - } - } + if(notifyPeerToHandle.fromId !== message.fromId) { + notifyPeerToHandle.fromId = message.fromId; + notifyPeerToHandle.fwdCount = 0; + } - break; + if((message as Message.message).fwd_from) { + notifyPeerToHandle.fwdCount++; } - case 'updateDialogUnreadMark': { - //this.log('updateDialogUnreadMark', update); - const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer); - const foundDialog = this.getDialogByPeerId(peerId); + notifyPeerToHandle.topMessage = message; - if(!foundDialog.length) { - this.newDialogsToHandle[peerId] = {reload: true}; - this.scheduleHandleNewDialogs(); - } else { - const dialog = foundDialog[0]; + if(!this.notificationsHandlePromise) { + this.notificationsHandlePromise = window.setTimeout(this.handleNotifications, 0); + } + } + }; - if(!update.pFlags.unread) { - delete dialog.pFlags.unread_mark; - } else { - dialog.pFlags.unread_mark = true; - } + private onUpdateDialogUnreadMark = (update: Update.updateDialogUnreadMark) => { + //this.log('updateDialogUnreadMark', update); + const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer); + const foundDialog = this.getDialogByPeerId(peerId); - rootScope.broadcast('dialogs_multiupdate', {peerId: dialog}); - } + if(!foundDialog.length) { + this.newDialogsToHandle[peerId] = {reload: true}; + this.scheduleHandleNewDialogs(); + } else { + const dialog = foundDialog[0]; - break; + if(!update.pFlags.unread) { + delete dialog.pFlags.unread_mark; + } else { + dialog.pFlags.unread_mark = true; } - case 'updateFolderPeers': { // only 0 and 1 folders - //this.log('updateFolderPeers', update); - const peers = update.folder_peers; - - this.scheduleHandleNewDialogs(); - peers.forEach((folderPeer) => { - const {folder_id, peer} = folderPeer; + rootScope.broadcast('dialogs_multiupdate', {peerId: dialog}); + } + }; - const peerId = appPeersManager.getPeerId(peer); - const dropped = this.dialogsStorage.dropDialog(peerId); - if(!dropped.length) { - this.newDialogsToHandle[peerId] = {reload: true}; - } else { - const dialog = dropped[0]; - this.newDialogsToHandle[peerId] = dialog; + // only 0 and 1 folders + private onUpdateFolderPeers = (update: Update.updateFolderPeers) => { + //this.log('updateFolderPeers', update); + const peers = update.folder_peers; - if(dialog.pFlags?.pinned) { - delete dialog.pFlags.pinned; - this.dialogsStorage.pinnedOrders[folder_id].findAndSplice(p => p === dialog.peerId); - } + this.scheduleHandleNewDialogs(); + peers.forEach((folderPeer) => { + const {folder_id, peer} = folderPeer; - dialog.folder_id = folder_id; + const peerId = appPeersManager.getPeerId(peer); + const dropped = this.dialogsStorage.dropDialog(peerId); + if(!dropped.length) { + this.newDialogsToHandle[peerId] = {reload: true}; + } else { + const dialog = dropped[0]; + this.newDialogsToHandle[peerId] = dialog; - this.dialogsStorage.generateIndexForDialog(dialog); - this.dialogsStorage.pushDialog(dialog); // need for simultaneously updatePinnedDialogs - } - }); - break; - } + if(dialog.pFlags?.pinned) { + delete dialog.pFlags.pinned; + this.dialogsStorage.pinnedOrders[folder_id].findAndSplice(p => p === dialog.peerId); + } - case 'updateDialogPinned': { - const folderId = update.folder_id ?? 0; - //this.log('updateDialogPinned', update); - const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer); - const foundDialog = this.getDialogByPeerId(peerId); + dialog.folder_id = folder_id; - // этот код внизу никогда не сработает, в папках за пиннед отвечает updateDialogFilter - /* if(update.folder_id > 1) { - const filter = this.filtersStorage.filters[update.folder_id]; - if(update.pFlags.pinned) { - filter.pinned_peers.unshift(peerId); - } else { - filter.pinned_peers.findAndSplice(p => p === peerId); - } - } */ + this.dialogsStorage.generateIndexForDialog(dialog); + this.dialogsStorage.pushDialog(dialog); // need for simultaneously updatePinnedDialogs + } + }); + }; - this.scheduleHandleNewDialogs(); - if(!foundDialog.length) { - this.newDialogsToHandle[peerId] = {reload: true}; - } else { - const dialog = foundDialog[0]; - this.newDialogsToHandle[peerId] = dialog; - - if(!update.pFlags.pinned) { - delete dialog.pFlags.pinned; - this.dialogsStorage.pinnedOrders[folderId].findAndSplice(p => p === dialog.peerId); - } else { // means set - dialog.pFlags.pinned = true; - } + private onUpdateDialogPinned = (update: Update.updateDialogPinned) => { + const folderId = update.folder_id ?? 0; + //this.log('updateDialogPinned', update); + const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer); + const foundDialog = this.getDialogByPeerId(peerId); + + // этот код внизу никогда не сработает, в папках за пиннед отвечает updateDialogFilter + /* if(update.folder_id > 1) { + const filter = this.filtersStorage.filters[update.folder_id]; + if(update.pFlags.pinned) { + filter.pinned_peers.unshift(peerId); + } else { + filter.pinned_peers.findAndSplice(p => p === peerId); + } + } */ - this.dialogsStorage.generateIndexForDialog(dialog); - } + this.scheduleHandleNewDialogs(); + if(!foundDialog.length) { + this.newDialogsToHandle[peerId] = {reload: true}; + } else { + const dialog = foundDialog[0]; + this.newDialogsToHandle[peerId] = dialog; - break; + if(!update.pFlags.pinned) { + delete dialog.pFlags.pinned; + this.dialogsStorage.pinnedOrders[folderId].findAndSplice(p => p === dialog.peerId); + } else { // means set + dialog.pFlags.pinned = true; } - case 'updatePinnedDialogs': { - const folderId = update.folder_id ?? 0; + this.dialogsStorage.generateIndexForDialog(dialog); + } + }; + + private onUpdatePinnedDialogs = (update: Update.updatePinnedDialogs) => { + const folderId = update.folder_id ?? 0; - const handleOrder = (order: number[]) => { - this.dialogsStorage.pinnedOrders[folderId].length = 0; - let willHandle = false; - order.reverse(); // index must be higher - order.forEach((peerId) => { - newPinned[peerId] = true; + const handleOrder = (order: number[]) => { + this.dialogsStorage.pinnedOrders[folderId].length = 0; + let willHandle = false; + order.reverse(); // index must be higher + order.forEach((peerId) => { + newPinned[peerId] = true; - const foundDialog = this.getDialogByPeerId(peerId); - if(!foundDialog.length) { - this.newDialogsToHandle[peerId] = {reload: true}; - willHandle = true; - return; - } + const foundDialog = this.getDialogByPeerId(peerId); + if(!foundDialog.length) { + this.newDialogsToHandle[peerId] = {reload: true}; + willHandle = true; + return; + } - const dialog = foundDialog[0]; - dialog.pFlags.pinned = true; - this.dialogsStorage.generateIndexForDialog(dialog); + const dialog = foundDialog[0]; + dialog.pFlags.pinned = true; + this.dialogsStorage.generateIndexForDialog(dialog); - this.newDialogsToHandle[peerId] = dialog; - willHandle = true; - }); - - this.dialogsStorage.getFolder(folderId).forEach(dialog => { - const peerId = dialog.peerId; - if(dialog.pFlags.pinned && !newPinned[peerId]) { - this.newDialogsToHandle[peerId] = {reload: true}; - willHandle = true; - } - }); + this.newDialogsToHandle[peerId] = dialog; + willHandle = true; + }); + + this.dialogsStorage.getFolder(folderId).forEach(dialog => { + const peerId = dialog.peerId; + if(dialog.pFlags.pinned && !newPinned[peerId]) { + this.newDialogsToHandle[peerId] = {reload: true}; + willHandle = true; + } + }); - if(willHandle) { - this.scheduleHandleNewDialogs(); - } - }; - - //this.log('updatePinnedDialogs', update); - const newPinned: {[peerId: number]: true} = {}; - if(!update.order) { - apiManager.invokeApi('messages.getPinnedDialogs', { - folder_id: folderId - }).then((dialogsResult) => { - // * for test reordering and rendering - // dialogsResult.dialogs.reverse(); - - this.applyConversations(dialogsResult); + if(willHandle) { + this.scheduleHandleNewDialogs(); + } + }; - handleOrder(dialogsResult.dialogs.map(d => d.peerId)); + //this.log('updatePinnedDialogs', update); + const newPinned: {[peerId: number]: true} = {}; + if(!update.order) { + apiManager.invokeApi('messages.getPinnedDialogs', { + folder_id: folderId + }).then((dialogsResult) => { + // * for test reordering and rendering + // dialogsResult.dialogs.reverse(); - /* dialogsResult.dialogs.forEach((dialog) => { - newPinned[dialog.peerId] = true; - }); + this.applyConversations(dialogsResult); - this.dialogsStorage.getFolder(folderId).forEach((dialog) => { - const peerId = dialog.peerId; - if(dialog.pFlags.pinned && !newPinned[peerId]) { - this.newDialogsToHandle[peerId] = {reload: true}; - this.scheduleHandleNewDialogs(); - } - }); */ - }); + handleOrder(dialogsResult.dialogs.map(d => d.peerId)); - break; - } + /* dialogsResult.dialogs.forEach((dialog) => { + newPinned[dialog.peerId] = true; + }); - //this.log('before order:', this.dialogsStorage[0].map(d => d.peerId)); + this.dialogsStorage.getFolder(folderId).forEach((dialog) => { + const peerId = dialog.peerId; + if(dialog.pFlags.pinned && !newPinned[peerId]) { + this.newDialogsToHandle[peerId] = {reload: true}; + this.scheduleHandleNewDialogs(); + } + }); */ + }); - handleOrder(update.order.map(peer => appPeersManager.getPeerId((peer as DialogPeer.dialogPeer).peer))); + return; + } - break; - } + //this.log('before order:', this.dialogsStorage[0].map(d => d.peerId)); - case 'updateEditMessage': - case 'updateEditChannelMessage': { - const message = update.message as MyMessage; - const peerId = this.getMessagePeer(message); - const mid = this.generateMessageId(message.id); - const storage = this.getMessagesStorage(peerId); - if(storage[mid] === undefined) { - break; - } + handleOrder(update.order.map(peer => appPeersManager.getPeerId((peer as DialogPeer.dialogPeer).peer))); + }; - // console.trace(dT(), 'edit message', message) - - const oldMessage = this.getMessageFromStorage(storage, mid); - this.saveMessages([message], {storage}); - const newMessage = this.getMessageFromStorage(storage, mid); + private onUpdateEditMessage = (update: Update.updateEditMessage | Update.updateEditChannelMessage) => { + const message = update.message as MyMessage; + const peerId = this.getMessagePeer(message); + const mid = this.generateMessageId(message.id); + const storage = this.getMessagesStorage(peerId); + if(storage[mid] === undefined) { + return; + } - this.handleEditedMessage(oldMessage, newMessage); + // console.trace(dT(), 'edit message', message) + + const oldMessage = this.getMessageFromStorage(storage, mid); + this.saveMessages([message], {storage}); + const newMessage = this.getMessageFromStorage(storage, mid); - const dialog = this.getDialogByPeerId(peerId)[0]; - const isTopMessage = dialog && dialog.top_message === mid; - // @ts-ignore - if(message.clear_history) { // that's will never happen - if(isTopMessage) { - rootScope.broadcast('dialog_flush', {peerId}); - } - } else { - rootScope.broadcast('message_edit', { - storage, - peerId, - mid - }); + this.handleEditedMessage(oldMessage, newMessage); - if(isTopMessage || (message as Message.message).grouped_id) { - const updatedDialogs: {[peerId: number]: Dialog} = {}; - updatedDialogs[peerId] = dialog; - rootScope.broadcast('dialogs_multiupdate', updatedDialogs); - } - } - break; + const dialog = this.getDialogByPeerId(peerId)[0]; + const isTopMessage = dialog && dialog.top_message === mid; + // @ts-ignore + if(message.clear_history) { // that's will never happen + if(isTopMessage) { + rootScope.broadcast('dialog_flush', {peerId}); } + } else { + rootScope.broadcast('message_edit', { + storage, + peerId, + mid + }); - case 'updateReadChannelDiscussionInbox': - case 'updateReadChannelDiscussionOutbox': - case 'updateReadHistoryInbox': - case 'updateReadHistoryOutbox': - case 'updateReadChannelInbox': - case 'updateReadChannelOutbox': { - const channelId = (update as Update.updateReadChannelInbox).channel_id; - const maxId = this.generateMessageId((update as Update.updateReadChannelInbox).max_id || (update as Update.updateReadChannelDiscussionInbox).read_max_id); - const threadId = this.generateMessageId((update as Update.updateReadChannelDiscussionInbox).top_msg_id); - const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer); + if(isTopMessage || (message as Message.message).grouped_id) { + const updatedDialogs: {[peerId: number]: Dialog} = {}; + updatedDialogs[peerId] = dialog; + rootScope.broadcast('dialogs_multiupdate', updatedDialogs); + } + } + }; - const isOut = update._ === 'updateReadHistoryOutbox' || update._ === 'updateReadChannelOutbox' || update._ === 'updateReadChannelDiscussionOutbox' ? true : undefined; + private onUpdateReadHistory = (update: Update.updateReadChannelDiscussionInbox | Update.updateReadChannelDiscussionOutbox + | Update.updateReadHistoryInbox | Update.updateReadHistoryOutbox + | Update.updateReadChannelInbox | Update.updateReadChannelOutbox) => { + const channelId = (update as Update.updateReadChannelInbox).channel_id; + const maxId = this.generateMessageId((update as Update.updateReadChannelInbox).max_id || (update as Update.updateReadChannelDiscussionInbox).read_max_id); + const threadId = this.generateMessageId((update as Update.updateReadChannelDiscussionInbox).top_msg_id); + const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer); - const storage = this.getMessagesStorage(peerId); - const history = getObjectKeysAndSort(storage, 'desc'); - const foundDialog = this.getDialogByPeerId(peerId)[0]; - const stillUnreadCount = (update as Update.updateReadChannelInbox).still_unread_count; - let newUnreadCount = 0; - let foundAffected = false; + const isOut = update._ === 'updateReadHistoryOutbox' || update._ === 'updateReadChannelOutbox' || update._ === 'updateReadChannelDiscussionOutbox' ? true : undefined; - //this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId) + const storage = this.getMessagesStorage(peerId); + const history = getObjectKeysAndSort(storage, 'desc'); + const foundDialog = this.getDialogByPeerId(peerId)[0]; + const stillUnreadCount = (update as Update.updateReadChannelInbox).still_unread_count; + let newUnreadCount = 0; + let foundAffected = false; - const historyStorage = this.getHistoryStorage(peerId, threadId); + //this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId) - if(peerId > 0 && isOut) { - appUsersManager.forceUserOnline(peerId); - } + const historyStorage = this.getHistoryStorage(peerId, threadId); - if(threadId) { - const repliesKey = this.threadsToReplies[peerId + '_' + threadId]; - if(repliesKey) { - const [peerId, mid] = repliesKey.split('_').map(n => +n); - this.updateMessage(peerId, mid, 'replies_updated'); - } - } + if(peerId > 0 && isOut) { + appUsersManager.forceUserOnline(peerId); + } - for(let i = 0, length = history.length; i < length; i++) { - const messageId = history[i]; - if(messageId > maxId) { - continue; - } - - const message = storage[messageId]; + if(threadId) { + const repliesKey = this.threadsToReplies[peerId + '_' + threadId]; + if(repliesKey) { + const [peerId, mid] = repliesKey.split('_').map(n => +n); + this.updateMessage(peerId, mid, 'replies_updated'); + } + } - if(message.pFlags.out !== isOut) { - continue; - } + for(let i = 0, length = history.length; i < length; i++) { + const messageId = history[i]; + if(messageId > maxId) { + continue; + } + + const message = storage[messageId]; - if(!message.pFlags.unread) { - break; - } + if(message.pFlags.out !== isOut) { + continue; + } - if(threadId) { - const replyTo = message.reply_to as MessageReplyHeader; - if(!replyTo || (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) !== threadId) { - continue; - } - } - - // this.log.warn('read', messageId, message.pFlags.unread, message) - if(message.pFlags.unread) { - delete message.pFlags.unread; - if(!foundAffected) { - foundAffected = true; - } + if(!message.pFlags.unread) { + break; + } - if(!message.pFlags.out && !threadId && stillUnreadCount === undefined) { - newUnreadCount = --foundDialog.unread_count; - } - - appNotificationsManager.cancel('msg' + messageId); - } + if(threadId) { + const replyTo = message.reply_to as MessageReplyHeader; + if(!replyTo || (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) !== threadId) { + continue; } - - if(isOut) historyStorage.readOutboxMaxId = maxId; - else historyStorage.readMaxId = maxId; - - if(!threadId && foundDialog) { - if(isOut) foundDialog.read_outbox_max_id = maxId; - else foundDialog.read_inbox_max_id = maxId; - - if(!isOut) { - if(newUnreadCount < 0 || !this.getReadMaxIdIfUnread(peerId)) { - foundDialog.unread_count = 0; - } else if(newUnreadCount && foundDialog.top_message > maxId) { - foundDialog.unread_count = newUnreadCount; - } - } - - rootScope.broadcast('dialog_unread', {peerId}); + } + + // this.log.warn('read', messageId, message.pFlags.unread, message) + if(message.pFlags.unread) { + delete message.pFlags.unread; + if(!foundAffected) { + foundAffected = true; } - if(foundAffected) { - rootScope.broadcast('messages_read'); + if(!message.pFlags.out && !threadId && stillUnreadCount === undefined) { + newUnreadCount = --foundDialog.unread_count; } + + appNotificationsManager.cancel('msg' + messageId); + } + } - if(!threadId && channelId) { - const threadKeyPart = peerId + '_'; - for(const threadKey in this.threadsToReplies) { - if(threadKey.indexOf(threadKeyPart) === 0) { - const [peerId, mid] = this.threadsToReplies[threadKey].split('_').map(n => +n); - rootScope.broadcast('replies_updated', this.getMessageByPeer(peerId, mid)); - } - } - } + if(isOut) historyStorage.readOutboxMaxId = maxId; + else historyStorage.readMaxId = maxId; - break; - } + if(!threadId && foundDialog) { + if(isOut) foundDialog.read_outbox_max_id = maxId; + else foundDialog.read_inbox_max_id = maxId; - case 'updateChannelReadMessagesContents': - case 'updateReadMessagesContents': { - const channelId = (update as Update.updateChannelReadMessagesContents).channel_id; - const mids = (update as Update.updateReadMessagesContents).messages.map(id => this.generateMessageId(id)); - const peerId = channelId ? -channelId : this.getMessageById(mids[0]).peerId; - for(const mid of mids) { - const message = this.getMessageByPeer(peerId, mid); - if(!message.deleted) { - delete message.pFlags.media_unread; - } + if(!isOut) { + if(newUnreadCount < 0 || !this.getReadMaxIdIfUnread(peerId)) { + foundDialog.unread_count = 0; + } else if(newUnreadCount && foundDialog.top_message > maxId) { + foundDialog.unread_count = newUnreadCount; } - - rootScope.broadcast('messages_media_read', {peerId, mids}); - break; } - case 'updateChannelAvailableMessages': { - const channelId: number = update.channel_id; - const messages: number[] = []; - const peerId: number = -channelId; - const history = this.getHistoryStorage(peerId).history.slice; - if(history.length) { - history.forEach((msgId: number) => { - if(!update.available_min_id || msgId <= update.available_min_id) { - messages.push(msgId); - } - }); - } + rootScope.broadcast('dialog_unread', {peerId}); + } - (update as any as Update.updateDeleteChannelMessages).messages = messages; - } + if(foundAffected) { + rootScope.broadcast('messages_read'); + } - case 'updateDeleteMessages': - case 'updateDeleteChannelMessages': { - const channelId: number = (update as Update.updateDeleteChannelMessages).channel_id; - //const messages = (update as any as Update.updateDeleteChannelMessages).messages; - const messages = (update as any as Update.updateDeleteChannelMessages).messages.map(id => this.generateMessageId(id)); - const peerId: number = channelId ? -channelId : this.getMessageById(messages[0]).peerId; - - if(!peerId) { - break; + if(!threadId && channelId) { + const threadKeyPart = peerId + '_'; + for(const threadKey in this.threadsToReplies) { + if(threadKey.indexOf(threadKeyPart) === 0) { + const [peerId, mid] = this.threadsToReplies[threadKey].split('_').map(n => +n); + rootScope.broadcast('replies_updated', this.getMessageByPeer(peerId, mid)); } + } + } + }; - apiManager.clearCache('messages.getSearchCounters', (params) => { - return appPeersManager.getPeerId(params.peer) === peerId; - }); + private onUpdateReadMessagesContents = (update: Update.updateChannelReadMessagesContents | Update.updateReadMessagesContents) => { + const channelId = (update as Update.updateChannelReadMessagesContents).channel_id; + const mids = (update as Update.updateReadMessagesContents).messages.map(id => this.generateMessageId(id)); + const peerId = channelId ? -channelId : this.getMessageById(mids[0]).peerId; + for(const mid of mids) { + const message = this.getMessageByPeer(peerId, mid); + if(!message.deleted) { + delete message.pFlags.media_unread; + } + } - const threadKeys: Set = new Set(); - for(const mid of messages) { - const message = this.getMessageByPeer(peerId, mid); - const threadKey = this.getThreadKey(message); - if(threadKey && this.threadsStorage[peerId] && this.threadsStorage[peerId][+threadKey.split('_')[1]]) { - threadKeys.add(threadKey); - } + rootScope.broadcast('messages_media_read', {peerId, mids}); + }; + + private onUpdateChannelAvailableMessages = (update: Update.updateChannelAvailableMessages) => { + const channelId: number = update.channel_id; + const messages: number[] = []; + const peerId: number = -channelId; + const history = this.getHistoryStorage(peerId).history.slice; + if(history.length) { + history.forEach((msgId: number) => { + if(!update.available_min_id || msgId <= update.available_min_id) { + messages.push(msgId); } - - const historyUpdated = this.handleDeletedMessages(peerId, this.getMessagesStorage(peerId), messages); + }); + } - const threadsStorages = Array.from(threadKeys).map(threadKey => { - const splitted = threadKey.split('_'); - return this.getHistoryStorage(+splitted[0], +splitted[1]); - }); + (update as any as Update.updateDeleteChannelMessages).messages = messages; + this.onUpdateDeleteMessages(update as any as Update.updateDeleteChannelMessages); + }; - [this.getHistoryStorage(peerId)].concat(threadsStorages).forEach(historyStorage => { - for(const mid in historyUpdated.msgs) { - historyStorage.history.delete(+mid); - } - if(historyUpdated.count && - historyStorage.count !== null && - historyStorage.count > 0) { - historyStorage.count -= historyUpdated.count; - if(historyStorage.count < 0) { - historyStorage.count = 0; - } - } - }); + private onUpdateDeleteMessages = (update: Update.updateDeleteMessages | Update.updateDeleteChannelMessages) => { + const channelId: number = (update as Update.updateDeleteChannelMessages).channel_id; + //const messages = (update as any as Update.updateDeleteChannelMessages).messages; + const messages = (update as any as Update.updateDeleteChannelMessages).messages.map(id => this.generateMessageId(id)); + const peerId: number = channelId ? -channelId : this.getMessageById(messages[0]).peerId; + + if(!peerId) { + return; + } - rootScope.broadcast('history_delete', {peerId, msgs: historyUpdated.msgs}); + apiManager.clearCache('messages.getSearchCounters', (params) => { + return appPeersManager.getPeerId(params.peer) === peerId; + }); - const foundDialog = this.getDialogByPeerId(peerId)[0]; - if(foundDialog) { - if(historyUpdated.unread) { - foundDialog.unread_count -= historyUpdated.unread; + const threadKeys: Set = new Set(); + for(const mid of messages) { + const message = this.getMessageByPeer(peerId, mid); + const threadKey = this.getThreadKey(message); + if(threadKey && this.threadsStorage[peerId] && this.threadsStorage[peerId][+threadKey.split('_')[1]]) { + threadKeys.add(threadKey); + } + } + + const historyUpdated = this.handleDeletedMessages(peerId, this.getMessagesStorage(peerId), messages); - rootScope.broadcast('dialog_unread', {peerId}); - } + const threadsStorages = Array.from(threadKeys).map(threadKey => { + const splitted = threadKey.split('_'); + return this.getHistoryStorage(+splitted[0], +splitted[1]); + }); - if(historyUpdated.msgs[foundDialog.top_message]) { - this.reloadConversation(peerId); - } + [this.getHistoryStorage(peerId)].concat(threadsStorages).forEach(historyStorage => { + for(const mid in historyUpdated.msgs) { + historyStorage.history.delete(+mid); + } + if(historyUpdated.count && + historyStorage.count !== null && + historyStorage.count > 0) { + historyStorage.count -= historyUpdated.count; + if(historyStorage.count < 0) { + historyStorage.count = 0; } - break; } + }); - case 'updateChannel': { - const channelId: number = update.channel_id; - const peerId = -channelId; - const channel = appChatsManager.getChat(channelId); - - const needDialog = channel._ === 'channel' && (!channel.pFlags.left && !channel.pFlags.kicked); - const foundDialog = this.getDialogByPeerId(peerId); - const hasDialog = foundDialog.length > 0; - - const canViewHistory = channel._ === 'channel' && (channel.username || !channel.pFlags.left && !channel.pFlags.kicked); - const hasHistory = this.historiesStorage[peerId] !== undefined; + rootScope.broadcast('history_delete', {peerId, msgs: historyUpdated.msgs}); - if(canViewHistory !== hasHistory) { - delete this.historiesStorage[peerId]; - rootScope.broadcast('history_forbidden', peerId); - } + const foundDialog = this.getDialogByPeerId(peerId)[0]; + if(foundDialog) { + if(historyUpdated.unread) { + foundDialog.unread_count -= historyUpdated.unread; - if(hasDialog !== needDialog) { - if(needDialog) { - this.reloadConversation(-channelId); - } else { - if(foundDialog[0]) { - this.dialogsStorage.dropDialog(peerId); - rootScope.broadcast('dialog_drop', {peerId: peerId, dialog: foundDialog[0]}); - } - } - } + rootScope.broadcast('dialog_unread', {peerId}); + } - break; + if(historyUpdated.msgs[foundDialog.top_message]) { + this.reloadConversation(peerId); } + } + }; - // @ts-ignore - case 'updateChannelReload': { - // @ts-ignore - const channelId: number = update.channel_id; - const peerId = -channelId; + private onUpdateChannel = (update: Update.updateChannel) => { + const channelId: number = update.channel_id; + const peerId = -channelId; + const channel = appChatsManager.getChat(channelId); - this.dialogsStorage.dropDialog(peerId); + const needDialog = channel._ === 'channel' && (!channel.pFlags.left && !channel.pFlags.kicked); + const foundDialog = this.getDialogByPeerId(peerId); + const hasDialog = foundDialog.length > 0; - delete this.historiesStorage[peerId]; - this.reloadConversation(-channelId).then(() => { - rootScope.broadcast('history_reload', peerId); - }); + const canViewHistory = channel._ === 'channel' && (channel.username || !channel.pFlags.left && !channel.pFlags.kicked); + const hasHistory = this.historiesStorage[peerId] !== undefined; - break; - } + if(canViewHistory !== hasHistory) { + delete this.historiesStorage[peerId]; + rootScope.broadcast('history_forbidden', peerId); + } - case 'updateChannelMessageViews': { - const views = update.views; - //const mid = update.id; - const mid = this.generateMessageId(update.id); - const message = this.getMessageByPeer(-update.channel_id, mid); - if(!message.deleted && message.views && message.views < views) { - message.views = views; - rootScope.broadcast('message_views', {mid, views}); + if(hasDialog !== needDialog) { + if(needDialog) { + this.reloadConversation(-channelId); + } else { + if(foundDialog[0]) { + this.dialogsStorage.dropDialog(peerId); + rootScope.broadcast('dialog_drop', {peerId: peerId, dialog: foundDialog[0]}); } - break; } - - case 'updateServiceNotification': { - //this.log('updateServiceNotification', update); - const fromId = 777000; - const peerId = fromId; - const messageId = this.generateTempMessageId(peerId); - const message: any = { - _: 'message', - id: messageId, - from_id: appPeersManager.getOutputPeer(fromId), - peer_id: appPeersManager.getOutputPeer(peerId), - pFlags: {unread: true}, - date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset, - message: update.message, - media: update.media, - entities: update.entities - }; - if(!appUsersManager.hasUser(fromId)) { - appUsersManager.saveApiUsers([{ - _: 'user', - id: fromId, - pFlags: {verified: true}, - access_hash: 0, - first_name: 'Telegram', - phone: '42777' - }]); - } - this.saveMessages([message], {isOutgoing: true}); - - if(update.inbox_date) { - this.pendingTopMsgs[peerId] = messageId; - this.handleUpdate({ - _: 'updateNewMessage', - message - } as any); - } + } + }; - break; - } + private onUpdateChannelReload = (update: any) => { + // @ts-ignore + const channelId: number = update.channel_id; + const peerId = -channelId; - case 'updatePinnedMessages': - case 'updatePinnedChannelMessages': { - const channelId = update._ === 'updatePinnedChannelMessages' ? update.channel_id : undefined; - const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updatePinnedMessages).peer); + this.dialogsStorage.dropDialog(peerId); - /* const storage = this.getSearchStorage(peerId, 'inputMessagesFilterPinned'); - if(storage.count !== storage.history.length) { - if(storage.count !== undefined) { - delete this.searchesStorage[peerId]['inputMessagesFilterPinned']; - } + delete this.historiesStorage[peerId]; + this.reloadConversation(-channelId).then(() => { + rootScope.broadcast('history_reload', peerId); + }); + }; + + private onUpdateChannelMessageViews = (update: Update.updateChannelMessageViews) => { + const views = update.views; + //const mid = update.id; + const mid = this.generateMessageId(update.id); + const message = this.getMessageByPeer(-update.channel_id, mid); + if(!message.deleted && message.views && message.views < views) { + message.views = views; + rootScope.broadcast('message_views', {mid, views}); + } + }; - rootScope.broadcast('peer_pinned_messages', peerId); - break; - } */ + private onUpdateServiceNotification = (update: Update.updateServiceNotification) => { + //this.log('updateServiceNotification', update); + const fromId = 777000; + const peerId = fromId; + const messageId = this.generateTempMessageId(peerId); + const message: any = { + _: 'message', + id: messageId, + from_id: appPeersManager.getOutputPeer(fromId), + peer_id: appPeersManager.getOutputPeer(peerId), + pFlags: {unread: true}, + date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset, + message: update.message, + media: update.media, + entities: update.entities + }; + if(!appUsersManager.hasUser(fromId)) { + appUsersManager.saveApiUsers([{ + _: 'user', + id: fromId, + pFlags: {verified: true}, + access_hash: 0, + first_name: 'Telegram', + phone: '42777' + }]); + } + this.saveMessages([message], {isOutgoing: true}); + + if(update.inbox_date) { + this.pendingTopMsgs[peerId] = messageId; + this.onUpdateNewMessage({ + _: 'updateNewMessage', + message + } as any); + } + }; - const messages = update.messages.map(id => this.generateMessageId(id)); + private onUpdatePinnedMessages = (update: Update.updatePinnedMessages | Update.updatePinnedChannelMessages) => { + const channelId = update._ === 'updatePinnedChannelMessages' ? update.channel_id : undefined; + const peerId = channelId ? -channelId : appPeersManager.getPeerId((update as Update.updatePinnedMessages).peer); - const storage = this.getMessagesStorage(peerId); - const missingMessages = messages.filter(mid => !storage[mid]); - const getMissingPromise = missingMessages.length ? Promise.all(missingMessages.map(mid => this.wrapSingleMessage(peerId, mid))) : Promise.resolve(); - getMissingPromise.finally(() => { - const werePinned = update.pFlags?.pinned; - if(werePinned) { - for(const mid of messages) { - //storage.history.push(mid); - const message = storage[mid]; - message.pFlags.pinned = true; - } + /* const storage = this.getSearchStorage(peerId, 'inputMessagesFilterPinned'); + if(storage.count !== storage.history.length) { + if(storage.count !== undefined) { + delete this.searchesStorage[peerId]['inputMessagesFilterPinned']; + } - /* if(this.pinnedMessages[peerId]?.maxId) { - const maxMid = Math.max(...messages); - this.pinnedMessages - } */ + rootScope.broadcast('peer_pinned_messages', peerId); + break; + } */ - //storage.history.sort((a, b) => b - a); - } else { - for(const mid of messages) { - //storage.history.findAndSplice(_mid => _mid === mid); - const message = storage[mid]; - delete message.pFlags.pinned; - } - } + const messages = update.messages.map(id => this.generateMessageId(id)); - /* const info = this.pinnedMessages[peerId]; - if(info) { - info.count += messages.length * (werePinned ? 1 : -1); - } */ - - delete this.pinnedMessages[peerId]; - appStateManager.getState().then(state => { - delete state.hiddenPinnedMessages[peerId]; - rootScope.broadcast('peer_pinned_messages', {peerId, mids: messages, pinned: werePinned}); - }); - }); + const storage = this.getMessagesStorage(peerId); + const missingMessages = messages.filter(mid => !storage[mid]); + const getMissingPromise = missingMessages.length ? Promise.all(missingMessages.map(mid => this.wrapSingleMessage(peerId, mid))) : Promise.resolve(); + getMissingPromise.finally(() => { + const werePinned = update.pFlags?.pinned; + if(werePinned) { + for(const mid of messages) { + //storage.history.push(mid); + const message = storage[mid]; + message.pFlags.pinned = true; + } - break; - } + /* if(this.pinnedMessages[peerId]?.maxId) { + const maxMid = Math.max(...messages); + this.pinnedMessages + } */ - case 'updateNotifySettings': { - const {peer, notify_settings} = update; - if(peer._ === 'notifyPeer') { - const peerId = appPeersManager.getPeerId((peer as NotifyPeer.notifyPeer).peer); - - const dialog = this.getDialogByPeerId(peerId)[0]; - if(dialog) { - dialog.notify_settings = notify_settings; - rootScope.broadcast('dialog_notify_settings', dialog); - } + //storage.history.sort((a, b) => b - a); + } else { + for(const mid of messages) { + //storage.history.findAndSplice(_mid => _mid === mid); + const message = storage[mid]; + delete message.pFlags.pinned; } + } - /////this.log('updateNotifySettings', peerId, notify_settings); - break; + /* const info = this.pinnedMessages[peerId]; + if(info) { + info.count += messages.length * (werePinned ? 1 : -1); + } */ + + delete this.pinnedMessages[peerId]; + appStateManager.getState().then(state => { + delete state.hiddenPinnedMessages[peerId]; + rootScope.broadcast('peer_pinned_messages', {peerId, mids: messages, pinned: werePinned}); + }); + }); + }; + + private onUpdateNotifySettings = (update: Update.updateNotifySettings) => { + const {peer, notify_settings} = update; + if(peer._ === 'notifyPeer') { + const peerId = appPeersManager.getPeerId((peer as NotifyPeer.notifyPeer).peer); + + const dialog = this.getDialogByPeerId(peerId)[0]; + if(dialog) { + dialog.notify_settings = notify_settings; + rootScope.broadcast('dialog_notify_settings', dialog); } + } + }; - case 'updateNewScheduledMessage': { - const message = update.message as MyMessage; - const peerId = this.getMessagePeer(message); + private onUpdateNewScheduledMessage = (update: Update.updateNewScheduledMessage) => { + const message = update.message as MyMessage; + const peerId = this.getMessagePeer(message); - const storage = this.scheduledMessagesStorage[peerId]; - if(storage) { - const mid = this.generateMessageId(message.id); + const storage = this.scheduledMessagesStorage[peerId]; + if(storage) { + const mid = this.generateMessageId(message.id); - const oldMessage = this.getMessageFromStorage(storage, mid); - this.saveMessages([message], {storage, isScheduled: true}); - const newMessage = this.getMessageFromStorage(storage, mid); + const oldMessage = this.getMessageFromStorage(storage, mid); + this.saveMessages([message], {storage, isScheduled: true}); + const newMessage = this.getMessageFromStorage(storage, mid); - if(!oldMessage.deleted) { - this.handleEditedMessage(oldMessage, newMessage); - rootScope.broadcast('message_edit', {storage, peerId, mid: message.mid}); - } else { - const pendingMessage = this.checkPendingMessage(message); - if(!pendingMessage) { - rootScope.broadcast('scheduled_new', {peerId, mid: message.mid}); - } - } + if(!oldMessage.deleted) { + this.handleEditedMessage(oldMessage, newMessage); + rootScope.broadcast('message_edit', {storage, peerId, mid: message.mid}); + } else { + const pendingMessage = this.checkPendingMessage(message); + if(!pendingMessage) { + rootScope.broadcast('scheduled_new', {peerId, mid: message.mid}); } - - break; } + } + }; - case 'updateDeleteScheduledMessages': { - const peerId = appPeersManager.getPeerId(update.peer); - - const storage = this.scheduledMessagesStorage[peerId]; - if(storage) { - const mids = update.messages.map(id => this.generateMessageId(id)); - this.handleDeletedMessages(peerId, storage, mids); + private onUpdateDeleteScheduledMessages = (update: Update.updateDeleteScheduledMessages) => { + const peerId = appPeersManager.getPeerId(update.peer); - rootScope.broadcast('scheduled_delete', {peerId, mids}); - } + const storage = this.scheduledMessagesStorage[peerId]; + if(storage) { + const mids = update.messages.map(id => this.generateMessageId(id)); + this.handleDeletedMessages(peerId, storage, mids); - break; - } + rootScope.broadcast('scheduled_delete', {peerId, mids}); } - } + }; private updateMessageRepliesIfNeeded(threadMessage: MyMessage) { try { // * на всякий случай, скорее всего это не понадобится diff --git a/src/lib/appManagers/appNotificationsManager.ts b/src/lib/appManagers/appNotificationsManager.ts index 1f5638fb..3578e2e2 100644 --- a/src/lib/appManagers/appNotificationsManager.ts +++ b/src/lib/appManagers/appNotificationsManager.ts @@ -13,7 +13,7 @@ import { fontFamily } from "../../components/middleEllipsis"; import { MOUNT_CLASS_TO } from "../../config/debug"; import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise"; import { tsNow } from "../../helpers/date"; -import { copy, deepEqual } from "../../helpers/object"; +import { deepEqual } from "../../helpers/object"; import { convertInputKeyToKey } from "../../helpers/string"; import { isMobile } from "../../helpers/userAgent"; import { InputNotifyPeer, InputPeerNotifySettings, NotifyPeer, PeerNotifySettings, Update } from "../../layer"; @@ -114,14 +114,10 @@ export class AppNotificationsManager { this.toggleToggler(); }); - rootScope.on('apiUpdate', (update) => { - // console.log('on apiUpdate', update) - switch(update._) { - case 'updateNotifySettings': { - this.savePeerSettings(update.peer._ === 'notifyPeer' ? appPeersManager.getPeerId(update.peer.peer) : update.peer._, update.notify_settings); - rootScope.broadcast('notify_settings', update); - break; - } + rootScope.addMultipleEventsListeners({ + updateNotifySettings: (update) => { + this.savePeerSettings(update.peer._ === 'notifyPeer' ? appPeersManager.getPeerId(update.peer.peer) : update.peer._, update.notify_settings); + rootScope.broadcast('notify_settings', update); } }); diff --git a/src/lib/appManagers/appPeersManager.ts b/src/lib/appManagers/appPeersManager.ts index 8c17aba0..6a02c29b 100644 --- a/src/lib/appManagers/appPeersManager.ts +++ b/src/lib/appManagers/appPeersManager.ts @@ -37,14 +37,9 @@ const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5]; export type PeerType = 'channel' | 'chat' | 'megagroup' | 'group' | 'saved'; export class AppPeersManager { constructor() { - rootScope.on('apiUpdate', (e) => { - const update = e as Update; - //console.log('on apiUpdate', update); - switch(update._) { - case 'updatePeerBlocked': { - rootScope.broadcast('peer_block', {peerId: this.getPeerId(update.peer_id), blocked: update.blocked}); - break; - } + rootScope.addMultipleEventsListeners({ + updatePeerBlocked: (update) => { + rootScope.broadcast('peer_block', {peerId: this.getPeerId(update.peer_id), blocked: update.blocked}); } }); } diff --git a/src/lib/appManagers/appPollsManager.ts b/src/lib/appManagers/appPollsManager.ts index 938890ac..5881ccaf 100644 --- a/src/lib/appManagers/appPollsManager.ts +++ b/src/lib/appManagers/appPollsManager.ts @@ -83,31 +83,19 @@ export class AppPollsManager { private log = logger('POLLS', LogLevels.error); constructor() { - rootScope.on('apiUpdate', (e) => { - const update = e; - - this.handleUpdate(update); - }); - } - - public handleUpdate(update: any) { - switch(update._) { - case 'updateMessagePoll': { // when someone voted, we too + rootScope.addMultipleEventsListeners({ + updateMessagePoll: (update) => { this.log('updateMessagePoll:', update); let poll: Poll = update.poll || this.polls[update.poll_id]; if(!poll) { - break; + return; } - poll = this.savePoll(poll, update.results); - rootScope.broadcast('poll_update', {poll, results: update.results}); - break; + poll = this.savePoll(poll, update.results as any); + rootScope.broadcast('poll_update', {poll, results: update.results as any}); } - - default: - break; - } + }); } public savePoll(poll: Poll, results: PollResults) { diff --git a/src/lib/appManagers/appPrivacyManager.ts b/src/lib/appManagers/appPrivacyManager.ts index f07e06b2..ebad25b6 100644 --- a/src/lib/appManagers/appPrivacyManager.ts +++ b/src/lib/appManagers/appPrivacyManager.ts @@ -25,15 +25,11 @@ export class AppPrivacyManager { }> = {}; constructor() { - rootScope.on('apiUpdate', (e) => { - const update = e as Update; - - switch(update._) { - case 'updatePrivacy': - const key = update.key._; - this.privacy[key] = update.rules; - rootScope.broadcast('privacy_update', update); - break; + rootScope.addMultipleEventsListeners({ + updatePrivacy: (update) => { + const key = update.key._; + this.privacy[key] = update.rules; + rootScope.broadcast('privacy_update', update); } }); } diff --git a/src/lib/appManagers/appProfileManager.ts b/src/lib/appManagers/appProfileManager.ts index e8ec8adc..46ec7473 100644 --- a/src/lib/appManagers/appProfileManager.ts +++ b/src/lib/appManagers/appProfileManager.ts @@ -42,67 +42,59 @@ export class AppProfileManager { } = {}; constructor() { - rootScope.on('apiUpdate', (update) => { - switch(update._) { - case 'updateChatParticipants': { - const participants = update.participants; - if(participants._ === 'chatParticipants') { - const chatId = participants.chat_id; - const chatFull = this.chatsFull[chatId] as ChatFull.chatFull; - if(chatFull !== undefined) { - chatFull.participants = participants; - rootScope.broadcast('chat_full_update', chatId); - } + rootScope.addMultipleEventsListeners({ + updateChatParticipants: (update) => { + const participants = update.participants; + if(participants._ === 'chatParticipants') { + const chatId = participants.chat_id; + const chatFull = this.chatsFull[chatId] as ChatFull.chatFull; + if(chatFull !== undefined) { + chatFull.participants = participants; + rootScope.broadcast('chat_full_update', chatId); } - - break; } - - case 'updateChatParticipantAdd': { - const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; - if(chatFull !== undefined) { - const _participants = chatFull.participants as ChatParticipants.chatParticipants; - const participants = _participants.participants || []; - for(let i = 0, length = participants.length; i < length; i++) { - if(participants[i].user_id === update.user_id) { - return; - } + }, + + updateChatParticipantAdd: (update) => { + const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; + if(chatFull !== undefined) { + const _participants = chatFull.participants as ChatParticipants.chatParticipants; + const participants = _participants.participants || []; + for(let i = 0, length = participants.length; i < length; i++) { + if(participants[i].user_id === update.user_id) { + return; } - - participants.push({ - _: 'chatParticipant', - user_id: update.user_id, - inviter_id: update.inviter_id, - date: tsNow(true) - }); - - _participants.version = update.version; - rootScope.broadcast('chat_full_update', update.chat_id); } - break; + participants.push({ + _: 'chatParticipant', + user_id: update.user_id, + inviter_id: update.inviter_id, + date: tsNow(true) + }); + + _participants.version = update.version; + rootScope.broadcast('chat_full_update', update.chat_id); } - - case 'updateChatParticipantDelete': { - const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; - if(chatFull !== undefined) { - const _participants = chatFull.participants as ChatParticipants.chatParticipants; - const participants = _participants.participants || []; - for(let i = 0, length = participants.length; i < length; i++) { - if(participants[i].user_id === update.user_id) { - participants.splice(i, 1); - _participants.version = update.version; - rootScope.broadcast('chat_full_update', update.chat_id); - return; - } + }, + + updateChatParticipantDelete: (update) => { + const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull; + if(chatFull !== undefined) { + const _participants = chatFull.participants as ChatParticipants.chatParticipants; + const participants = _participants.participants || []; + for(let i = 0, length = participants.length; i < length; i++) { + if(participants[i].user_id === update.user_id) { + participants.splice(i, 1); + _participants.version = update.version; + rootScope.broadcast('chat_full_update', update.chat_id); + return; } } - - break; } } }); - + rootScope.on('chat_update', (chatId) => { const fullChat = this.chatsFull[chatId]; const chat = appChatsManager.getChat(chatId); diff --git a/src/lib/appManagers/appStickersManager.ts b/src/lib/appManagers/appStickersManager.ts index fcb331f0..b1e7d2d5 100644 --- a/src/lib/appManagers/appStickersManager.ts +++ b/src/lib/appManagers/appStickersManager.ts @@ -26,17 +26,12 @@ export class AppStickersManager { constructor() { this.getStickerSet({id: 'emoji', access_hash: ''}, {overwrite: true}); - rootScope.on('apiUpdate', (e) => { - const update = e; - - switch(update._) { - case 'updateNewStickerSet': { - this.saveStickerSet(update.stickerset, update.stickerset.set.id); - rootScope.broadcast('stickers_installed', update.stickerset.set); - break; - } + rootScope.addMultipleEventsListeners({ + updateNewStickerSet: (update) => { + this.saveStickerSet(update.stickerset, update.stickerset.set.id); + rootScope.broadcast('stickers_installed', update.stickerset.set); } - }); + }) } public saveStickers(docs: Document[]) { diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 8fa00580..7dc71d5c 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -13,7 +13,7 @@ import { formatPhoneNumber } from "../../components/misc"; import { MOUNT_CLASS_TO } from "../../config/debug"; import { tsNow } from "../../helpers/date"; import { safeReplaceObject, isObject } from "../../helpers/object"; -import { InputUser, Update, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer"; +import { InputUser, Update, User as MTUser, UserStatus } from "../../layer"; import I18n, { i18n, LangPackKey } from "../langPack"; //import apiManager from '../mtproto/apiManager'; import apiManager from '../mtproto/mtprotoworker'; @@ -22,6 +22,7 @@ import serverTimeManager from "../mtproto/serverTimeManager"; import { RichTextProcessor } from "../richtextprocessor"; import rootScope from "../rootScope"; import searchIndexManager from "../searchIndexManager"; +//import AppStorage from "../storage"; import apiUpdatesManager from "./apiUpdatesManager"; import appChatsManager from "./appChatsManager"; import appPeersManager from "./appPeersManager"; @@ -32,12 +33,15 @@ import appStateManager from "./appStateManager"; export type User = MTUser.user; export class AppUsersManager { + /* private storage = new AppStorage>({ + storeName: 'users' + }); */ + private users: {[userId: number]: User} = {}; private usernames: {[username: string]: number} = {}; - //public userAccess: {[userId: number]: string} = {}; private contactsIndex = searchIndexManager.createIndex(); private contactsFillPromise: Promise>; - public contactsList: Set = new Set(); + private contactsList: Set = new Set(); private updatedContactsList = false; private getTopPeersPromise: Promise; @@ -47,73 +51,63 @@ export class AppUsersManager { rootScope.on('state_synchronized', this.updateUsersStatuses); - rootScope.on('apiUpdate', (e) => { - const update = e as Update; - //console.log('on apiUpdate', update); - switch(update._) { - case 'updateUserStatus': { - const userId = update.user_id; - const user = this.users[userId]; - if(user) { - user.status = update.status; - if(user.status) { - if('expires' in user.status) { - user.status.expires -= serverTimeManager.serverTimeOffset; - } - - if('was_online' in user.status) { - user.status.was_online -= serverTimeManager.serverTimeOffset; - } + rootScope.addMultipleEventsListeners({ + updateUserStatus: (update) => { + const userId = update.user_id; + const user = this.users[userId]; + if(user) { + user.status = update.status; + if(user.status) { + if('expires' in user.status) { + user.status.expires -= serverTimeManager.serverTimeOffset; } - user.sortStatus = this.getUserStatusForSort(user.status); - rootScope.broadcast('user_update', userId); - } //////else console.warn('No user by id:', userId); - - break; - } - - case 'updateUserPhoto': { - const userId = update.user_id; - const user = this.users[userId]; - if(user) { - this.forceUserOnline(userId); - - if(update.photo._ === 'userProfilePhotoEmpty') { - delete user.photo; - } else { - user.photo = safeReplaceObject(user.photo, update.photo); + if('was_online' in user.status) { + user.status.was_online -= serverTimeManager.serverTimeOffset; } + } - rootScope.broadcast('user_update', userId); - rootScope.broadcast('avatar_update', userId); - } else console.warn('No user by id:', userId); - - break; - } - - case 'updateUserName': { - const userId = update.user_id; - const user = this.users[userId]; - if(user) { - this.forceUserOnline(userId); - - this.saveApiUser(Object.assign({}, user, { - first_name: update.first_name, - last_name: update.last_name, - username: update.username - })); + user.sortStatus = this.getUserStatusForSort(user.status); + rootScope.broadcast('user_update', userId); + } //////else console.warn('No user by id:', userId); + }, + + updateUserPhoto: (update) => { + const userId = update.user_id; + const user = this.users[userId]; + if(user) { + this.forceUserOnline(userId); + + if(update.photo._ === 'userProfilePhotoEmpty') { + delete user.photo; + } else { + user.photo = safeReplaceObject(user.photo, update.photo); } - break; - } + rootScope.broadcast('user_update', userId); + rootScope.broadcast('avatar_update', userId); + } else console.warn('No user by id:', userId); + }, - /* case 'updateContactLink': - this.onContactUpdated(update.user_id, update.my_link._ === 'contactLinkContact'); - break; */ + updateUserName: (update) => { + const userId = update.user_id; + const user = this.users[userId]; + if(user) { + this.forceUserOnline(userId); + + this.saveApiUser(Object.assign({}, user, { + first_name: update.first_name, + last_name: update.last_name, + username: update.username + })); + } } }); + /* case 'updateContactLink': + this.onContactUpdated(update.user_id, update.my_link._ === 'contactLinkContact'); + break; */ + rootScope.on('language_change', (e) => { const userId = this.getSelf().id; searchIndexManager.indexObject(userId, this.getUserSearchText(userId), this.contactsIndex); @@ -350,19 +344,14 @@ export class AppUsersManager { } safeReplaceObject(oldUser, user); + rootScope.broadcast('user_update', userId); } - rootScope.broadcast('user_update', userId); - if(changedTitle) { rootScope.broadcast('peer_title_edit', user.id); } } - /* public saveUserAccess(id: number, accessHash: string) { - this.userAccess[id] = accessHash; - } */ - public getUserStatusForSort(status: User['status'] | number) { if(typeof(status) === 'number') { status = this.getUser(status).status; @@ -401,7 +390,7 @@ export class AppUsersManager { return id; } - return this.users[id] || {id: id, pFlags: {deleted: true}, access_hash: ''/* this.userAccess[id] */} as User; + return this.users[id] || {id: id, pFlags: {deleted: true}, access_hash: ''} as User; } public getSelf() { @@ -755,7 +744,7 @@ export class AppUsersManager { } public onContactUpdated(userId: number, isContact: boolean) { - const curIsContact = this.contactsList.has(userId); + const curIsContact = this.isContact(userId); if(isContact !== curIsContact) { if(isContact) { this.contactsList.add(userId) diff --git a/src/lib/appManagers/appWebPagesManager.ts b/src/lib/appManagers/appWebPagesManager.ts index 35c83829..d3f018a6 100644 --- a/src/lib/appManagers/appWebPagesManager.ts +++ b/src/lib/appManagers/appWebPagesManager.ts @@ -26,13 +26,9 @@ export class AppWebPagesManager { } = {}; constructor() { - rootScope.on('apiUpdate', (e) => { - const update = e; - - switch(update._) { - case 'updateWebPage': - this.saveWebPage(update.webpage); - break; + rootScope.addMultipleEventsListeners({ + updateWebPage: (update) => { + this.saveWebPage(update.webpage); } }); } diff --git a/src/lib/cacheStorage.ts b/src/lib/cacheStorage.ts index b675d4bc..19f56738 100644 --- a/src/lib/cacheStorage.ts +++ b/src/lib/cacheStorage.ts @@ -11,15 +11,15 @@ import FileManager from './filemanager'; //import { logger } from './polyfill'; export default class CacheStorageController { - public static STORAGES: CacheStorageController[] = []; + private static STORAGES: CacheStorageController[] = []; //public dbName = 'cachedFiles'; - public openDbPromise: Promise; + private openDbPromise: Promise; - public useStorage = true; + private useStorage = true; //private log: ReturnType = logger('CS'); - constructor(public dbName: string) { + constructor(private dbName: string) { if(Modes.test) { this.dbName += '_test'; } @@ -28,7 +28,7 @@ export default class CacheStorageController { CacheStorageController.STORAGES.push(this); } - public openDatabase(): Promise { + private openDatabase(): Promise { if(this.openDbPromise) { return this.openDbPromise; } diff --git a/src/lib/rootScope.ts b/src/lib/rootScope.ts index 92201138..c383a546 100644 --- a/src/lib/rootScope.ts +++ b/src/lib/rootScope.ts @@ -4,7 +4,7 @@ * https://github.com/morethanwords/tweb/blob/master/LICENSE */ -import type { Message, StickerSet, Update, NotifyPeer, PeerNotifySettings } from "../layer"; +import type { Message, StickerSet, Update, NotifyPeer, PeerNotifySettings, ConstructorDeclMap } from "../layer"; import type { MyDocument } from "./appManagers/appDocsManager"; import type { AppMessagesManager, Dialog, MessagesStorage } from "./appManagers/appMessagesManager"; import type { Poll, PollResults } from "./appManagers/appPollsManager"; @@ -86,7 +86,6 @@ export type BroadcastEvents = { 'channel_settings': {channelId: number}, 'webpage_updated': {id: string, msgs: number[]}, - 'apiUpdate': Update, 'download_progress': any, 'connection_status_change': ConnectionStatusChange, 'settings_updated': {key: string, value: any}, @@ -112,7 +111,11 @@ export type BroadcastEvents = { 'language_change': void, }; -export class RootScope extends EventListenerBase { +export class RootScope extends EventListenerBase<{ + [name in Update['_']]: (update: ConstructorDeclMap[name]) => void +} & { + [name in keyof BroadcastEvents]: (e: BroadcastEvents[name]) => void +}> { private _overlayIsActive: boolean = false; public myId = 0; public idle = { diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 85a95a52..e93dee71 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -13,7 +13,7 @@ import { DatabaseStore, DatabaseStoreName } from "../config/database"; import IDBStorage, { IDBOptions } from "./idb"; export default class AppStorage/* Storage extends {[name: string]: any} *//* Storage extends Record */> { - public static STORAGES: AppStorage[] = []; + private static STORAGES: AppStorage[] = []; private storage: IDBStorage;//new CacheStorageController('session'); //private cache: Partial<{[key: string]: Storage[typeof key]}> = {}; diff --git a/src/lib/storages/filters.ts b/src/lib/storages/filters.ts index 71866ad6..7ead8919 100644 --- a/src/lib/storages/filters.ts +++ b/src/lib/storages/filters.ts @@ -13,6 +13,7 @@ import type { AppUsersManager } from "../appManagers/appUsersManager"; import type _rootScope from "../rootScope"; import type {AppMessagesManager, Dialog} from '../appManagers/appMessagesManager'; import type {AppNotificationsManager} from "../appManagers/appNotificationsManager"; +import type { ApiUpdatesManager } from "../appManagers/apiUpdatesManager"; import apiManager from "../mtproto/mtprotoworker"; import { forEachReverse } from "../../helpers/array"; @@ -34,30 +35,14 @@ export default class FiltersStorage { private appPeersManager: AppPeersManager, private appUsersManager: AppUsersManager, private appNotificationsManager: AppNotificationsManager, + private apiUpdatesManager: ApiUpdatesManager, /* private apiManager: ApiManagerProxy, */ private rootScope: typeof _rootScope) { - rootScope.on('apiUpdate', (e) => { - this.handleUpdate(e); - }); - } - - public handleUpdate(update: Update) { - switch(update._) { - case 'updateDialogFilter': { - //console.log('updateDialogFilter', update); - - if(update.filter) { - this.saveDialogFilter(update.filter as any); - } else if(this.filters[update.id]) { // Папка удалена - //this.getDialogFilters(true); - this.rootScope.broadcast('filter_delete', this.filters[update.id]); - delete this.filters[update.id]; - } - break; - } + rootScope.addMultipleEventsListeners({ + updateDialogFilter: this.onUpdateDialogFilter, - case 'updateDialogFilters': { + updateDialogFilters: (update) => { //console.warn('updateDialogFilters', update); const oldFilters = copy(this.filters); @@ -66,32 +51,40 @@ export default class FiltersStorage { for(const _filterId in oldFilters) { const filterId = +_filterId; if(!filters.find(filter => filter.id === filterId)) { // * deleted - this.handleUpdate({_: 'updateDialogFilter', id: filterId}); + this.onUpdateDialogFilter({_: 'updateDialogFilter', id: filterId}); } } - this.handleUpdate({_: 'updateDialogFilterOrder', order: filters.map(filter => filter.id)}); + this.onUpdateDialogFilterOrder({_: 'updateDialogFilterOrder', order: filters.map(filter => filter.id)}); }); + }, - break; - } + updateDialogFilterOrder: this.onUpdateDialogFilterOrder + }); + } - case 'updateDialogFilterOrder': { - //console.log('updateDialogFilterOrder', update); + private onUpdateDialogFilter = (update: Update.updateDialogFilter) => { + if(update.filter) { + this.saveDialogFilter(update.filter as any); + } else if(this.filters[update.id]) { // Папка удалена + //this.getDialogFilters(true); + this.rootScope.broadcast('filter_delete', this.filters[update.id]); + delete this.filters[update.id]; + } + }; - this.orderIndex = START_ORDER_INDEX; - update.order.forEach((filterId, idx) => { - const filter = this.filters[filterId]; - delete filter.orderIndex; - this.setOrderIndex(filter); - }); + private onUpdateDialogFilterOrder = (update: Update.updateDialogFilterOrder) => { + //console.log('updateDialogFilterOrder', update); - this.rootScope.broadcast('filter_order', update.order); - - break; - } - } - } + this.orderIndex = START_ORDER_INDEX; + update.order.forEach((filterId, idx) => { + const filter = this.filters[filterId]; + delete filter.orderIndex; + this.setOrderIndex(filter); + }); + + this.rootScope.broadcast('filter_order', update.order); + }; public testDialogForFilter(dialog: Dialog, filter: MyDialogFilter) { // exclude_peers @@ -146,12 +139,12 @@ export default class FiltersStorage { } // non_contacts - if(pFlags.non_contacts && !this.appUsersManager.contactsList.has(peerId)) { + if(pFlags.non_contacts && !this.appUsersManager.isContact(peerId)) { return true; } // contacts - if(pFlags.contacts && this.appUsersManager.contactsList.has(peerId)) { + if(pFlags.contacts && this.appUsersManager.isContact(peerId)) { return true; } } @@ -194,7 +187,7 @@ export default class FiltersStorage { rootScope.$broadcast('filter_update', filter); */ - this.handleUpdate({ + this.onUpdateDialogFilter({ _: 'updateDialogFilter', id: filter.id, filter: remove ? undefined : filter as any