Browse Source

Improve state save performance

master
morethanwords 4 years ago
parent
commit
2289fbff07
  1. 7
      src/helpers/json.ts
  2. 9
      src/layer.d.ts
  3. 51
      src/lib/appManagers/appChatsManager.ts
  4. 9
      src/lib/appManagers/appDocsManager.ts
  5. 149
      src/lib/appManagers/appMessagesManager.ts
  6. 4
      src/lib/appManagers/appPhotosManager.ts
  7. 4
      src/lib/appManagers/appStateManager.ts
  8. 83
      src/lib/appManagers/appUsersManager.ts
  9. 10
      src/lib/storage.ts
  10. 15
      src/lib/utils.ts
  11. 11
      src/scripts/in/schema_additional_params.json

7
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]}}'); // parse('{"file_reference": {"type": "bytes", "value": [1,2,3]}, "file_reference2": {"type": "bytes", "value": [3,2,1]}}');
// -> {file_reference: Uint8Array} // -> {file_reference: Uint8Array}
export function stringify(value: any) { // TOO SLOW TOO
/* export function stringify(value: any) {
return JSON.stringify(value, (key, value) => { return JSON.stringify(value, (key, value) => {
if(key == 'downloaded' || (key == 'url' && value.indexOf('blob:') === 0)) return undefined; if(key == 'downloaded' || (key == 'url' && value.indexOf('blob:') === 0)) return undefined;
return value; return value;
}); });
} } */
export {};

9
src/layer.d.ts vendored

@ -493,7 +493,14 @@ export namespace User {
bot_info_version?: number, bot_info_version?: number,
restriction_reason?: Array<RestrictionReason>, restriction_reason?: Array<RestrictionReason>,
bot_inline_placeholder?: string, bot_inline_placeholder?: string,
lang_code?: string lang_code?: string,
initials?: string,
rFirstName?: string,
rFullName?: string,
rPhone?: string,
sortName?: string,
sortStatus?: number,
num?: number
}; };
} }

51
src/lib/appManagers/appChatsManager.ts

@ -3,7 +3,7 @@ import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import searchIndexManager from "../searchIndexManager"; 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 apiUpdatesManager from "./apiUpdatesManager";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appProfileManager from "./appProfileManager"; import appProfileManager from "./appProfileManager";
@ -89,61 +89,64 @@ export class AppChatsManager {
apiChats.forEach(chat => this.saveApiChat(chat)); apiChats.forEach(chat => this.saveApiChat(chat));
} }
public saveApiChat(apiChat: any) { public saveApiChat(chat: any) {
if(!isObject(apiChat)) { if(!isObject(chat)) {
return; return;
} }
apiChat.rTitle = apiChat.title || 'chat_title_deleted'; // * exclude from state
apiChat.rTitle = RichTextProcessor.wrapRichText(apiChat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted'; defineNotNumerableProperties(chat, ['rTitle', 'initials']);
let oldChat = this.chats[apiChat.id]; //chat.rTitle = chat.title || 'chat_title_deleted';
chat.rTitle = RichTextProcessor.wrapRichText(chat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted';
apiChat.initials = getAbbreviation(apiChat.title); const oldChat = this.chats[chat.id];
if(apiChat.pFlags === undefined) { chat.initials = getAbbreviation(chat.title);
apiChat.pFlags = {};
if(chat.pFlags === undefined) {
chat.pFlags = {};
} }
if(apiChat.pFlags.min) { if(chat.pFlags.min) {
if(oldChat !== undefined) { if(oldChat !== undefined) {
return; return;
} }
} }
if(apiChat._ == 'channel' && if(chat._ == 'channel' &&
apiChat.participants_count === undefined && chat.participants_count === undefined &&
oldChat !== undefined && oldChat !== undefined &&
oldChat.participants_count) { oldChat.participants_count) {
apiChat.participants_count = oldChat.participants_count; chat.participants_count = oldChat.participants_count;
} }
if(apiChat.username) { if(chat.username) {
let searchUsername = searchIndexManager.cleanUsername(apiChat.username); let searchUsername = searchIndexManager.cleanUsername(chat.username);
this.usernames[searchUsername] = apiChat.id; this.usernames[searchUsername] = chat.id;
} }
let changedPhoto = false; let changedPhoto = false;
if(oldChat === undefined) { if(oldChat === undefined) {
oldChat = this.chats[apiChat.id] = apiChat; this.chats[chat.id] = chat;
} else { } else {
let oldPhoto = oldChat.photo && oldChat.photo.photo_small; 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)) { if(JSON.stringify(oldPhoto) !== JSON.stringify(newPhoto)) {
changedPhoto = true; changedPhoto = true;
} }
safeReplaceObject(oldChat, apiChat); safeReplaceObject(oldChat, chat);
$rootScope.$broadcast('chat_update', apiChat.id); $rootScope.$broadcast('chat_update', chat.id);
} }
if(this.cachedPhotoLocations[apiChat.id] !== undefined) { if(this.cachedPhotoLocations[chat.id] !== undefined) {
safeReplaceObject(this.cachedPhotoLocations[apiChat.id], apiChat && safeReplaceObject(this.cachedPhotoLocations[chat.id], chat &&
apiChat.photo ? apiChat.photo : {empty: true}); chat.photo ? chat.photo : {empty: true});
} }
if(changedPhoto) { if(changedPhoto) {
$rootScope.$broadcast('avatar_update', -apiChat.id); $rootScope.$broadcast('avatar_update', -chat.id);
} }
} }

9
src/lib/appManagers/appDocsManager.ts

@ -4,7 +4,7 @@ import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase'; import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
import opusDecodeController from '../opusDecodeController'; import opusDecodeController from '../opusDecodeController';
import { RichTextProcessor } from '../richtextprocessor'; 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 appDownloadManager, { DownloadBlob } from './appDownloadManager';
import appPhotosManager from './appPhotosManager'; import appPhotosManager from './appPhotosManager';
@ -49,6 +49,12 @@ class AppDocsManager {
this.docs[doc.id] = doc; 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 => { doc.attributes.forEach(attribute => {
switch(attribute._) { switch(attribute._) {
case 'documentAttributeFilename': case 'documentAttributeFilename':
@ -277,6 +283,7 @@ class AppDocsManager {
const originalPromise = download; const originalPromise = download;
originalPromise.then((blob) => { originalPromise.then((blob) => {
if(thumb) { if(thumb) {
defineNotNumerableProperties(thumb, ['url']);
thumb.url = URL.createObjectURL(blob); thumb.url = URL.createObjectURL(blob);
return; return;
} else if(!doc.supportsStreaming) { } else if(!doc.supportsStreaming) {

149
src/lib/appManagers/appMessagesManager.ts

@ -13,7 +13,7 @@ import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import searchIndexManager from '../searchIndexManager'; import searchIndexManager from '../searchIndexManager';
import AppStorage from '../storage'; 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 { telegramMeWebService } from "../mtproto/mtproto";
import apiUpdatesManager from "./apiUpdatesManager"; import apiUpdatesManager from "./apiUpdatesManager";
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
@ -2195,78 +2195,81 @@ export class AppMessagesManager {
}); });
} }
public saveMessages(apiMessages: any[], options: { public saveMessages(messages: any[], options: {
isEdited?: boolean isEdited?: boolean
} = {}) { } = {}) {
apiMessages.forEach((apiMessage) => { messages.forEach((message) => {
if(apiMessage.pFlags === undefined) { if(message.pFlags === undefined) {
apiMessage.pFlags = {}; message.pFlags = {};
} }
if(apiMessage._ == 'messageEmpty') { if(message._ == 'messageEmpty') {
return; return;
} }
const peerID = this.getMessagePeer(apiMessage); // * exclude from state
const isChannel = apiMessage.peer_id._ == 'peerChannel'; 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 channelID = isChannel ? -peerID : 0;
const isBroadcast = isChannel && appChatsManager.isBroadcast(channelID); const isBroadcast = isChannel && appChatsManager.isBroadcast(channelID);
const mid = appMessagesIDsManager.getFullMessageID(apiMessage.id, channelID); const mid = appMessagesIDsManager.getFullMessageID(message.id, channelID);
apiMessage.mid = mid; message.mid = mid;
if(apiMessage.grouped_id) { if(message.grouped_id) {
const storage = this.groupedMessagesStorage[apiMessage.grouped_id] ?? (this.groupedMessagesStorage[apiMessage.grouped_id] = {}); const storage = this.groupedMessagesStorage[message.grouped_id] ?? (this.groupedMessagesStorage[message.grouped_id] = {});
storage[mid] = apiMessage; storage[mid] = message;
} }
const dialog = this.getDialogByPeerID(peerID)[0]; const dialog = this.getDialogByPeerID(peerID)[0];
if(dialog && mid > 0) { if(dialog && mid > 0) {
if(mid > dialog[apiMessage.pFlags.out if(mid > dialog[message.pFlags.out
? 'read_outbox_max_id' ? 'read_outbox_max_id'
: 'read_inbox_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']) // 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) { if(message.reply_to && message.reply_to.reply_to_msg_id) {
apiMessage.reply_to_mid = appMessagesIDsManager.getFullMessageID(apiMessage.reply_to.reply_to_msg_id, channelID); 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; const myID = appUsersManager.getSelf().id;
apiMessage.peerID = peerID; message.peerID = peerID;
if(apiMessage.peerID == myID && !apiMessage.from_id && !apiMessage.fwd_from) { if(message.peerID == myID && !message.from_id && !message.fwd_from) {
apiMessage.fromID = myID; message.fromID = myID;
} else { } 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(fwdHeader) {
//if(peerID == myID) { //if(peerID == myID) {
if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) { if(fwdHeader.saved_from_peer && fwdHeader.saved_from_msg_id) {
const savedFromPeerID = appPeersManager.getPeerID(fwdHeader.saved_from_peer); const savedFromPeerID = appPeersManager.getPeerID(fwdHeader.saved_from_peer);
const savedFromMid = appMessagesIDsManager.getFullMessageID(fwdHeader.saved_from_msg_id, const savedFromMid = appMessagesIDsManager.getFullMessageID(fwdHeader.saved_from_msg_id,
appPeersManager.isChannel(savedFromPeerID) ? -savedFromPeerID : 0); 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 { /* } else {
apiMessage.fwdPostID = fwdHeader.channel_post; apiMessage.fwdPostID = fwdHeader.channel_post;
} */ } */
apiMessage.fwdFromID = appPeersManager.getPeerID(fwdHeader.from_id); message.fwdFromID = appPeersManager.getPeerID(fwdHeader.from_id);
fwdHeader.date -= serverTimeManager.serverTimeOffset; fwdHeader.date -= serverTimeManager.serverTimeOffset;
} }
if(apiMessage.via_bot_id > 0) { if(message.via_bot_id > 0) {
apiMessage.viaBotID = apiMessage.via_bot_id; message.viaBotID = message.via_bot_id;
} }
const mediaContext: ReferenceContext = { const mediaContext: ReferenceContext = {
@ -2274,27 +2277,27 @@ export class AppMessagesManager {
messageID: mid messageID: mid
}; };
if(apiMessage.media) { if(message.media) {
switch(apiMessage.media._) { switch(message.media._) {
case 'messageMediaEmpty': case 'messageMediaEmpty':
delete apiMessage.media; delete message.media;
break; break;
case 'messageMediaPhoto': case 'messageMediaPhoto':
if(apiMessage.media.ttl_seconds) { if(message.media.ttl_seconds) {
apiMessage.media = {_: 'messageMediaUnsupportedWeb'}; message.media = {_: 'messageMediaUnsupportedWeb'};
} else { } 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); //appPhotosManager.savePhoto(apiMessage.media.photo, mediaContext);
} }
break; break;
case 'messageMediaPoll': 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; break;
case 'messageMediaDocument': case 'messageMediaDocument':
if(apiMessage.media.ttl_seconds) { if(message.media.ttl_seconds) {
apiMessage.media = {_: 'messageMediaUnsupportedWeb'}; message.media = {_: 'messageMediaUnsupportedWeb'};
} else { } 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) { /* if(apiMessage.media.webpage.document) {
appDocsManager.saveDoc(apiMessage.media.webpage.document, mediaContext); appDocsManager.saveDoc(apiMessage.media.webpage.document, mediaContext);
} */ } */
appWebPagesManager.saveWebPage(apiMessage.media.webpage, apiMessage.mid, mediaContext); appWebPagesManager.saveWebPage(message.media.webpage, message.mid, mediaContext);
break; break;
/*case 'messageMediaGame': /*case 'messageMediaGame':
AppGamesManager.saveGame(apiMessage.media.game, apiMessage.mid, mediaContext); AppGamesManager.saveGame(apiMessage.media.game, apiMessage.mid, mediaContext);
apiMessage.media.handleMessage = true; apiMessage.media.handleMessage = true;
break; */ break; */
case 'messageMediaInvoice': case 'messageMediaInvoice':
apiMessage.media = {_: 'messageMediaUnsupportedWeb'}; message.media = {_: 'messageMediaUnsupportedWeb'};
break; break;
case 'messageMediaGeoLive': case 'messageMediaGeoLive':
apiMessage.media._ = 'messageMediaGeo'; message.media._ = 'messageMediaGeo';
break; break;
} }
} }
if(apiMessage.action) { if(message.action) {
let migrateFrom: number; let migrateFrom: number;
let migrateTo: number; let migrateTo: number;
switch(apiMessage.action._) { switch(message.action._) {
//case 'messageActionChannelEditPhoto': //case 'messageActionChannelEditPhoto':
case 'messageActionChatEditPhoto': 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); //appPhotosManager.savePhoto(apiMessage.action.photo, mediaContext);
if(isBroadcast) { // ! messageActionChannelEditPhoto не существует в принципе, это используется для перевода. if(isBroadcast) { // ! messageActionChannelEditPhoto не существует в принципе, это используется для перевода.
apiMessage.action._ = 'messageActionChannelEditPhoto'; message.action._ = 'messageActionChannelEditPhoto';
} }
break; break;
case 'messageActionChatEditTitle': case 'messageActionChatEditTitle':
if(isBroadcast) { if(isBroadcast) {
apiMessage.action._ = 'messageActionChannelEditTitle'; message.action._ = 'messageActionChannelEditTitle';
} }
break; break;
case 'messageActionChatDeletePhoto': case 'messageActionChatDeletePhoto':
if(isBroadcast) { if(isBroadcast) {
apiMessage.action._ = 'messageActionChannelDeletePhoto'; message.action._ = 'messageActionChannelDeletePhoto';
} }
break; break;
case 'messageActionChatAddUser': case 'messageActionChatAddUser':
if(apiMessage.action.users.length == 1) { if(message.action.users.length == 1) {
apiMessage.action.user_id = apiMessage.action.users[0]; message.action.user_id = message.action.users[0];
if(apiMessage.fromID == apiMessage.action.user_id) { if(message.fromID == message.action.user_id) {
if(isChannel) { if(isChannel) {
apiMessage.action._ = 'messageActionChatJoined'; message.action._ = 'messageActionChatJoined';
} else { } else {
apiMessage.action._ = 'messageActionChatReturn'; message.action._ = 'messageActionChatReturn';
} }
} }
} else if(apiMessage.action.users.length > 1) { } else if(message.action.users.length > 1) {
apiMessage.action._ = 'messageActionChatAddUsers'; message.action._ = 'messageActionChatAddUsers';
} }
break; break;
case 'messageActionChatDeleteUser': case 'messageActionChatDeleteUser':
if(apiMessage.fromID == apiMessage.action.user_id) { if(message.fromID == message.action.user_id) {
apiMessage.action._ = 'messageActionChatLeave'; message.action._ = 'messageActionChatLeave';
} }
break; break;
case 'messageActionChannelMigrateFrom': case 'messageActionChannelMigrateFrom':
migrateFrom = -apiMessage.action.chat_id; migrateFrom = -message.action.chat_id;
migrateTo = -channelID; migrateTo = -channelID;
break break
case 'messageActionChatMigrateTo': case 'messageActionChatMigrateTo':
migrateFrom = -channelID; migrateFrom = -channelID;
migrateTo = -apiMessage.action.channel_id; migrateTo = -message.action.channel_id;
break; break;
case 'messageActionHistoryClear': case 'messageActionHistoryClear':
//apiMessage.deleted = true; //apiMessage.deleted = true;
apiMessage.clear_history = true; message.clear_history = true;
delete apiMessage.pFlags.out; delete message.pFlags.out;
delete apiMessage.pFlags.unread; delete message.pFlags.unread;
break; break;
case 'messageActionPhoneCall': case 'messageActionPhoneCall':
delete apiMessage.fromID; delete message.fromID;
apiMessage.action.type = message.action.type =
(apiMessage.pFlags.out ? 'out_' : 'in_') + (message.pFlags.out ? 'out_' : 'in_') +
( (
apiMessage.action.reason._ == 'phoneCallDiscardReasonMissed' || message.action.reason._ == 'phoneCallDiscardReasonMissed' ||
apiMessage.action.reason._ == 'phoneCallDiscardReasonBusy' message.action.reason._ == 'phoneCallDiscardReasonBusy'
? 'missed' ? 'missed'
: 'ok' : '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) { if(message.message && message.message.length && !message.totalEntities) {
const myEntities = RichTextProcessor.parseEntities(apiMessage.message); const myEntities = RichTextProcessor.parseEntities(message.message);
const apiEntities = apiMessage.entities || []; const apiEntities = message.entities || [];
apiMessage.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !apiMessage.pending); message.totalEntities = RichTextProcessor.mergeEntities(myEntities, apiEntities, !message.pending);
} }
if(!options.isEdited) { if(!options.isEdited) {
this.messagesStorage[mid] = apiMessage; this.messagesStorage[mid] = message;
(this.messagesStorageByPeerID[peerID] ?? (this.messagesStorageByPeerID[peerID] = {}))[mid] = apiMessage; (this.messagesStorageByPeerID[peerID] ?? (this.messagesStorageByPeerID[peerID] = {}))[mid] = message;
} }
}); });
} }

4
src/lib/appManagers/appPhotosManager.ts

@ -5,7 +5,7 @@ import { bytesFromHex, getFileNameByLocation } from "../bin_utils";
import { DownloadOptions } from "../mtproto/apiFileManager"; import { DownloadOptions } from "../mtproto/apiFileManager";
import apiManager from "../mtproto/mtprotoworker"; import apiManager from "../mtproto/mtprotoworker";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase"; import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
import { calcImageInBox, isObject, safeReplaceArrayInObject } from "../utils"; import { calcImageInBox, defineNotNumerableProperties, isObject, safeReplaceArrayInObject } from "../utils";
import { MyDocument } from "./appDocsManager"; import { MyDocument } from "./appDocsManager";
import appDownloadManager from "./appDownloadManager"; import appDownloadManager from "./appDownloadManager";
import appUsersManager from "./appUsersManager"; import appUsersManager from "./appUsersManager";
@ -280,6 +280,8 @@ export class AppPhotosManager {
download = appDownloadManager.download(downloadOptions); download = appDownloadManager.download(downloadOptions);
download.then(blob => { download.then(blob => {
if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) { if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) {
defineNotNumerableProperties(cacheContext, ['downloaded', 'url']);
cacheContext.downloaded = blob.size; cacheContext.downloaded = blob.size;
cacheContext.url = URL.createObjectURL(blob); cacheContext.url = URL.createObjectURL(blob);

4
src/lib/appManagers/appStateManager.ts

@ -96,13 +96,17 @@ export class AppStateManager extends EventListenerBase<{
public saveState() { public saveState() {
if(this.state === undefined) return; if(this.state === undefined) return;
//let perf = performance.now();
this.setListenerResult('save', this.state); this.setListenerResult('save', this.state);
//this.log('saveState: event time:', performance.now() - perf);
//const pinnedOrders = appMessagesManager.dialogsStorage.pinnedOrders; //const pinnedOrders = appMessagesManager.dialogsStorage.pinnedOrders;
//perf = performance.now();
AppStorage.set({ AppStorage.set({
state: this.state state: this.state
}); });
//this.log('saveState: storage set time:', performance.now() - perf);
} }
public pushToState<T extends keyof State>(key: T, value: State[T]) { public pushToState<T extends keyof State>(key: T, value: State[T]) {

83
src/lib/appManagers/appUsersManager.ts

@ -1,12 +1,12 @@
import { formatPhoneNumber } from "../../components/misc"; 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/apiManager';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import serverTimeManager from "../mtproto/serverTimeManager"; import serverTimeManager from "../mtproto/serverTimeManager";
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
import searchIndexManager from "../searchIndexManager"; import searchIndexManager from "../searchIndexManager";
import { getAbbreviation, isObject, safeReplaceObject, tsNow } from "../utils"; import { defineNotNumerableProperties, getAbbreviation, isObject, safeReplaceObject, tsNow } from "../utils";
import appChatsManager from "./appChatsManager"; import appChatsManager from "./appChatsManager";
import appPeersManager from "./appPeersManager"; import appPeersManager from "./appPeersManager";
import appStateManager from "./appStateManager"; import appStateManager from "./appStateManager";
@ -40,15 +40,7 @@ import appStateManager from "./appStateManager";
sortName?: string, sortName?: string,
sortStatus?: number, sortStatus?: number,
}; */ }; */
export interface User extends MTUser.user { export type User = MTUser.user;
initials?: string,
num?: number,
rFirstName?: string,
rFullName?: string,
rPhone?: string,
sortName?: string,
sortStatus?: number,
}
export class AppUsersManager { export class AppUsersManager {
public users: {[userID: number]: User} = {}; public users: {[userID: number]: User} = {};
@ -172,7 +164,7 @@ export class AppUsersManager {
} }
return await apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => { 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); appChatsManager.saveApiChats(resolvedPeer.chats);
return this.users[this.usernames[username]]; return this.users[this.usernames[username]];
@ -237,75 +229,80 @@ export class AppUsersManager {
apiUsers.forEach((user) => this.saveApiUser(user)); apiUsers.forEach((user) => this.saveApiUser(user));
} }
public saveApiUser(apiUser: any, noReplace?: boolean) { public saveApiUser(_user: MTUser, noReplace?: boolean) {
if(!isObject(apiUser) || if(_user._ == 'userEmpty') return;
noReplace && isObject(this.users[apiUser.id]) && this.users[apiUser.id].first_name) {
const user = _user;
if(noReplace && isObject(this.users[user.id]) && this.users[user.id].first_name) {
return; return;
} }
var userID = apiUser.id; var userID = user.id;
var result = this.users[userID]; var result = this.users[userID];
if(apiUser.pFlags === undefined) { if(user.pFlags === undefined) {
apiUser.pFlags = {}; user.pFlags = {};
} }
if(apiUser.pFlags.min) { if(user.pFlags.min) {
if(result !== undefined) { if(result !== undefined) {
return; return;
} }
} }
if(apiUser.phone) { // * exclude from state
apiUser.rPhone = '+' + formatPhoneNumber(apiUser.phone).formatted; 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 || ''); const fullName = user.first_name + ' ' + (user.last_name || '');
if(apiUser.first_name) { if(user.first_name) {
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.first_name, {noLinks: true, noLinebreaks: true}) user.rFirstName = RichTextProcessor.wrapRichText(user.first_name, {noLinks: true, noLinebreaks: true})
apiUser.rFullName = apiUser.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : apiUser.rFirstName; user.rFullName = user.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : user.rFirstName;
} else { } else {
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'user_first_name_deleted'; user.rFirstName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_first_name_deleted';
apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'user_name_deleted'; user.rFullName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_name_deleted';
} }
if(apiUser.username) { if(user.username) {
var searchUsername = searchIndexManager.cleanUsername(apiUser.username); var searchUsername = searchIndexManager.cleanUsername(user.username);
this.usernames[searchUsername] = userID; 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(user.status) {
if(apiUser.status.expires) { if((user.status as UserStatus.userStatusOnline).expires) {
apiUser.status.expires -= serverTimeManager.serverTimeOffset (user.status as UserStatus.userStatusOnline).expires -= serverTimeManager.serverTimeOffset
} }
if(apiUser.status.was_online) { if((user.status as UserStatus.userStatusOffline).was_online) {
apiUser.status.was_online -= serverTimeManager.serverTimeOffset (user.status as UserStatus.userStatusOffline).was_online -= serverTimeManager.serverTimeOffset
} }
} }
if(apiUser.pFlags.bot) { if(user.pFlags.bot) {
apiUser.sortStatus = -1; user.sortStatus = -1;
} else { } else {
apiUser.sortStatus = this.getUserStatusForSort(apiUser.status); user.sortStatus = this.getUserStatusForSort(user.status);
} }
var result = this.users[userID]; var result = this.users[userID];
if(result === undefined) { if(result === undefined) {
result = this.users[userID] = apiUser; result = this.users[userID] = user;
} else { } else {
safeReplaceObject(result, apiUser); safeReplaceObject(result, user);
} }
$rootScope.$broadcast('user_update', userID); $rootScope.$broadcast('user_update', userID);
if(this.cachedPhotoLocations[userID] !== undefined) { if(this.cachedPhotoLocations[userID] !== undefined) {
safeReplaceObject(this.cachedPhotoLocations[userID], apiUser && safeReplaceObject(this.cachedPhotoLocations[userID], user &&
apiUser.photo ? apiUser.photo : {empty: true}); user.photo ? user.photo : {empty: true});
} }
} }

10
src/lib/storage.ts

@ -1,6 +1,6 @@
import { Modes } from './mtproto/mtproto_config'; import { Modes } from './mtproto/mtproto_config';
import { notifySomeone, isWorker } from '../helpers/context'; import { notifySomeone, isWorker } from '../helpers/context';
import { stringify } from '../helpers/json'; //import { stringify } from '../helpers/json';
class ConfigStorage { class ConfigStorage {
public keyPrefix = ''; public keyPrefix = '';
@ -72,7 +72,15 @@ class ConfigStorage {
value = obj[key]; value = obj[key];
key = prefix + key; key = prefix + key;
this.cache[key] = value; 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); value = stringify(value);
console.log('LocalStorage set: stringify time by own stringify:', performance.now() - perf); */
if(this.useLs) { if(this.useLs) {
try { try {

15
src/lib/utils.ts

@ -580,4 +580,17 @@ export function splitStringByLength(str: string, maxLength: number) {
return out; 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;

11
src/scripts/in/schema_additional_params.json

@ -211,4 +211,15 @@
"params": [ "params": [
{"name": "nested", "type": "Array<MessageEntity>"} {"name": "nested", "type": "Array<MessageEntity>"}
] ]
}, {
"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"}
]
}] }]
Loading…
Cancel
Save