From 307fa42c2b05098634878cb47ad78778ae0a1762 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Mon, 15 Feb 2021 13:26:26 +0400 Subject: [PATCH] Fix connection in Safari --- src/lib/mtproto/apiManager.ts | 6 +- src/lib/mtproto/dcConfigurator.ts | 20 ++++-- src/lib/mtproto/mtprotoworker.ts | 3 + src/lib/mtproto/networker.ts | 72 ++++++++++++++++----- src/lib/mtproto/transports/obfuscation.ts | 4 +- src/lib/mtproto/transports/tcpObfuscated.ts | 14 ++-- src/lib/mtproto/transports/transport.ts | 1 + src/lib/mtproto/transports/websocket.ts | 50 ++++++-------- 8 files changed, 110 insertions(+), 60 deletions(-) diff --git a/src/lib/mtproto/apiManager.ts b/src/lib/mtproto/apiManager.ts index 036f9738..97e98ed1 100644 --- a/src/lib/mtproto/apiManager.ts +++ b/src/lib/mtproto/apiManager.ts @@ -158,8 +158,8 @@ export class ApiManager { // mtpGetNetworker public getNetworker(dcId: number, options: InvokeApiOptions = {}): Promise { - //const connectionType: ConnectionType = options.fileDownload ? 'download' : (options.fileUpload ? 'upload' : 'client'); - const connectionType: ConnectionType = 'client'; + const connectionType: ConnectionType = options.fileDownload ? 'download' : (options.fileUpload ? 'upload' : 'client'); + //const connectionType: ConnectionType = 'client'; /// #if MTPROTO_HTTP_UPLOAD // @ts-ignore @@ -184,7 +184,7 @@ export class ApiManager { } const networkers = cache[dcId]; - if(networkers.length >= /* 1 */(connectionType === 'client' || transportType === 'https' ? 1 : (connectionType === 'download' ? 3 : 1))) { + if(networkers.length >= /* 1 */(connectionType === 'client' || transportType === 'https' ? 1 : (connectionType === 'download' ? 3 : 3))) { let i = networkers.length - 1, found = false; for(; i >= 0; --i) { if(networkers[i].isOnline) { diff --git a/src/lib/mtproto/dcConfigurator.ts b/src/lib/mtproto/dcConfigurator.ts index df54d79e..2ad70463 100644 --- a/src/lib/mtproto/dcConfigurator.ts +++ b/src/lib/mtproto/dcConfigurator.ts @@ -52,7 +52,7 @@ class SocketProxied extends EventListenerBase<{ }); } - send = (payload: Uint8Array) => { + public send(payload: Uint8Array) { const task: any = { type: 'socketProxy', payload: { @@ -63,7 +63,19 @@ class SocketProxied extends EventListenerBase<{ }; notifyAll(task); - }; + } + + public close() { + const task: any = { + type: 'socketProxy', + payload: { + type: 'close', + id: this.id + } + }; + + notifyAll(task); + } } export const socketsProxied: Map = new Map(); @@ -94,9 +106,9 @@ export class DcConfigurator { const chosenServer = 'wss://' + subdomain + '.web.telegram.org/' + path; const logSuffix = connectionType === 'upload' ? '-U' : connectionType === 'download' ? '-D' : ''; - const retryTimeout = connectionType === 'client' ? 30000 : 10000; + const retryTimeout = connectionType === 'client' ? 15000 : 10000; - const oooohLetMeLive: MTConnectionConstructable = (isSafari && isWebWorker) || true ? SocketProxied : Socket; + const oooohLetMeLive: MTConnectionConstructable = (isSafari && isWebWorker) /* || true */ ? SocketProxied : Socket; return new TcpObfuscated(oooohLetMeLive, dcId, chosenServer, logSuffix, retryTimeout); }; diff --git a/src/lib/mtproto/mtprotoworker.ts b/src/lib/mtproto/mtprotoworker.ts index 0a67a19a..d6816474 100644 --- a/src/lib/mtproto/mtprotoworker.ts +++ b/src/lib/mtproto/mtprotoworker.ts @@ -198,6 +198,9 @@ export class ApiManagerProxy extends CryptoWorkerMethods { if(socketTask.type === 'send') { const socket = this.sockets.get(id); socket.send(socketTask.payload); + } else if(socketTask.type === 'close') { + const socket = this.sockets.get(id); + socket.close(); } else if(socketTask.type === 'setup') { const socket = new Socket(socketTask.payload.dcId, socketTask.payload.url, socketTask.payload.logSuffix); diff --git a/src/lib/mtproto/networker.ts b/src/lib/mtproto/networker.ts index 032ba48c..40eb1af5 100644 --- a/src/lib/mtproto/networker.ts +++ b/src/lib/mtproto/networker.ts @@ -11,8 +11,8 @@ import { InvokeApiOptions } from '../../types'; import { longToBytes } from '../crypto/crypto_utils'; import MTTransport from './transports/transport'; import { convertToUint8Array, bufferConcat, bytesCmp, bytesToHex } from '../../helpers/bytes'; -import { nextRandomInt } from '../../helpers/random'; -import { CancellablePromise } from '../../helpers/cancellablePromise'; +import { nextRandomInt, randomLong } from '../../helpers/random'; +import { CancellablePromise, deferredPromise } from '../../helpers/cancellablePromise'; import { isSafari } from '../../helpers/userAgent'; import App from '../../config/app'; import DEBUG from '../../config/debug'; @@ -116,8 +116,6 @@ export default class MTPNetworker { private lastResponseTime = 0; private disconnectDelay: number; private pingPromise: CancellablePromise; - private sentPingTimes = 0; - private tt = 0; //public onConnectionStatusChange: (online: boolean) => void; private debugRequests: Array<{before: Uint8Array, after: Uint8Array}> = []; @@ -171,15 +169,11 @@ export default class MTPNetworker { /// #endif // * handle outcoming dead socket, server will close the connection - if((this.transport as TcpObfuscated).networker) { - if(isSafari) { - this.pingPromise = Promise.resolve(); - } else { - this.disconnectDelay = (this.transport as TcpObfuscated).retryTimeout / 1000 | 0; - //setInterval(this.sendPingDelayDisconnect, (this.disconnectDelay - 5) * 1000); - // ! this.sendPingDelayDisconnect(); - } - } + // if((this.transport as TcpObfuscated).networker) { + // this.disconnectDelay = /* (this.transport as TcpObfuscated).retryTimeout */75; + // //setInterval(this.sendPingDelayDisconnect, (this.disconnectDelay - 5) * 1000); + // this.sendPingDelayDisconnect(); + // } } public updateSession() { @@ -401,6 +395,52 @@ export default class MTPNetworker { // }); // }; + // private sendPingDelayDisconnect = () => { + // if(this.pingPromise || true) return; + + // /* if(!this.isOnline) { + // if((this.transport as TcpObfuscated).connected) { + // (this.transport as TcpObfuscated).connection.close(); + // } + + // return; + // } */ + + // const deferred = this.pingPromise = deferredPromise(); + + // const timeoutTime = this.disconnectDelay * 1000; + + // const startTime = Date.now(); + // this.wrapMtpCall('ping_delay_disconnect', { + // ping_id: randomLong(), + // disconnect_delay: this.disconnectDelay + // }, {}).then(pong => { + // const elapsedTime = Date.now() - startTime; + // this.log('sendPingDelayDisconnect: response', pong, elapsedTime > timeoutTime); + + // if(elapsedTime > timeoutTime) { + // deferred.reject(); + // } else { + // setTimeout(deferred.resolve, timeoutTime - elapsedTime); + // } + // }, deferred.reject).finally(() => { + // clearTimeout(rejectTimeout); + // //--this.sentPingTimes; + // }); + + // const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime); + + // deferred.catch(() => { + // this.log.error('sendPingDelayDisconnect: catch, closing connection if exists'); + // (this.transport as TcpObfuscated).connection.close(); + // }); + + // deferred.finally(() => { + // this.pingPromise = null; + // this.sendPingDelayDisconnect(); + // }); + // }; + /// #if MTPROTO_HTTP || MTPROTO_HTTP_UPLOAD public checkLongPoll = () => { const isClean = this.cleanupSent(); @@ -640,9 +680,9 @@ export default class MTPNetworker { }); } - /* if(!this.pingPromise && (this.transport as TcpObfuscated).networker) { - this.sendPingDelayDisconnect(); - } */ + // if((this.transport as TcpObfuscated).networker) { + // this.sendPingDelayDisconnect(); + // } /* this.sentPingTimes = 0; this.sendPingDelayDisconnect(); */ } diff --git a/src/lib/mtproto/transports/obfuscation.ts b/src/lib/mtproto/transports/obfuscation.ts index 608100e8..2e57efe0 100644 --- a/src/lib/mtproto/transports/obfuscation.ts +++ b/src/lib/mtproto/transports/obfuscation.ts @@ -95,8 +95,8 @@ export default class Obfuscation { /* this.enc = new aesjs.ModeOfOperation.ctr(encKey, new aesjs.Counter(encIv as any)); this.dec = new aesjs.ModeOfOperation.ctr(decKey, new aesjs.Counter(decIv as any)); */ - console.log('encKey', encKey.hex, encIv.hex); - console.log('decKey', decKey.hex, decIv.hex); + // console.log('encKey', encKey.hex, encIv.hex); + // console.log('decKey', decKey.hex, decIv.hex); this.encNew = new CTR(encKey, encIv); this.decNew = new CTR(decKey, decIv); diff --git a/src/lib/mtproto/transports/tcpObfuscated.ts b/src/lib/mtproto/transports/tcpObfuscated.ts index 259e6b78..dc40ab54 100644 --- a/src/lib/mtproto/transports/tcpObfuscated.ts +++ b/src/lib/mtproto/transports/tcpObfuscated.ts @@ -19,21 +19,17 @@ export default class TcpObfuscated implements MTTransport { }>> = []; private debug = Modes.debug && false; - private log: ReturnType; - public connected = false; - private lastCloseTime: number; - - private connection: MTConnection; + public connection: MTConnection; //private debugPayloads: MTPNetworker['debugRequests'] = []; constructor(private Connection: MTConnectionConstructable, private dcId: number, private url: string, private logSuffix: string, public retryTimeout: number) { let logLevel = LogLevels.error | LogLevels.log; if(this.debug) logLevel |= LogLevels.debug; - this.log = logger(`WS-${dcId}` + logSuffix, logLevel); + this.log = logger(`TCP-${dcId}` + logSuffix, logLevel); this.log('constructor'); this.connect(); @@ -53,6 +49,12 @@ export default class TcpObfuscated implements MTTransport { } } + for(const pending of this.pending) { + if(pending.encoded && pending.body) { + pending.encoded = this.encodeBody(pending.body); + } + } + setTimeout(() => { this.releasePending(); }, 0); diff --git a/src/lib/mtproto/transports/transport.ts b/src/lib/mtproto/transports/transport.ts index 02892299..ca73cb82 100644 --- a/src/lib/mtproto/transports/transport.ts +++ b/src/lib/mtproto/transports/transport.ts @@ -10,6 +10,7 @@ export interface MTConnection extends EventListenerBase<{ close: () => void, }> { send: (data: Uint8Array) => void; + close: () => void; } export interface MTConnectionConstructable { diff --git a/src/lib/mtproto/transports/websocket.ts b/src/lib/mtproto/transports/websocket.ts index bab2dc1b..6dd6d9bf 100644 --- a/src/lib/mtproto/transports/websocket.ts +++ b/src/lib/mtproto/transports/websocket.ts @@ -25,10 +25,15 @@ export default class Socket extends EventListenerBase<{ } private removeListeners() { + if(!this.ws) { + return; + } + this.ws.removeEventListener('open', this.handleOpen); this.ws.removeEventListener('close', this.handleClose); this.ws.removeEventListener('error', this.handleError); this.ws.removeEventListener('message', this.handleMessage); + this.ws = undefined; } private connect() { @@ -39,58 +44,45 @@ export default class Socket extends EventListenerBase<{ this.ws.addEventListener('error', this.handleError); this.ws.addEventListener('message', this.handleMessage); } + + public close() { + if(!this.ws) { + return; + } + + this.log.error('close execution'); + + this.ws.close(); + this.handleClose(); + } - handleOpen = () => { + private handleOpen = () => { this.log('opened'); this.debug && this.log.debug('sending init packet'); this.setListenerResult('open'); }; - handleError = (e: Event) => { + private handleError = (e: Event) => { this.log.error(e); }; - handleClose = () => { + private handleClose = () => { this.log('closed'/* , event, this.pending, this.ws.bufferedAmount */); this.removeListeners(); this.setListenerResult('close'); }; - handleMessage = (event: MessageEvent) => { + private handleMessage = (event: MessageEvent) => { this.debug && this.log.debug('<-', 'handleMessage', /* event, */event.data.byteLength); this.setListenerResult('message', event.data as ArrayBuffer); }; - send = (body: Uint8Array) => { + public send = (body: Uint8Array) => { this.debug && this.log.debug('-> body length to send:', body.length); this.ws.send(body); }; } - -/* const setupSafariFix = () => { - -}; - -if(isWebWorker) { - import('../../polyfill').then(() => { - //ctx.postMessage('ready'); - let socket: Socket; - ctx.addEventListener('message', (e) => { - console.log('websocket worker message', e); - const task = e.data; - - if(task.type === 'send') { - // const promise = socket.send(task.payload); - // if(task.taskId) { - // promise - // } - } else if(task.type === 'setup') { - socket = new Socket(task.dcId, task.url, task.logSuffix, task.retryTimeout); - } - }); - }); -} */