From 2289fbff07c95a98032cb19727d458a43c243943 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Sat, 17 Oct 2020 01:31:58 +0300 Subject: [PATCH] Improve state save performance --- src/helpers/json.ts | 7 +- src/layer.d.ts | 9 +- src/lib/appManagers/appChatsManager.ts | 51 ++++--- src/lib/appManagers/appDocsManager.ts | 9 +- src/lib/appManagers/appMessagesManager.ts | 149 ++++++++++--------- src/lib/appManagers/appPhotosManager.ts | 4 +- src/lib/appManagers/appStateManager.ts | 4 + src/lib/appManagers/appUsersManager.ts | 83 +++++------ src/lib/storage.ts | 10 +- src/lib/utils.ts | 15 +- src/scripts/in/schema_additional_params.json | 11 ++ 11 files changed, 205 insertions(+), 147 deletions(-) diff --git a/src/helpers/json.ts b/src/helpers/json.ts index 1fca6776..d4785b62 100644 --- a/src/helpers/json.ts +++ b/src/helpers/json.ts @@ -24,9 +24,12 @@ // parse('{"file_reference": {"type": "bytes", "value": [1,2,3]}, "file_reference2": {"type": "bytes", "value": [3,2,1]}}'); // -> {file_reference: Uint8Array} -export function stringify(value: any) { +// TOO SLOW TOO +/* export function stringify(value: any) { return JSON.stringify(value, (key, value) => { if(key == 'downloaded' || (key == 'url' && value.indexOf('blob:') === 0)) return undefined; return value; }); -} \ No newline at end of file +} */ + +export {}; \ No newline at end of file diff --git a/src/layer.d.ts b/src/layer.d.ts index e161171a..7f85dbae 100644 --- a/src/layer.d.ts +++ b/src/layer.d.ts @@ -493,7 +493,14 @@ export namespace User { bot_info_version?: number, restriction_reason?: Array, bot_inline_placeholder?: string, - lang_code?: string + lang_code?: string, + initials?: string, + rFirstName?: string, + rFullName?: string, + rPhone?: string, + sortName?: string, + sortStatus?: number, + num?: number }; } diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts index a75e7958..76c40181 100644 --- a/src/lib/appManagers/appChatsManager.ts +++ b/src/lib/appManagers/appChatsManager.ts @@ -3,7 +3,7 @@ import apiManager from '../mtproto/mtprotoworker'; import { RichTextProcessor } from "../richtextprocessor"; import $rootScope from "../rootScope"; import searchIndexManager from "../searchIndexManager"; -import { copy, getAbbreviation, isObject, numberWithCommas, safeReplaceObject } from "../utils"; +import { copy, defineNotNumerableProperties, getAbbreviation, isObject, numberWithCommas, safeReplaceObject } from "../utils"; import apiUpdatesManager from "./apiUpdatesManager"; import appMessagesManager from "./appMessagesManager"; import appProfileManager from "./appProfileManager"; @@ -89,61 +89,64 @@ export class AppChatsManager { apiChats.forEach(chat => this.saveApiChat(chat)); } - public saveApiChat(apiChat: any) { - if(!isObject(apiChat)) { + public saveApiChat(chat: any) { + if(!isObject(chat)) { return; } + + // * exclude from state + defineNotNumerableProperties(chat, ['rTitle', 'initials']); - apiChat.rTitle = apiChat.title || 'chat_title_deleted'; - apiChat.rTitle = RichTextProcessor.wrapRichText(apiChat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted'; + //chat.rTitle = chat.title || 'chat_title_deleted'; + chat.rTitle = RichTextProcessor.wrapRichText(chat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted'; - let oldChat = this.chats[apiChat.id]; + const oldChat = this.chats[chat.id]; - apiChat.initials = getAbbreviation(apiChat.title); + chat.initials = getAbbreviation(chat.title); - if(apiChat.pFlags === undefined) { - apiChat.pFlags = {}; + if(chat.pFlags === undefined) { + chat.pFlags = {}; } - if(apiChat.pFlags.min) { + if(chat.pFlags.min) { if(oldChat !== undefined) { return; } } - if(apiChat._ == 'channel' && - apiChat.participants_count === undefined && + if(chat._ == 'channel' && + chat.participants_count === undefined && oldChat !== undefined && oldChat.participants_count) { - apiChat.participants_count = oldChat.participants_count; + chat.participants_count = oldChat.participants_count; } - if(apiChat.username) { - let searchUsername = searchIndexManager.cleanUsername(apiChat.username); - this.usernames[searchUsername] = apiChat.id; + if(chat.username) { + let searchUsername = searchIndexManager.cleanUsername(chat.username); + this.usernames[searchUsername] = chat.id; } let changedPhoto = false; if(oldChat === undefined) { - oldChat = this.chats[apiChat.id] = apiChat; + this.chats[chat.id] = chat; } else { let oldPhoto = oldChat.photo && oldChat.photo.photo_small; - let newPhoto = apiChat.photo && apiChat.photo.photo_small; + let newPhoto = chat.photo && chat.photo.photo_small; if(JSON.stringify(oldPhoto) !== JSON.stringify(newPhoto)) { changedPhoto = true; } - safeReplaceObject(oldChat, apiChat); - $rootScope.$broadcast('chat_update', apiChat.id); + safeReplaceObject(oldChat, chat); + $rootScope.$broadcast('chat_update', chat.id); } - if(this.cachedPhotoLocations[apiChat.id] !== undefined) { - safeReplaceObject(this.cachedPhotoLocations[apiChat.id], apiChat && - apiChat.photo ? apiChat.photo : {empty: true}); + if(this.cachedPhotoLocations[chat.id] !== undefined) { + safeReplaceObject(this.cachedPhotoLocations[chat.id], chat && + chat.photo ? chat.photo : {empty: true}); } if(changedPhoto) { - $rootScope.$broadcast('avatar_update', -apiChat.id); + $rootScope.$broadcast('avatar_update', -chat.id); } } diff --git a/src/lib/appManagers/appDocsManager.ts b/src/lib/appManagers/appDocsManager.ts index 7c6f44fc..169496d6 100644 --- a/src/lib/appManagers/appDocsManager.ts +++ b/src/lib/appManagers/appDocsManager.ts @@ -4,7 +4,7 @@ import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config'; import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase'; import opusDecodeController from '../opusDecodeController'; import { RichTextProcessor } from '../richtextprocessor'; -import { FileURLType, getFileURL, isObject, safeReplaceArrayInObject } from '../utils'; +import { defineNotNumerableProperties, FileURLType, getFileURL, isObject, safeReplaceArrayInObject } from '../utils'; import appDownloadManager, { DownloadBlob } from './appDownloadManager'; import appPhotosManager from './appPhotosManager'; @@ -48,6 +48,12 @@ class AppDocsManager { } this.docs[doc.id] = doc; + + // * exclude from state + defineNotNumerableProperties(doc, [/* 'thumbs', */'type', 'h', 'w', 'file_name', + 'file', 'duration', 'downloaded', 'url', 'audioTitle', + 'audioPerformer', 'sticker', 'stickerEmoji', 'stickerEmojiRaw', + 'stickerSetInput', 'stickerThumbConverted', 'animated', 'supportsStreaming']); doc.attributes.forEach(attribute => { switch(attribute._) { @@ -277,6 +283,7 @@ class AppDocsManager { const originalPromise = download; originalPromise.then((blob) => { if(thumb) { + defineNotNumerableProperties(thumb, ['url']); thumb.url = URL.createObjectURL(blob); return; } else if(!doc.supportsStreaming) { diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index bf5f87f6..8fad6ea2 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -13,7 +13,7 @@ import { RichTextProcessor } from "../richtextprocessor"; import $rootScope from "../rootScope"; import searchIndexManager from '../searchIndexManager'; import AppStorage from '../storage'; -import { copy, deepEqual, getObjectKeysAndSort, langPack, limitSymbols, listMergeSorted, safeReplaceObject, splitStringByLength, tsNow } from "../utils"; +import { copy, deepEqual, defineNotNumerableProperties, getObjectKeysAndSort, langPack, limitSymbols, listMergeSorted, safeReplaceObject, splitStringByLength, tsNow } from "../utils"; //import { telegramMeWebService } from "../mtproto/mtproto"; import apiUpdatesManager from "./apiUpdatesManager"; import appChatsManager from "./appChatsManager"; @@ -2195,78 +2195,81 @@ export class AppMessagesManager { }); } - public saveMessages(apiMessages: any[], options: { + public saveMessages(messages: any[], options: { isEdited?: boolean } = {}) { - apiMessages.forEach((apiMessage) => { - if(apiMessage.pFlags === undefined) { - apiMessage.pFlags = {}; + messages.forEach((message) => { + if(message.pFlags === undefined) { + message.pFlags = {}; } - if(apiMessage._ == 'messageEmpty') { + if(message._ == 'messageEmpty') { return; } - const peerID = this.getMessagePeer(apiMessage); - const isChannel = apiMessage.peer_id._ == 'peerChannel'; + // * exclude from state + defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromID', 'fromID', 'peerID', 'reply_to_mid', 'viaBotID']); + + const peerID = this.getMessagePeer(message); + const isChannel = message.peer_id._ == 'peerChannel'; const channelID = isChannel ? -peerID : 0; const isBroadcast = isChannel && appChatsManager.isBroadcast(channelID); - const mid = appMessagesIDsManager.getFullMessageID(apiMessage.id, channelID); - apiMessage.mid = mid; + const mid = appMessagesIDsManager.getFullMessageID(message.id, channelID); + message.mid = mid; - if(apiMessage.grouped_id) { - const storage = this.groupedMessagesStorage[apiMessage.grouped_id] ?? (this.groupedMessagesStorage[apiMessage.grouped_id] = {}); - storage[mid] = apiMessage; + if(message.grouped_id) { + const storage = this.groupedMessagesStorage[message.grouped_id] ?? (this.groupedMessagesStorage[message.grouped_id] = {}); + storage[mid] = message; } const dialog = this.getDialogByPeerID(peerID)[0]; if(dialog && mid > 0) { - if(mid > dialog[apiMessage.pFlags.out + if(mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) { - apiMessage.pFlags.unread = true; + message.pFlags.unread = true; } } // this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) - if(apiMessage.reply_to && apiMessage.reply_to.reply_to_msg_id) { - apiMessage.reply_to_mid = appMessagesIDsManager.getFullMessageID(apiMessage.reply_to.reply_to_msg_id, channelID); + if(message.reply_to && message.reply_to.reply_to_msg_id) { + message.reply_to_mid = appMessagesIDsManager.getFullMessageID(message.reply_to.reply_to_msg_id, channelID); } - apiMessage.date -= serverTimeManager.serverTimeOffset; + message.date -= serverTimeManager.serverTimeOffset; const myID = appUsersManager.getSelf().id; - apiMessage.peerID = peerID; - if(apiMessage.peerID == myID && !apiMessage.from_id && !apiMessage.fwd_from) { - apiMessage.fromID = myID; + message.peerID = peerID; + if(message.peerID == myID && !message.from_id && !message.fwd_from) { + message.fromID = myID; } else { - apiMessage.fromID = apiMessage.pFlags.post || (!apiMessage.pFlags.out && !apiMessage.from_id) ? peerID : appPeersManager.getPeerID(apiMessage.from_id); + message.fromID = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerID : appPeersManager.getPeerID(message.from_id); } - const fwdHeader = apiMessage.fwd_from; + const fwdHeader = message.fwd_from; if(fwdHeader) { //if(peerID == myID) { if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) { const savedFromPeerID = appPeersManager.getPeerID(fwdHeader.saved_from_peer); const savedFromMid = appMessagesIDsManager.getFullMessageID(fwdHeader.saved_from_msg_id, appPeersManager.isChannel(savedFromPeerID) ? -savedFromPeerID : 0); - apiMessage.savedFrom = savedFromPeerID + '_' + savedFromMid; + message.savedFrom = savedFromPeerID + '_' + savedFromMid; } - apiMessage.fromID = appPeersManager.getPeerID(deepEqual(apiMessage.from_id, fwdHeader.from_id) ? fwdHeader.from_id : apiMessage.from_id); + message.fromID = appPeersManager.getPeerID(deepEqual(message.from_id, fwdHeader.from_id) ? fwdHeader.from_id : message.from_id); /* } else { apiMessage.fwdPostID = fwdHeader.channel_post; } */ - apiMessage.fwdFromID = appPeersManager.getPeerID(fwdHeader.from_id); + message.fwdFromID = appPeersManager.getPeerID(fwdHeader.from_id); fwdHeader.date -= serverTimeManager.serverTimeOffset; } - if(apiMessage.via_bot_id > 0) { - apiMessage.viaBotID = apiMessage.via_bot_id; + if(message.via_bot_id > 0) { + message.viaBotID = message.via_bot_id; } const mediaContext: ReferenceContext = { @@ -2274,27 +2277,27 @@ export class AppMessagesManager { messageID: mid }; - if(apiMessage.media) { - switch(apiMessage.media._) { + if(message.media) { + switch(message.media._) { case 'messageMediaEmpty': - delete apiMessage.media; + delete message.media; break; case 'messageMediaPhoto': - if(apiMessage.media.ttl_seconds) { - apiMessage.media = {_: 'messageMediaUnsupportedWeb'}; + if(message.media.ttl_seconds) { + message.media = {_: 'messageMediaUnsupportedWeb'}; } else { - apiMessage.media.photo = appPhotosManager.savePhoto(apiMessage.media.photo, mediaContext); + message.media.photo = appPhotosManager.savePhoto(message.media.photo, mediaContext); //appPhotosManager.savePhoto(apiMessage.media.photo, mediaContext); } break; case 'messageMediaPoll': - apiMessage.media.poll = appPollsManager.savePoll(apiMessage.media.poll, apiMessage.media.results); + message.media.poll = appPollsManager.savePoll(message.media.poll, message.media.results); break; case 'messageMediaDocument': - if(apiMessage.media.ttl_seconds) { - apiMessage.media = {_: 'messageMediaUnsupportedWeb'}; + if(message.media.ttl_seconds) { + message.media = {_: 'messageMediaUnsupportedWeb'}; } else { - apiMessage.media.document = appDocsManager.saveDoc(apiMessage.media.document, mediaContext); // 11.04.2020 warning + message.media.document = appDocsManager.saveDoc(message.media.document, mediaContext); // 11.04.2020 warning } @@ -2303,91 +2306,91 @@ export class AppMessagesManager { /* if(apiMessage.media.webpage.document) { appDocsManager.saveDoc(apiMessage.media.webpage.document, mediaContext); } */ - appWebPagesManager.saveWebPage(apiMessage.media.webpage, apiMessage.mid, mediaContext); + appWebPagesManager.saveWebPage(message.media.webpage, message.mid, mediaContext); break; /*case 'messageMediaGame': AppGamesManager.saveGame(apiMessage.media.game, apiMessage.mid, mediaContext); apiMessage.media.handleMessage = true; break; */ case 'messageMediaInvoice': - apiMessage.media = {_: 'messageMediaUnsupportedWeb'}; + message.media = {_: 'messageMediaUnsupportedWeb'}; break; case 'messageMediaGeoLive': - apiMessage.media._ = 'messageMediaGeo'; + message.media._ = 'messageMediaGeo'; break; } } - if(apiMessage.action) { + if(message.action) { let migrateFrom: number; let migrateTo: number; - switch(apiMessage.action._) { + switch(message.action._) { //case 'messageActionChannelEditPhoto': case 'messageActionChatEditPhoto': - apiMessage.action.photo = appPhotosManager.savePhoto(apiMessage.action.photo, mediaContext); + message.action.photo = appPhotosManager.savePhoto(message.action.photo, mediaContext); //appPhotosManager.savePhoto(apiMessage.action.photo, mediaContext); if(isBroadcast) { // ! messageActionChannelEditPhoto не существует в принципе, это используется для перевода. - apiMessage.action._ = 'messageActionChannelEditPhoto'; + message.action._ = 'messageActionChannelEditPhoto'; } break; case 'messageActionChatEditTitle': if(isBroadcast) { - apiMessage.action._ = 'messageActionChannelEditTitle'; + message.action._ = 'messageActionChannelEditTitle'; } break; case 'messageActionChatDeletePhoto': if(isBroadcast) { - apiMessage.action._ = 'messageActionChannelDeletePhoto'; + message.action._ = 'messageActionChannelDeletePhoto'; } break; case 'messageActionChatAddUser': - if(apiMessage.action.users.length == 1) { - apiMessage.action.user_id = apiMessage.action.users[0]; - if(apiMessage.fromID == apiMessage.action.user_id) { + if(message.action.users.length == 1) { + message.action.user_id = message.action.users[0]; + if(message.fromID == message.action.user_id) { if(isChannel) { - apiMessage.action._ = 'messageActionChatJoined'; + message.action._ = 'messageActionChatJoined'; } else { - apiMessage.action._ = 'messageActionChatReturn'; + message.action._ = 'messageActionChatReturn'; } } - } else if(apiMessage.action.users.length > 1) { - apiMessage.action._ = 'messageActionChatAddUsers'; + } else if(message.action.users.length > 1) { + message.action._ = 'messageActionChatAddUsers'; } break; case 'messageActionChatDeleteUser': - if(apiMessage.fromID == apiMessage.action.user_id) { - apiMessage.action._ = 'messageActionChatLeave'; + if(message.fromID == message.action.user_id) { + message.action._ = 'messageActionChatLeave'; } break; case 'messageActionChannelMigrateFrom': - migrateFrom = -apiMessage.action.chat_id; + migrateFrom = -message.action.chat_id; migrateTo = -channelID; break case 'messageActionChatMigrateTo': migrateFrom = -channelID; - migrateTo = -apiMessage.action.channel_id; + migrateTo = -message.action.channel_id; break; case 'messageActionHistoryClear': //apiMessage.deleted = true; - apiMessage.clear_history = true; - delete apiMessage.pFlags.out; - delete apiMessage.pFlags.unread; + message.clear_history = true; + delete message.pFlags.out; + delete message.pFlags.unread; break; case 'messageActionPhoneCall': - delete apiMessage.fromID; - apiMessage.action.type = - (apiMessage.pFlags.out ? 'out_' : 'in_') + + delete message.fromID; + message.action.type = + (message.pFlags.out ? 'out_' : 'in_') + ( - apiMessage.action.reason._ == 'phoneCallDiscardReasonMissed' || - apiMessage.action.reason._ == 'phoneCallDiscardReasonBusy' + message.action.reason._ == 'phoneCallDiscardReasonMissed' || + message.action.reason._ == 'phoneCallDiscardReasonBusy' ? 'missed' : 'ok' ); @@ -2402,17 +2405,17 @@ export class AppMessagesManager { } } - apiMessage.rReply = this.getRichReplyText(apiMessage); + message.rReply = this.getRichReplyText(message); - if(apiMessage.message && apiMessage.message.length && !apiMessage.totalEntities) { - const myEntities = RichTextProcessor.parseEntities(apiMessage.message); - const apiEntities = apiMessage.entities || []; - apiMessage.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !apiMessage.pending); + if(message.message && message.message.length && !message.totalEntities) { + const myEntities = RichTextProcessor.parseEntities(message.message); + const apiEntities = message.entities || []; + message.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !message.pending); } if(!options.isEdited) { - this.messagesStorage[mid] = apiMessage; - (this.messagesStorageByPeerID[peerID] ?? (this.messagesStorageByPeerID[peerID] = {}))[mid] = apiMessage; + this.messagesStorage[mid] = message; + (this.messagesStorageByPeerID[peerID] ?? (this.messagesStorageByPeerID[peerID] = {}))[mid] = message; } }); } diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts index 2fe598f3..d40b1555 100644 --- a/src/lib/appManagers/appPhotosManager.ts +++ b/src/lib/appManagers/appPhotosManager.ts @@ -5,7 +5,7 @@ import { bytesFromHex, getFileNameByLocation } from "../bin_utils"; import { DownloadOptions } from "../mtproto/apiFileManager"; import apiManager from "../mtproto/mtprotoworker"; import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase"; -import { calcImageInBox, isObject, safeReplaceArrayInObject } from "../utils"; +import { calcImageInBox, defineNotNumerableProperties, isObject, safeReplaceArrayInObject } from "../utils"; import { MyDocument } from "./appDocsManager"; import appDownloadManager from "./appDownloadManager"; import appUsersManager from "./appUsersManager"; @@ -280,6 +280,8 @@ export class AppPhotosManager { download = appDownloadManager.download(downloadOptions); download.then(blob => { if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) { + defineNotNumerableProperties(cacheContext, ['downloaded', 'url']); + cacheContext.downloaded = blob.size; cacheContext.url = URL.createObjectURL(blob); diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts index f1615adb..4bcbe779 100644 --- a/src/lib/appManagers/appStateManager.ts +++ b/src/lib/appManagers/appStateManager.ts @@ -96,13 +96,17 @@ export class AppStateManager extends EventListenerBase<{ public saveState() { if(this.state === undefined) return; + //let perf = performance.now(); this.setListenerResult('save', this.state); + //this.log('saveState: event time:', performance.now() - perf); //const pinnedOrders = appMessagesManager.dialogsStorage.pinnedOrders; + //perf = performance.now(); AppStorage.set({ state: this.state }); + //this.log('saveState: storage set time:', performance.now() - perf); } public pushToState(key: T, value: State[T]) { diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 4ba9d8c7..2ca5ceb9 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -1,12 +1,12 @@ import { formatPhoneNumber } from "../../components/misc"; -import { InputUser, Update, User as MTUser } from "../../layer"; +import { InputUser, Update, User as MTUser, UserStatus } from "../../layer"; //import apiManager from '../mtproto/apiManager'; import apiManager from '../mtproto/mtprotoworker'; import serverTimeManager from "../mtproto/serverTimeManager"; import { RichTextProcessor } from "../richtextprocessor"; import $rootScope from "../rootScope"; import searchIndexManager from "../searchIndexManager"; -import { getAbbreviation, isObject, safeReplaceObject, tsNow } from "../utils"; +import { defineNotNumerableProperties, getAbbreviation, isObject, safeReplaceObject, tsNow } from "../utils"; import appChatsManager from "./appChatsManager"; import appPeersManager from "./appPeersManager"; import appStateManager from "./appStateManager"; @@ -40,15 +40,7 @@ import appStateManager from "./appStateManager"; sortName?: string, sortStatus?: number, }; */ -export interface User extends MTUser.user { - initials?: string, - num?: number, - rFirstName?: string, - rFullName?: string, - rPhone?: string, - sortName?: string, - sortStatus?: number, -} +export type User = MTUser.user; export class AppUsersManager { public users: {[userID: number]: User} = {}; @@ -172,7 +164,7 @@ export class AppUsersManager { } return await apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => { - this.saveApiUser(resolvedPeer.users[0]); + this.saveApiUser(resolvedPeer.users[0] as User); appChatsManager.saveApiChats(resolvedPeer.chats); return this.users[this.usernames[username]]; @@ -237,75 +229,80 @@ export class AppUsersManager { apiUsers.forEach((user) => this.saveApiUser(user)); } - public saveApiUser(apiUser: any, noReplace?: boolean) { - if(!isObject(apiUser) || - noReplace && isObject(this.users[apiUser.id]) && this.users[apiUser.id].first_name) { + public saveApiUser(_user: MTUser, noReplace?: boolean) { + if(_user._ == 'userEmpty') return; + + const user = _user; + if(noReplace && isObject(this.users[user.id]) && this.users[user.id].first_name) { return; } - var userID = apiUser.id; + var userID = user.id; var result = this.users[userID]; - if(apiUser.pFlags === undefined) { - apiUser.pFlags = {}; + if(user.pFlags === undefined) { + user.pFlags = {}; } - if(apiUser.pFlags.min) { + if(user.pFlags.min) { if(result !== undefined) { return; } } - if(apiUser.phone) { - apiUser.rPhone = '+' + formatPhoneNumber(apiUser.phone).formatted; + // * exclude from state + defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']); + + if(user.phone) { + user.rPhone = '+' + formatPhoneNumber(user.phone).formatted; } - const fullName = apiUser.first_name + ' ' + (apiUser.last_name || ''); - if(apiUser.first_name) { - apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.first_name, {noLinks: true, noLinebreaks: true}) - apiUser.rFullName = apiUser.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : apiUser.rFirstName; + const fullName = user.first_name + ' ' + (user.last_name || ''); + if(user.first_name) { + user.rFirstName = RichTextProcessor.wrapRichText(user.first_name, {noLinks: true, noLinebreaks: true}) + user.rFullName = user.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : user.rFirstName; } else { - apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'user_first_name_deleted'; - apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'user_name_deleted'; + user.rFirstName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_first_name_deleted'; + user.rFullName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_name_deleted'; } - if(apiUser.username) { - var searchUsername = searchIndexManager.cleanUsername(apiUser.username); + if(user.username) { + var searchUsername = searchIndexManager.cleanUsername(user.username); this.usernames[searchUsername] = userID; } - apiUser.sortName = apiUser.pFlags.deleted ? '' : searchIndexManager.cleanSearchText(fullName, false); + user.sortName = user.pFlags.deleted ? '' : searchIndexManager.cleanSearchText(fullName, false); - apiUser.initials = getAbbreviation(fullName); + user.initials = getAbbreviation(fullName); - if(apiUser.status) { - if(apiUser.status.expires) { - apiUser.status.expires -= serverTimeManager.serverTimeOffset + if(user.status) { + if((user.status as UserStatus.userStatusOnline).expires) { + (user.status as UserStatus.userStatusOnline).expires -= serverTimeManager.serverTimeOffset } - if(apiUser.status.was_online) { - apiUser.status.was_online -= serverTimeManager.serverTimeOffset + if((user.status as UserStatus.userStatusOffline).was_online) { + (user.status as UserStatus.userStatusOffline).was_online -= serverTimeManager.serverTimeOffset } } - if(apiUser.pFlags.bot) { - apiUser.sortStatus = -1; + if(user.pFlags.bot) { + user.sortStatus = -1; } else { - apiUser.sortStatus = this.getUserStatusForSort(apiUser.status); + user.sortStatus = this.getUserStatusForSort(user.status); } var result = this.users[userID]; if(result === undefined) { - result = this.users[userID] = apiUser; + result = this.users[userID] = user; } else { - safeReplaceObject(result, apiUser); + safeReplaceObject(result, user); } $rootScope.$broadcast('user_update', userID); if(this.cachedPhotoLocations[userID] !== undefined) { - safeReplaceObject(this.cachedPhotoLocations[userID], apiUser && - apiUser.photo ? apiUser.photo : {empty: true}); + safeReplaceObject(this.cachedPhotoLocations[userID], user && + user.photo ? user.photo : {empty: true}); } } diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 06b8a7ec..f83f2daf 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -1,6 +1,6 @@ import { Modes } from './mtproto/mtproto_config'; import { notifySomeone, isWorker } from '../helpers/context'; -import { stringify } from '../helpers/json'; +//import { stringify } from '../helpers/json'; class ConfigStorage { public keyPrefix = ''; @@ -72,7 +72,15 @@ class ConfigStorage { value = obj[key]; key = prefix + key; this.cache[key] = value; + + value = JSON.stringify(value); + /* let perf = performance.now(); + let value2 = JSON.stringify(value); + console.log('LocalStorage set: stringify time by JSON.stringify:', performance.now() - perf, value2); + + perf = performance.now(); value = stringify(value); + console.log('LocalStorage set: stringify time by own stringify:', performance.now() - perf); */ if(this.useLs) { try { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 8a86f301..02fbbb18 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -580,4 +580,17 @@ export function splitStringByLength(str: string, maxLength: number) { return out; } -(window as any).splitStringByLength = splitStringByLength; +export function defineNotNumerableProperties(obj: {[key: string]: any}, names: string[]) { + //const perf = performance.now(); + const props = {writable: true, configurable: true}; + const out: {[name: string]: typeof props} = {}; + names.forEach(name => { + if(obj[name] === undefined) { + out[name] = props; + } + }); + Object.defineProperties(obj, out); + //console.log('defineNotNumerableProperties time:', performance.now() - perf); +} + +//(window as any).splitStringByLength = splitStringByLength; diff --git a/src/scripts/in/schema_additional_params.json b/src/scripts/in/schema_additional_params.json index bd22aa3f..68914c35 100644 --- a/src/scripts/in/schema_additional_params.json +++ b/src/scripts/in/schema_additional_params.json @@ -211,4 +211,15 @@ "params": [ {"name": "nested", "type": "Array"} ] +}, { + "predicate": "user", + "params": [ + {"name": "initials", "type": "string"}, + {"name": "rFirstName", "type": "string"}, + {"name": "rFullName", "type": "string"}, + {"name": "rPhone", "type": "string"}, + {"name": "sortName", "type": "string"}, + {"name": "sortStatus", "type": "number"}, + {"name": "num", "type": "number"} + ] }] \ No newline at end of file