/* * 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 * https://github.com/zhukov/webogram/blob/master/LICENSE */ import MTTransport, {MTConnectionConstructable} from './transports/transport'; import Modes from '../../config/modes'; import App from '../../config/app'; import indexOfAndSplice from '../../helpers/array/indexOfAndSplice'; // #if MTPROTO_HAS_HTTP import HTTP from './transports/http'; // #endif // #if MTPROTO_HAS_WS import Socket from './transports/websocket'; import TcpObfuscated from './transports/tcpObfuscated'; import {IS_WEB_WORKER} from '../../helpers/context'; import {DcId} from '../../types'; import {getEnvironment} from '../../environment/utils'; // #if !MTPROTO_SW && SAFARI_PROXY_WEBSOCKET import SocketProxied from './transports/socketProxied'; // #endif // #endif export type TransportType = 'websocket' | 'https' | 'http'; export type ConnectionType = 'client' | 'download' | 'upload'; type Servers = { [transportType in TransportType]: { [connectionType in ConnectionType]: { [dcId: DcId]: MTTransport[] } } }; const TEST_SUFFIX = Modes.test ? '_test' : ''; const PREMIUM_SUFFIX = '_premium'; export function getTelegramConnectionSuffix(connectionType: ConnectionType) { return connectionType === 'client' ? '' : '-1'; } // #if MTPROTO_HAS_WS export function constructTelegramWebSocketUrl(dcId: DcId, connectionType: ConnectionType, premium?: boolean) { const suffix = getTelegramConnectionSuffix(connectionType); const path = connectionType !== 'client' ? 'apiws' + TEST_SUFFIX + (premium ? PREMIUM_SUFFIX : '') : ('apiws' + TEST_SUFFIX); const chosenServer = `wss://${App.suffix.toLowerCase()}ws${dcId}${suffix}.web.telegram.org/${path}`; return chosenServer; } // #endif 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} ]; public chosenServers: Servers = {} as any; // #if MTPROTO_HAS_WS private transportSocket = (dcId: DcId, connectionType: ConnectionType, premium?: boolean) => { const chosenServer = constructTelegramWebSocketUrl(dcId, connectionType, premium); const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : ''; const retryTimeout = connectionType === 'client' ? 10000 : 10000; let oooohLetMeLive: MTConnectionConstructable; // #if MTPROTO_SW || !SAFARI_PROXY_WEBSOCKET oooohLetMeLive = Socket; // #else oooohLetMeLive = (getEnvironment().IS_SAFARI && IS_WEB_WORKER && typeof(SocketProxied) !== 'undefined') /* || true */ ? SocketProxied : Socket; // #endif return new TcpObfuscated(oooohLetMeLive, dcId, chosenServer, logSuffix, retryTimeout); }; // #endif // #if MTPROTO_HAS_HTTP private transportHTTP = (dcId: DcId, connectionType: ConnectionType, premium?: boolean) => { let chosenServer: string; if(Modes.ssl || !Modes.http) { const suffix = getTelegramConnectionSuffix(connectionType); const subdomain = this.sslSubdomains[dcId - 1] + suffix; const path = Modes.test ? 'apiw_test1' : 'apiw1'; chosenServer = 'https://' + subdomain + '.web.telegram.org/' + path; } else { for(const dcOption of this.dcOptions) { if(dcOption.id === dcId) { chosenServer = 'http://' + dcOption.host + (dcOption.port !== 80 ? ':' + dcOption.port : '') + '/apiw1'; break; } } } const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : ''; return new HTTP(dcId, chosenServer, logSuffix); }; // #endif public chooseServer( dcId: DcId, connectionType: ConnectionType = 'client', transportType: TransportType = Modes.transport, reuse = true, premium?: boolean ) { /* 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_HAS_WS && MTPROTO_HAS_HTTP transport = (transportType === 'websocket' ? this.transportSocket : this.transportHTTP)(dcId, connectionType, premium); // #elif !MTPROTO_HTTP transport = this.transportSocket(dcId, connectionType, premium); // #else transport = this.transportHTTP(dcId, connectionType, premium); // #endif if(!transport) { console.error('No chosenServer!', dcId); return null; } if(reuse) { transports.push(transport); } return transport; } return transports[0]; } public static removeTransport(obj: any, transport: T) { for(const transportType in obj) { // @ts-ignore for(const connectionType in obj[transportType]) { // @ts-ignore for(const dcId in obj[transportType][connectionType]) { // @ts-ignore const transports: T[] = obj[transportType][connectionType][dcId]; indexOfAndSplice(transports, transport); } } } } }