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.
 
 
 
 
 

167 lines
4.6 KiB

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import App from "../../config/app";
import { MOUNT_CLASS_TO } from "../../config/debug";
import tabId from "../../config/tabId";
import IS_SHARED_WORKER_SUPPORTED from "../../environment/sharedWorkerSupport";
import EventListenerBase from "../../helpers/eventListenerBase";
import idleController from "../../helpers/idleController";
import { logger } from "../logger";
import rootScope from "../rootScope";
import sessionStorage from "../sessionStorage";
import apiManagerProxy from "./mtprotoworker";
export type AppInstance = {
id: number,
idle: boolean,
time: number
};
export type InstanceDeactivateReason = 'version' | 'tabs';
const CHECK_INSTANCE_INTERVAL = 5000;
const DEACTIVATE_TIMEOUT = 30000;
const MULTIPLE_TABS_THRESHOLD = 20000;
const IS_MULTIPLE_TABS_SUPPORTED = IS_SHARED_WORKER_SUPPORTED;
export class SingleInstance extends EventListenerBase<{
activated: () => void,
deactivated: (reason: InstanceDeactivateReason) => void
}> {
private instanceId: number;
private started: boolean;
private masterInstance: boolean;
private deactivateTimeout: number;
private deactivated: InstanceDeactivateReason;
private log = logger('INSTANCE');
constructor() {
super(false);
this.log = logger('INSTANCE');
this.instanceId = tabId;
}
public get deactivatedReason() {
return this.deactivated;
}
public start() {
this.reset();
if(!this.started/* && !Config.Navigator.mobile && !Config.Modes.packed */) {
this.started = true;
idleController.addEventListener('change', this.checkInstance);
setInterval(this.checkInstance, CHECK_INSTANCE_INTERVAL);
this.checkInstance();
try {
document.documentElement.addEventListener('beforeunload', this.clearInstance);
} catch(e) {}
}
}
private reset() {
this.masterInstance = false;
this.clearDeactivateTimeout();
this.deactivated = undefined;
}
private clearInstance = () => {
if(this.masterInstance && !this.deactivated) {
this.log.warn('clear master instance');
sessionStorage.delete('xt_instance');
}
};
public activateInstance() {
if(this.deactivated) {
this.reset();
this.checkInstance(false);
this.dispatchEvent('activated');
}
}
private deactivateInstance(reason: InstanceDeactivateReason) {
if(this.masterInstance || this.deactivated) {
return;
}
this.log.warn('deactivate', reason);
this.clearDeactivateTimeout();
this.deactivated = reason;
this.dispatchEvent('deactivated', reason);
}
private clearDeactivateTimeout() {
if(this.deactivateTimeout) {
clearTimeout(this.deactivateTimeout);
this.deactivateTimeout = 0;
}
}
private checkInstance = async(idle = idleController.isIdle) => {
if(this.deactivated) {
return;
}
const time = Date.now();
const newInstance: AppInstance = {
id: this.instanceId,
idle,
time
};
const [curInstance, build = App.build] = await Promise.all([
sessionStorage.get('xt_instance', false),
sessionStorage.get('k_build', false)
]);
if(build > App.build) {
this.masterInstance = false;
rootScope.managers.networkerFactory.stopAll();
this.deactivateInstance('version');
apiManagerProxy.toggleStorages(false, false);
return;
} else if(IS_MULTIPLE_TABS_SUPPORTED) {
sessionStorage.set({xt_instance: newInstance});
return;
}
// this.log('check instance', newInstance, curInstance)
if(!idle ||
!curInstance ||
curInstance.id === this.instanceId ||
curInstance.time < (time - MULTIPLE_TABS_THRESHOLD)) {
sessionStorage.set({xt_instance: newInstance});
if(!this.masterInstance) {
this.masterInstance = true;
rootScope.managers.networkerFactory.startAll();
this.log.warn('now master instance', newInstance);
}
this.clearDeactivateTimeout();
} else if(this.masterInstance) {
this.masterInstance = false;
rootScope.managers.networkerFactory.stopAll();
this.log.warn('now idle instance', newInstance);
this.deactivateTimeout ||= window.setTimeout(() => this.deactivateInstance('tabs'), DEACTIVATE_TIMEOUT);
}
};
}
const singleInstance = new SingleInstance();
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.singleInstance = singleInstance);
export default singleInstance;