From e374122d8540445a9a1deaf76f21c44ce4849c92 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Thu, 15 Jul 2021 21:50:29 +0300 Subject: [PATCH] [Refactoring] Optimize fetching notify exceptions (#1277) --- src/api/gramjs/apiBuilders/misc.ts | 16 ++++++++++++ src/api/gramjs/methods/chats.ts | 2 +- src/api/gramjs/methods/settings.ts | 28 ++++++++++++++++----- src/api/gramjs/updater.ts | 14 ++--------- src/api/types/misc.ts | 7 ++++++ src/api/types/updates.ts | 8 ++---- src/modules/actions/api/settings.ts | 14 +++++++++-- src/modules/actions/apiUpdaters/settings.ts | 8 +++--- src/modules/reducers/settings.ts | 12 +++++++++ src/util/notifications.ts | 16 ++++++++---- 10 files changed, 89 insertions(+), 36 deletions(-) diff --git a/src/api/gramjs/apiBuilders/misc.ts b/src/api/gramjs/apiBuilders/misc.ts index 52650360e..ef8ee0f1b 100644 --- a/src/api/gramjs/apiBuilders/misc.ts +++ b/src/api/gramjs/apiBuilders/misc.ts @@ -4,6 +4,7 @@ import { ApiSession, ApiWallpaper } from '../../types'; import { ApiPrivacySettings, ApiPrivacyKey, PrivacyVisibility } from '../../../types'; import { buildApiDocument } from './messages'; +import { getApiChatIdFromMtpPeer } from './chats'; import { pick } from '../../../util/iteratees'; export function buildApiWallpaper(wallpaper: GramJs.TypeWallPaper): ApiWallpaper | undefined { @@ -96,3 +97,18 @@ export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySe blockChatIds: blockChatIds || [], }; } + +export function buildApiNotifyException( + notifySettings: GramJs.TypePeerNotifySettings, peer: GramJs.TypePeer, serverTimeOffset: number, +) { + const { + silent, muteUntil, showPreviews, sound, + } = notifySettings; + + return { + chatId: getApiChatIdFromMtpPeer(peer), + isMuted: silent || (typeof muteUntil === 'number' && Date.now() + serverTimeOffset * 1000 < muteUntil * 1000), + ...(sound === '' && { isSilent: true }), + ...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }), + }; +} diff --git a/src/api/gramjs/methods/chats.ts b/src/api/gramjs/methods/chats.ts index 1e0cf1da7..9cee391e9 100644 --- a/src/api/gramjs/methods/chats.ts +++ b/src/api/gramjs/methods/chats.ts @@ -414,7 +414,7 @@ export async function updateChatMutedState({ onUpdate({ '@type': 'updateNotifyExceptions', - id: chat.id, + chatId: chat.id, isMuted, }); diff --git a/src/api/gramjs/methods/settings.ts b/src/api/gramjs/methods/settings.ts index c1c2c2049..df7499468 100644 --- a/src/api/gramjs/methods/settings.ts +++ b/src/api/gramjs/methods/settings.ts @@ -2,12 +2,14 @@ import BigInt from 'big-integer'; import { Api as GramJs } from '../../../lib/gramjs'; import { - ApiChat, ApiLangString, ApiLanguage, ApiUser, ApiWallpaper, + ApiChat, ApiLangString, ApiLanguage, ApiNotifyException, ApiUser, ApiWallpaper, } from '../../types'; import { ApiPrivacyKey, IInputPrivacyRules } from '../../../types'; import { BLOCKED_LIST_LIMIT, DEFAULT_LANG_PACK } from '../../../config'; -import { buildApiWallpaper, buildApiSession, buildPrivacyRules } from '../apiBuilders/misc'; +import { + buildApiWallpaper, buildApiSession, buildPrivacyRules, buildApiNotifyException, +} from '../apiBuilders/misc'; import { buildApiUser } from '../apiBuilders/users'; import { buildApiChatFromPreview, getApiChatIdFromMtpPeer } from '../apiBuilders/chats'; @@ -156,12 +158,26 @@ export function terminateAllAuthorizations() { return invokeRequest(new GramJs.auth.ResetAuthorizations()); } -export async function fetchNotificationExceptions() { - const result = await invokeRequest(new GramJs.account.GetNotifyExceptions({ compareSound: true }), true); +export async function fetchNotificationExceptions({ + serverTimeOffset, +}: { serverTimeOffset: number }) { + const result = await invokeRequest(new GramJs.account.GetNotifyExceptions({ compareSound: true })); - if (result instanceof GramJs.Updates || result instanceof GramJs.UpdatesCombined) { - updateLocalDb(result); + if (!(result instanceof GramJs.Updates || result instanceof GramJs.UpdatesCombined)) { + return undefined; } + + updateLocalDb(result); + + return result.updates.reduce((acc, update) => { + if (!(update instanceof GramJs.UpdateNotifySettings && update.peer instanceof GramJs.NotifyPeer)) { + return acc; + } + + acc.push(buildApiNotifyException(update.notifySettings, update.peer.peer, serverTimeOffset)); + + return acc; + }, [] as ApiNotifyException[]); } export async function fetchNotificationSettings({ diff --git a/src/api/gramjs/updater.ts b/src/api/gramjs/updater.ts index cc77b75ee..34ab5f241 100644 --- a/src/api/gramjs/updater.ts +++ b/src/api/gramjs/updater.ts @@ -33,7 +33,7 @@ import localDb from './localDb'; import { omitVirtualClassFields } from './apiBuilders/helpers'; import { DEBUG } from '../../config'; import { addMessageToLocalDb, addPhotoToLocalDb, resolveMessageApiChatId } from './helpers'; -import { buildPrivacyKey, buildPrivacyRules } from './apiBuilders/misc'; +import { buildApiNotifyException, buildPrivacyKey, buildPrivacyRules } from './apiBuilders/misc'; import { buildApiPhoto } from './apiBuilders/common'; type Update = ( @@ -548,19 +548,9 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) { update instanceof GramJs.UpdateNotifySettings && update.peer instanceof GramJs.NotifyPeer ) { - const { - silent, muteUntil, showPreviews, sound, - } = update.notifySettings; - - const isMuted = silent - || (typeof muteUntil === 'number' && Date.now() + serverTimeOffset * 1000 < muteUntil * 1000); - onUpdate({ '@type': 'updateNotifyExceptions', - id: getApiChatIdFromMtpPeer(update.peer.peer), - isMuted, - ...(sound === '' && { isSilent: true }), - ...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }), + ...buildApiNotifyException(update.notifySettings, update.peer.peer, serverTimeOffset), }); } else if ( update instanceof GramJs.UpdateUserTyping diff --git a/src/api/types/misc.ts b/src/api/types/misc.ts index 510d7ea21..ec47a1fd4 100644 --- a/src/api/types/misc.ts +++ b/src/api/types/misc.ts @@ -60,3 +60,10 @@ export interface ApiSessionData { keys: Record; hashes: Record; } + +export type ApiNotifyException = { + chatId: number; + isMuted: boolean; + isSilent?: boolean; + shouldShowPreviews?: boolean; +}; diff --git a/src/api/types/updates.ts b/src/api/types/updates.ts index 5aaaf1941..e53becab2 100644 --- a/src/api/types/updates.ts +++ b/src/api/types/updates.ts @@ -9,7 +9,7 @@ import { ApiFormattedText, ApiMessage, ApiPhoto, ApiPoll, ApiStickerSet, ApiThreadInfo, } from './messages'; import { ApiUser, ApiUserFullInfo, ApiUserStatus } from './users'; -import { ApiSessionData } from './misc'; +import { ApiNotifyException, ApiSessionData } from './misc'; export type ApiUpdateReady = { '@type': 'updateApiReady'; @@ -358,11 +358,7 @@ export type ApiUpdateNotifySettings = { export type ApiUpdateNotifyExceptions = { '@type': 'updateNotifyExceptions'; - id: number; - isMuted: boolean; - isSilent?: boolean; - shouldShowPreviews?: boolean; -}; +} & ApiNotifyException; export type updateTwoFaStateWaitCode = { '@type': 'updateTwoFaStateWaitCode'; diff --git a/src/modules/actions/api/settings.ts b/src/modules/actions/api/settings.ts index 01c01537c..e346c9132 100644 --- a/src/modules/actions/api/settings.ts +++ b/src/modules/actions/api/settings.ts @@ -11,6 +11,7 @@ import { buildCollectionByKey } from '../../../util/iteratees'; import { selectUser } from '../../selectors'; import { addUsers, addBlockedContact, updateChats, updateUser, removeBlockedContact, replaceSettings, updateNotifySettings, + addNotifyExceptions, } from '../../reducers'; import { isChatPrivate } from '../../helpers'; @@ -304,8 +305,17 @@ addReducer('terminateAllAuthorizations', () => { })(); }); -addReducer('loadNotificationExceptions', () => { - callApi('fetchNotificationExceptions'); +addReducer('loadNotificationExceptions', (global) => { + const { serverTimeOffset } = global; + + (async () => { + const result = await callApi('fetchNotificationExceptions', { serverTimeOffset }); + if (!result) { + return; + } + + setGlobal(addNotifyExceptions(getGlobal(), result)); + })(); }); addReducer('loadNotificationSettings', (global) => { diff --git a/src/modules/actions/apiUpdaters/settings.ts b/src/modules/actions/apiUpdaters/settings.ts index 1993be052..b120d0095 100644 --- a/src/modules/actions/apiUpdaters/settings.ts +++ b/src/modules/actions/apiUpdaters/settings.ts @@ -12,15 +12,15 @@ addReducer('apiUpdate', (global, actions, update: ApiUpdate): GlobalState | unde case 'updateNotifyExceptions': { const { - id, isMuted, isSilent, shouldShowPreviews, + chatId, isMuted, isSilent, shouldShowPreviews, } = update; - const chat = global.chats.byId[id]; + const chat = global.chats.byId[chatId]; if (chat) { - global = updateChat(global, id, { isMuted }); + global = updateChat(global, chatId, { isMuted }); } - setGlobal(addNotifyException(global, id, { isMuted, isSilent, shouldShowPreviews })); + setGlobal(addNotifyException(global, chatId, { isMuted, isSilent, shouldShowPreviews })); break; } } diff --git a/src/modules/reducers/settings.ts b/src/modules/reducers/settings.ts index 86f6f76ef..6f17c0019 100644 --- a/src/modules/reducers/settings.ts +++ b/src/modules/reducers/settings.ts @@ -2,6 +2,7 @@ import { GlobalState } from '../../global/types'; import { ISettings, IThemeSettings, ThemeKey, NotifyException, } from '../../types'; +import { ApiNotifyException } from '../../api/types'; export function replaceSettings(global: GlobalState, newSettings?: Partial): GlobalState { return { @@ -34,6 +35,17 @@ export function replaceThemeSettings( }; } +export function addNotifyExceptions( + global: GlobalState, notifyExceptions: ApiNotifyException[], +): GlobalState { + notifyExceptions.forEach((notifyException) => { + const { chatId, ...exceptionData } = notifyException; + global = addNotifyException(global, chatId, exceptionData); + }); + + return global; +} + export function addNotifyException( global: GlobalState, id: number, notifyException: NotifyException, ): GlobalState { diff --git a/src/util/notifications.ts b/src/util/notifications.ts index afa427a03..1f53f5e4f 100644 --- a/src/util/notifications.ts +++ b/src/util/notifications.ts @@ -14,7 +14,7 @@ import { selectIsChatMuted, } from '../modules/helpers'; import { getTranslation } from './langProvider'; -import { replaceSettings } from '../modules/reducers'; +import { addNotifyExceptions, replaceSettings } from '../modules/reducers'; import { selectChatMessage, selectNotifyExceptions, selectNotifySettings, selectUser, } from '../modules/selectors'; @@ -132,15 +132,21 @@ let areSettingsLoaded = false; // Load notification settings from the api async function loadNotificationSettings() { if (areSettingsLoaded) return; - const [result] = await Promise.all([ + const [resultSettings, resultExceptions] = await Promise.all([ callApi('fetchNotificationSettings', { serverTimeOffset: getGlobal().serverTimeOffset, }), - callApi('fetchNotificationExceptions'), + callApi('fetchNotificationExceptions', { + serverTimeOffset: getGlobal().serverTimeOffset, + }), ]); - if (!result) return; + if (!resultSettings) return; - setGlobal(replaceSettings(getGlobal(), result)); + let global = replaceSettings(getGlobal(), resultSettings); + if (resultExceptions) { + global = addNotifyExceptions(global, resultExceptions); + } + setGlobal(global); areSettingsLoaded = true; }