Telegram Web K with changes to work inside I2P https://web.telegram.i2p/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
6.5 KiB

4 years ago
import AppStorage from '../storage';
import appMessagesManager, { Dialog, DialogsStorage, FiltersStorage } from './appMessagesManager';
import appMessagesIDsManager from './appMessagesIDsManager';
import appPeersManager from './appPeersManager';
import appChatsManager from './appChatsManager';
import appUsersManager from './appUsersManager';
import apiUpdatesManager from './apiUpdatesManager';
import { copy } from '../utils';
4 years ago
import { logger } from '../logger';
4 years ago
const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day
type State = Partial<{
dialogs: Dialog[],
allDialogsLoaded: DialogsStorage['allDialogsLoaded'],
peers: {[peerID: string]: any},
messages: any[],
contactsList: number[],
updates: any,
filters: FiltersStorage['filters'],
maxSeenMsgID: number,
stateCreatedTime: number,
recentEmoji: string[],
topPeers: number[],
recentSearch: number[]
}>;
4 years ago
export class AppStateManager {
public loaded: Promise<any>;
private log = logger('STATE'/* , LogLevels.error */);
private state: State = {};
4 years ago
constructor() {
this.loadSavedState();
}
public loadSavedState() {
if(this.loaded) return this.loaded;
return this.loaded = new Promise((resolve, reject) => {
AppStorage.get<State>('state').then((state) => {
const time = Date.now();
if((state?.stateCreatedTime ?? 0) + REFRESH_EVERY < time) {
this.log('will refresh state', state.stateCreatedTime, time);
(['dialogs', 'allDialogsLoaded', 'messages', 'contactsList', 'stateCreatedTime',
'updates', 'maxSeenMsgID', 'filters', 'topPeers'] as any as Array<keyof State>).forEach(key => {
delete state[key];
});
//state = {};
}
4 years ago
const {dialogs, allDialogsLoaded, peers, messages, contactsList, maxSeenMsgID, updates, filters} = state;
4 years ago
this.state = state || {};
this.state.peers = peers || {};
if(!this.state.hasOwnProperty('stateCreatedTime')) {
this.state.stateCreatedTime = Date.now();
}
4 years ago
this.log('state res', dialogs, messages);
if(maxSeenMsgID && !appMessagesIDsManager.getMessageIDInfo(maxSeenMsgID)[1]) {
appMessagesManager.maxSeenID = maxSeenMsgID;
}
//return resolve();
if(peers) {
for(let peerID in peers) {
let peer = peers[peerID];
if(+peerID < 0) appChatsManager.saveApiChat(peer);
else appUsersManager.saveApiUser(peer);
}
}
if(contactsList && Array.isArray(contactsList) && contactsList.length) {
contactsList.forEach(userID => {
appUsersManager.pushContact(userID);
});
appUsersManager.contactsFillPromise = Promise.resolve(appUsersManager.contactsList);
}
if(messages) {
/* let tempID = this.tempID;
for(let message of messages) {
if(message.id < tempID) {
tempID = message.id;
}
}
if(tempID != this.tempID) {
this.log('Set tempID to:', tempID);
this.tempID = tempID;
} */
appMessagesManager.saveMessages(messages);
// FIX FILE_REFERENCE_EXPIRED KOSTIL'1999
for(let message of messages) {
if(message.media) {
appMessagesManager.wrapSingleMessage(message.mid, true);
}
}
}
if(allDialogsLoaded) {
appMessagesManager.dialogsStorage.allDialogsLoaded = allDialogsLoaded;
}
if(filters) {
for(const filterID in filters) {
appMessagesManager.filtersStorage.saveDialogFilter(filters[filterID], false);
}
}
if(dialogs) {
dialogs.forEachReverse(dialog => {
appMessagesManager.saveConversation(dialog);
});
}
apiUpdatesManager.attach(updates ?? null);
resolve(state);
}).catch(resolve).finally(() => {
setInterval(() => this.saveState(), 10000);
});
});
}
public getState() {
return this.loadSavedState();
}
public saveState() {
const messages: any[] = [];
const dialogs: Dialog[] = [];
const peers = this.state.peers;
4 years ago
for(const folderID in appMessagesManager.dialogsStorage.byFolders) {
const folder = appMessagesManager.dialogsStorage.getFolder(+folderID);
for(let dialog of folder) {
const historyStorage = appMessagesManager.historiesStorage[dialog.peerID];
const history = [].concat(historyStorage?.pending ?? [], historyStorage?.history ?? []);
dialog = copy(dialog);
let removeUnread = 0;
for(const mid of history) {
const message = appMessagesManager.getMessage(mid);
if(/* message._ != 'messageEmpty' && */message.id > 0) {
messages.push(message);
if(message.fromID != dialog.peerID) {
peers[message.fromID] = appPeersManager.getPeer(message.fromID);
}
dialog.top_message = message.mid;
break;
} else if(message.pFlags && message.pFlags.unread) {
++removeUnread;
}
}
if(removeUnread && dialog.unread_count) dialog.unread_count -= removeUnread;
dialogs.push(dialog);
peers[dialog.peerID] = appPeersManager.getPeer(dialog.peerID);
}
}
const us = apiUpdatesManager.updatesState;
const updates = {
seq: us.seq,
pts: us.pts,
date: us.date
};
const contactsList = [...appUsersManager.contactsList];
for(const userID of contactsList) {
if(!peers[userID]) {
peers[userID] = appUsersManager.getUser(userID);
}
}
const filters = appMessagesManager.filtersStorage.filters;
//const pinnedOrders = appMessagesManager.dialogsStorage.pinnedOrders;
AppStorage.set({
state: Object.assign({}, this.state, {
dialogs,
messages,
allDialogsLoaded: appMessagesManager.dialogsStorage.allDialogsLoaded,
peers,
contactsList,
filters,
//pinnedOrders,
updates,
maxSeenMsgID: appMessagesManager.maxSeenID
})
});
}
public pushToState<T extends keyof State>(key: T, value: State[T]) {
4 years ago
this.state[key] = value;
}
public pushPeer(peerID: number) {
this.state.peers[peerID] = appPeersManager.getPeer(peerID);
4 years ago
}
}
const appStateManager = new AppStateManager();
// @ts-ignore
if(process.env.NODE_ENV != 'production') {
(window as any).appStateManager = appStateManager;
}
4 years ago
export default appStateManager;