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.
 
 
 
 
 

196 lines
5.5 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 MTTransport, { MTConnection, MTConnectionConstructable } from './transports/transport';
import Modes from '../../config/modes';
/// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD
import HTTP from './transports/http';
/// #endif
/// #if !MTPROTO_HTTP
import Socket from './transports/websocket';
import TcpObfuscated from './transports/tcpObfuscated';
import EventListenerBase from '../../helpers/eventListenerBase';
import { isSafari } from '../../helpers/userAgent';
import { notifyAll, isWebWorker } from '../../helpers/context';
/// #endif
export type TransportType = 'websocket' | 'https' | 'http';
export type ConnectionType = 'client' | 'download' | 'upload';
type Servers = {
[transportType in TransportType]: {
[connectionType in ConnectionType]: {
[dcId: number]: MTTransport[]
}
}
};
let socketId = 0;
const TEST_SUFFIX = Modes.test ? '_test' : '';
/// #if !MTPROTO_SW
class SocketProxied extends EventListenerBase<{
open: () => void,
message: (buffer: ArrayBuffer) => any,
close: () => void,
}> implements MTConnection {
private id: number;
constructor(protected dcId: number, protected url: string, logSuffix: string) {
super();
this.id = ++socketId;
socketsProxied.set(this.id, this);
notifyAll({
type: 'socketProxy',
payload: {
type: 'setup',
payload: {
dcId,
url,
logSuffix
},
id: this.id
}
});
}
public send(payload: Uint8Array) {
const task: any = {
type: 'socketProxy',
payload: {
type: 'send',
payload,
id: this.id
}
};
notifyAll(task);
}
public close() {
const task: any = {
type: 'socketProxy',
payload: {
type: 'close',
id: this.id
}
};
notifyAll(task);
}
}
/// #endif
export const socketsProxied: Map<number, SocketProxied> = new Map();
export class DcConfigurator {
private sslSubdomains = ['pluto', 'venus', 'aurora', 'vesta', 'flora'];
private dcOptions = Modes.test
? [
{id: 1, host: '149.154.175.10', port: 80},
{id: 2, host: '149.154.167.40', port: 80},
{id: 3, host: '149.154.175.117', port: 80}
]
: [
{id: 1, host: '149.154.175.50', port: 80},
{id: 2, host: '149.154.167.50', port: 80},
{id: 3, host: '149.154.175.100', port: 80},
{id: 4, host: '149.154.167.91', port: 80},
{id: 5, host: '149.154.171.5', port: 80}
];
private chosenServers: Servers = {} as any;
/// #if !MTPROTO_HTTP
private transportSocket = (dcId: number, connectionType: ConnectionType) => {
const subdomain = this.sslSubdomains[dcId - 1];
const path = 'apiws' + TEST_SUFFIX;
const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path;
const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : '';
const retryTimeout = connectionType === 'client' ? 10000 : 10000;
const oooohLetMeLive: MTConnectionConstructable = (isSafari && isWebWorker && typeof(SocketProxied) !== 'undefined') /* || true */ ? SocketProxied : Socket;
return new TcpObfuscated(oooohLetMeLive, dcId, chosenServer, logSuffix, retryTimeout);
};
/// #endif
/// #if MTPROTO_HTTP_UPLOAD || MTPROTO_HTTP
private transportHTTP = (dcId: number, connectionType: ConnectionType) => {
if(Modes.ssl || !Modes.http) {
const subdomain = this.sslSubdomains[dcId - 1] + (connectionType !== 'client' ? '-1' : '');
const path = Modes.test ? 'apiw_test1' : 'apiw1';
const chosenServer = 'https://' + subdomain + '.web.telegram.org/' + path;
return new HTTP(dcId, chosenServer);
} else {
for(let dcOption of this.dcOptions) {
if(dcOption.id === dcId) {
const chosenServer = 'http://' + dcOption.host + (dcOption.port !== 80 ? ':' + dcOption.port : '') + '/apiw1';
return new HTTP(dcId, chosenServer);
}
}
}
};
/// #endif
public chooseServer(dcId: number, connectionType: ConnectionType = 'client', transportType: TransportType = 'websocket', reuse = true) {
/* if(transportType === 'websocket' && !Modes.multipleConnections) {
connectionType = 'client';
} */
if(!this.chosenServers.hasOwnProperty(transportType)) {
this.chosenServers[transportType] = {
client: {},
download: {},
upload: {}
};
}
const servers = this.chosenServers[transportType][connectionType];
if(!(dcId in servers)) {
servers[dcId] = [];
}
const transports = servers[dcId];
if(!transports.length || !reuse/* || (upload && transports.length < 1) */) {
let transport: MTTransport;
/// #if MTPROTO_HTTP_UPLOAD
transport = (transportType === 'websocket' ? this.transportSocket : this.transportHTTP)(dcId, connectionType);
/// #elif !MTPROTO_HTTP
transport = this.transportSocket(dcId, connectionType);
/// #else
transport = this.transportHTTP(dcId, connectionType);
/// #endif
if(!transport) {
console.error('No chosenServer!', dcId);
return null;
}
if(reuse) {
transports.push(transport);
}
return transport;
}
return transports[0];
}
}
export default new DcConfigurator();