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.
 
 
 
 
 

128 lines
4.0 KiB

/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import App from '../../../config/app';
import deferredPromise from '../../../helpers/cancellablePromise';
import EventListenerBase from '../../../helpers/eventListenerBase';
import pause from '../../../helpers/schedulers/pause';
import {TransportType, DcConfigurator} from '../dcConfigurator';
import type HTTP from './http';
import type TcpObfuscated from './tcpObfuscated';
import MTTransport from './transport';
export class MTTransportController extends EventListenerBase<{
change: (opened: MTTransportController['opened']) => void,
transport: (type: TransportType) => void
}> {
private opened: Map<TransportType, number>;
private transports: {[k in TransportType]?: MTTransport};
private pinging: boolean;
private dcConfigurator: DcConfigurator;
constructor() {
super(true);
this.opened = new Map();
/* this.addEventListener('change', (opened) => {
this.dispatchEvent('transport', opened.get('websocket') || !opened.get('https') ? 'websocket' : 'https');
}); */
this.addEventListener('change', (opened) => {
if(!opened.get('websocket')) {
this.waitForWebSocket();
}
});
// setTimeout(() => {
// this.waitForWebSocket();
// }, 200); // wait for first transport so won't have delay for first WS
}
public async pingTransports() {
const dcConfigurator = this.dcConfigurator ??= new DcConfigurator();
const timeout = 2000;
const transports: {[k in TransportType]?: MTTransport} = this.transports = {
https: dcConfigurator.chooseServer(App.baseDcId, 'client', 'https', false),
websocket: dcConfigurator.chooseServer(App.baseDcId, 'client', 'websocket', false)
};
const httpPromise = deferredPromise<boolean>();
((this.transports.https as HTTP)._send(new Uint8Array(), 'no-cors') as any as Promise<any>)
.then(() => httpPromise.resolve(true), () => httpPromise.resolve(false));
setTimeout(() => httpPromise.resolve(false), timeout);
const websocketPromise = deferredPromise<boolean>();
const socket = transports.websocket as TcpObfuscated;
socket.setAutoReconnect(false);
socket.connection.addEventListener('close', () => websocketPromise.resolve(false), {once: true});
socket.connection.addEventListener('open', () => websocketPromise.resolve(true), {once: true});
setTimeout(() => {
if(websocketPromise.isFulfilled || websocketPromise.isRejected) {
return;
}
if(socket.connection) {
socket.connection.close();
}
websocketPromise.resolve(false);
}, timeout);
const [isHttpAvailable, isWebSocketAvailable] = await Promise.all([httpPromise, websocketPromise]);
for(const transportType in transports) {
const transport = transports[transportType as TransportType];
transport.destroy();
}
const result = {
https: isHttpAvailable || this.opened.get('https') > 0,
websocket: isWebSocketAvailable || this.opened.get('websocket') > 0
};
// result.websocket = false;
return result;
}
public async waitForWebSocket() {
if(this.pinging) return;
this.pinging = true;
while(true) {
const {https, websocket} = await this.pingTransports();
if(https || websocket) {
this.dispatchEvent('transport', websocket || !https ? 'websocket' : 'https');
}
if(websocket) {
break;
}
await pause(10000);
}
this.pinging = false;
}
public setTransportValue(type: TransportType, value: boolean) {
let length = this.opened.get(type) || 0;
length += value ? 1 : -1;
this.opened.set(type, length);
this.dispatchEvent('change', this.opened);
}
public setTransportOpened(type: TransportType) {
return this.setTransportValue(type, true);
}
public setTransportClosed(type: TransportType) {
return this.setTransportValue(type, false);
}
}
const transportController = new MTTransportController();
export default transportController;