@ -41,6 +41,8 @@ import isObject from '../../helpers/object/isObject';
import forEachReverse from '../../helpers/array/forEachReverse' ;
import forEachReverse from '../../helpers/array/forEachReverse' ;
import sortLongsArray from '../../helpers/long/sortLongsArray' ;
import sortLongsArray from '../../helpers/long/sortLongsArray' ;
import randomize from '../../helpers/array/randomize' ;
import randomize from '../../helpers/array/randomize' ;
import { CancellablePromise , deferredPromise } from '../../helpers/cancellablePromise' ;
import { pause } from '../../helpers/schedulers/pause' ;
//console.error('networker included!', new Error().stack);
//console.error('networker included!', new Error().stack);
@ -50,6 +52,7 @@ export type MTMessageOptions = InvokeApiOptions & Partial<{
notContentRelated : true , // ACK
notContentRelated : true , // ACK
noSchedule : true ,
noSchedule : true ,
// withResult: true,
messageId : MTLong ,
messageId : MTLong ,
} > ;
} > ;
@ -62,10 +65,7 @@ export type MTMessage = InvokeApiOptions & MTMessageOptions & {
acked? : boolean ,
acked? : boolean ,
deferred ? : {
deferred? : CancellablePromise < void > ,
resolve : any ,
reject : any
} ,
container? : boolean ,
container? : boolean ,
inner? : MTLong [ ] ,
inner? : MTLong [ ] ,
@ -81,8 +81,35 @@ export type MTMessage = InvokeApiOptions & MTMessageOptions & {
noResponse? : true , // only with http (http_wait for longPoll)
noResponse? : true , // only with http (http_wait for longPoll)
} ;
} ;
const CONNECTION_TIMEOUT = 5000 ;
const DRAIN_TIMEOUT = 10000 ;
const DRAIN_TIMEOUT = 10000 ;
const delays : {
[ k in 'client' | 'file' ] : {
disconnectDelayMin : number ,
disconnectDelayMax : number ,
pingInterval : number ,
pingMaxTime : number ,
connectionTimeout : number
}
} = {
client : {
disconnectDelayMin : 7 ,
disconnectDelayMax : 20 ,
pingInterval : 2000 ,
pingMaxTime : 5 ,
connectionTimeout : 5000
} ,
file : {
disconnectDelayMin : 10 ,
disconnectDelayMax : 24 ,
pingInterval : 3000 ,
pingMaxTime : 7 ,
connectionTimeout : 7500
}
} ;
const RESEND_OPTIONS : MTMessageOptions = {
noSchedule : true ,
notContentRelated : true
} ;
let invokeAfterMsgConstructor : number ;
let invokeAfterMsgConstructor : number ;
export default class MTPNetworker {
export default class MTPNetworker {
@ -100,7 +127,8 @@ export default class MTPNetworker {
private pendingMessages : { [ msgId : MTLong ] : number } = { } ;
private pendingMessages : { [ msgId : MTLong ] : number } = { } ;
private pendingAcks : Array < MTLong > = [ ] ;
private pendingAcks : Array < MTLong > = [ ] ;
private pendingResends : Array < MTLong > = [ ] ;
private pendingResendReq : MTLong [ ] = [ ] ;
// private pendingResendAnsReq: MTLong[] = [];
public connectionInited : boolean ;
public connectionInited : boolean ;
private nextReqTimeout : number ;
private nextReqTimeout : number ;
@ -123,15 +151,16 @@ export default class MTPNetworker {
private serverSalt : Uint8Array ;
private serverSalt : Uint8Array ;
private lastResendReq : {
private lastResendReq : {
req_msg_id : MTLong ,
reqMsgId : MTLong ,
resend_msg_ids : Array < MTLong >
msgIds : MTPNetworker [ 'pendingResendReq' ]
} | null = null ;
} ;
// private lastResendAnsReq: MTPNetworker['lastResendReq'];
private name : string ;
private name : string ;
private log : ReturnType < typeof logger > ;
private log : ReturnType < typeof logger > ;
public isOnline = false ;
public isOnline = false ;
public status : ConnectionStatus = ConnectionStatus . Closed ;
private status : ConnectionStatus = ConnectionStatus . Closed ;
private lastResponseTime = 0 ;
private lastResponseTime = 0 ;
private debug = DEBUG /* && false */ || Modes . debug ;
private debug = DEBUG /* && false */ || Modes . debug ;
@ -143,12 +172,19 @@ export default class MTPNetworker {
public transport : MTTransport ;
public transport : MTTransport ;
//private disconnectDelay: number;
/// #if MTPROTO_HAS_WS
//private pingPromise: CancellablePromise<any>;
private pingDelayDisconnectDeferred : CancellablePromise < string > ;
private pingPromise : Promise < void > ;
// private pingInterval: number;
private lastPingTime : number ;
private lastPingDelayDisconnectId : string ;
/// #endif
//public onConnectionStatusChange: (online: boolean) => void;
//public onConnectionStatusChange: (online: boolean) => void;
//private debugRequests: Array<{before: Uint8Array, after: Uint8Array}> = [];
//private debugRequests: Array<{before: Uint8Array, after: Uint8Array}> = [];
private delays : typeof delays [ keyof typeof delays ] ;
constructor (
constructor (
public dcId : number ,
public dcId : number ,
private authKey : Uint8Array ,
private authKey : Uint8Array ,
@ -162,6 +198,7 @@ export default class MTPNetworker {
this . isFileUpload = ! ! options . fileUpload ;
this . isFileUpload = ! ! options . fileUpload ;
this . isFileDownload = ! ! options . fileDownload ;
this . isFileDownload = ! ! options . fileDownload ;
this . isFileNetworker = this . isFileUpload || this . isFileDownload ;
this . isFileNetworker = this . isFileUpload || this . isFileDownload ;
this . delays = this . isFileNetworker ? delays.file : delays.client ;
const suffix = this . isFileUpload ? '-U' : this . isFileDownload ? '-D' : '' ;
const suffix = this . isFileUpload ? '-U' : this . isFileDownload ? '-D' : '' ;
this . name = 'NET-' + dcId + suffix ;
this . name = 'NET-' + dcId + suffix ;
@ -182,13 +219,6 @@ export default class MTPNetworker {
// /* rootScope.offline = true
// /* rootScope.offline = true
// rootScope.offlineConnecting = true */
// rootScope.offlineConnecting = true */
// }
// }
// * handle outcoming dead socket, server will close the connection
// if((this.transport as TcpObfuscated).networker) {
// this.disconnectDelay = /* (this.transport as TcpObfuscated).retryTimeout */75;
// //setInterval(this.sendPingDelayDisconnect, (this.disconnectDelay - 5) * 1000);
// this.sendPingDelayDisconnect();
// }
}
}
private updateSession() {
private updateSession() {
@ -389,6 +419,19 @@ export default class MTPNetworker {
/// #endif
/// #endif
}
}
this . log ( 'change transport' , transport , oldTransport ) ;
/// #if MTPROTO_HAS_WS
this . clearPingDelayDisconnect ( ) ;
// if(this.pingInterval !== undefined) {
// clearInterval(this.pingInterval);
// this.pingInterval = undefined;
// }
// this.clearPing();
/// #endif
this . transport = transport ;
this . transport = transport ;
if ( ! transport ) {
if ( ! transport ) {
return ;
return ;
@ -408,9 +451,19 @@ export default class MTPNetworker {
/// #endif
/// #endif
/// #endif
/// #endif
if ( transport . connected && ( transport as TcpObfuscated ) . connection ) {
/// #if MTPROTO_HAS_WS
this . setConnectionStatus ( ConnectionStatus . Connected ) ;
// * handle outcoming dead socket, server will close the connection
if ( ( transport as TcpObfuscated ) . connection ) {
// this.sendPingDelayDisconnect();
if ( transport . connected ) {
this . setConnectionStatus ( ConnectionStatus . Connected ) ;
}
// this.pingInterval = ctx.setInterval(this.sendPing, PING_INTERVAL);
// this.sendPing();
}
}
/// #endif
this . resend ( ) ;
this . resend ( ) ;
}
}
@ -435,112 +488,125 @@ export default class MTPNetworker {
}
}
}
}
// private sendPingDelayDisconnect = () => {
/ * p r i v a t e c l e a r P i n g ( ) {
// if(this.pingPromise || true) return;
if ( this . pingPromise ) {
this . pingPromise = undefined ;
// if(!this.isOnline) {
}
// if((this.transport as TcpObfuscated).connected) {
// (this.transport as TcpObfuscated).handleClose();
this . lastPingTime = undefined ;
// }
}
// return;
private sendPing = ( ) = > {
// }
// return;
// this.log('sendPingDelayDisconnect', this.sentPingTimes);
// if(!(this.transport as TcpObfuscated).connected) {
// this.clearPing();
// /* if(this.tt) clearTimeout(this.tt);
// return;
// this.tt = self.setTimeout(() => {
// }
// (this.transport as any).ws.close(1000);
// this.tt = 0;
if ( this . pingPromise ) {
// }, this.disconnectDelay * 1000); */
return ;
// /* this.wrapMtpCall('ping_delay_disconnect', {
}
// ping_id: randomLong(),
// disconnect_delay: this.disconnectDelay
const startTime = Date . now ( ) ;
// }, {
this . log ( 'sendPing: ping' , startTime ) ;
// noResponse: true,
const promise = this . pingPromise = this . wrapMtpCall ( 'ping' , {
// notContentRelated: true
ping_id : randomLong ( )
// }); */
} , {
// const deferred = this.pingPromise = deferredPromise<void>();
notContentRelated : true
} ) . then ( ( ) = > {
// const timeoutTime = this.disconnectDelay * 1000;
const elapsedTime = Date . now ( ) - startTime ;
this . lastPingTime = elapsedTime / 1000 ;
// /* if(!this.sentPingTimes || true) {
this . log ( 'sendPing: pong' , elapsedTime ) ;
// ++this.sentPingTimes; */
// const startTime = Date.now();
setTimeout ( ( ) = > {
// this.wrapMtpCall('ping', {
if ( this . pingPromise !== promise ) {
// ping_id: randomLong()
return ;
// }, {}).then(pong => {
}
// const elapsedTime = Date.now() - startTime;
// this.log('sendPingDelayDisconnect: response', pong, elapsedTime > timeoutTime);
this . pingPromise = undefined ;
this . sendPing ( ) ;
// if(elapsedTime > timeoutTime) {
} , Math . max ( 0 , PING_INTERVAL - elapsedTime ) ) ;
// deferred.reject();
} ) ;
// } else {
} ; * /
// setTimeout(deferred.resolve, timeoutTime - elapsedTime);
// }
private clearPingDelayDisconnect() {
// }, deferred.reject).finally(() => {
const deferred = this . pingDelayDisconnectDeferred ;
// clearTimeout(rejectTimeout);
this . pingDelayDisconnectDeferred = undefined ;
// //--this.sentPingTimes;
this . lastPingDelayDisconnectId = undefined ;
// });
// //}
if ( deferred ) {
deferred . reject ( ) ;
// const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime);
}
}
// deferred.catch(() => {
// (this.transport as Socket).handleClose();
private sendPingDelayDisconnect = ( ) = > {
// });
// return;
// deferred.finally(() => {
if ( this . pingDelayDisconnectDeferred || ! this . transport || ! this . transport . connected ) return ;
// this.pingPromise = null;
// this.sendPingDelayDisconnect();
/ * i f ( ! t h i s . i s O n l i n e ) {
// });
if ( ( this . transport as TcpObfuscated ) . connected ) {
// };
( this . transport as TcpObfuscated ) . connection . close ( ) ;
}
// private sendPingDelayDisconnect = () => {
// if(this.pingPromise || true) return;
return ;
} * /
// /* if(!this.isOnline) {
// if((this.transport as TcpObfuscated).connected) {
const deferred = this . pingDelayDisconnectDeferred = deferredPromise ( ) ;
// (this.transport as TcpObfuscated).connection.close();
const delays = this . delays ;
// }
const pingMaxTime = this . delays . pingMaxTime ;
const lastPingTime = Math . min ( this . lastPingTime ? ? 0 , pingMaxTime ) ;
// return;
const disconnectDelay = Math . round ( delays . disconnectDelayMin + lastPingTime / pingMaxTime * ( delays . disconnectDelayMax - delays . disconnectDelayMin ) ) ;
// } */
const timeoutTime = disconnectDelay * 1000 ;
const startTime = Date . now ( ) ;
// const deferred = this.pingPromise = deferredPromise<void>();
const pingId = this . lastPingDelayDisconnectId = randomLong ( ) ;
const options : MTMessageOptions = { notContentRelated : true } ;
// const timeoutTime = this.disconnectDelay * 1000;
this . wrapMtpCall ( 'ping_delay_disconnect' , {
ping_id : pingId ,
// const startTime = Date.now();
disconnect_delay : disconnectDelay
// this.wrapMtpCall('ping_delay_disconnect', {
} , options ) ;
// ping_id: randomLong(),
// disconnect_delay: this.disconnectDelay
this . log ( ` sendPingDelayDisconnect: ping, timeout= ${ timeoutTime } , lastPingTime= ${ this . lastPingTime } , msgId= ${ options . messageId } ` ) ;
// }, {}).then(pong => {
const rejectTimeout = self . setTimeout ( deferred . reject , timeoutTime ) ;
// const elapsedTime = Date.now() - startTime;
// this.log('sendPingDelayDisconnect: response', pong, elapsedTime > timeoutTime);
const onResolved = ( reason : string ) = > {
clearTimeout ( rejectTimeout ) ;
// if(elapsedTime > timeoutTime) {
const elapsedTime = Date . now ( ) - startTime ;
// deferred.reject();
this . lastPingTime = elapsedTime / 1000 ;
// } else {
this . log ( ` sendPingDelayDisconnect: pong, reason=' ${ reason } ', time= ${ lastPingTime } , msgId= ${ options . messageId } ` ) ;
// setTimeout(deferred.resolve, timeoutTime - elapsedTime);
if ( elapsedTime > timeoutTime ) {
// }
throw undefined ;
// }, deferred.reject).finally(() => {
} else {
// clearTimeout(rejectTimeout);
return pause ( Math . max ( 0 , this . delays . pingInterval - elapsedTime /* timeoutTime - elapsedTime - PING_INTERVAL */ ) ) ;
// //--this.sentPingTimes;
}
// });
} ;
// const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime);
const onTimeout = ( ) = > {
clearTimeout ( rejectTimeout ) ;
// deferred.catch(() => {
const transport = this . transport as TcpObfuscated ;
// this.log.error('sendPingDelayDisconnect: catch, closing connection if exists');
if ( this . pingDelayDisconnectDeferred !== deferred || ! transport ? . connection ) {
// (this.transport as TcpObfuscated).connection.close();
return ;
// });
}
// deferred.finally(() => {
this . log . error ( 'sendPingDelayDisconnect: catch, closing connection' , this . lastPingTime , options . messageId ) ;
// this.pingPromise = null;
transport . connection . close ( ) ;
// this.sendPingDelayDisconnect();
} ;
// });
// };
const onFinally = ( ) = > {
if ( this . pingDelayDisconnectDeferred !== deferred ) {
return ;
}
this . pingDelayDisconnectDeferred = undefined ;
this . sendPingDelayDisconnect ( ) ;
} ;
deferred
. then ( onResolved )
. catch ( onTimeout )
. finally ( onFinally ) ;
} ;
/// #if MTPROTO_HAS_HTTP
/// #if MTPROTO_HAS_HTTP
private checkLongPoll = ( ) = > {
private checkLongPoll = ( ) = > {
@ -581,6 +647,7 @@ export default class MTPNetworker {
max_wait : maxWait
max_wait : maxWait
} , {
} , {
noResponse : true ,
noResponse : true ,
// notContentRelated: true,
longPoll : true
longPoll : true
} ) . then ( ( ) = > {
} ) . then ( ( ) = > {
this . longPollPending = undefined ;
this . longPollPending = undefined ;
@ -701,10 +768,12 @@ export default class MTPNetworker {
return false ;
return false ;
} ) . then ( ( shouldResolve ) = > {
} ) . then ( ( shouldResolve ) = > {
// clearTimeout(timeout);
// clearTimeout(timeout);
const sentMessages = this . sentMessages ;
noResponseMsgs . forEach ( ( msgId ) = > {
noResponseMsgs . forEach ( ( msgId ) = > {
if ( this . sentMessages [ msgId ] ) {
const sentMessage = sentMessages [ msgId ] ;
const deferred = this . sentMessages [ msgId ] . deferred ;
if ( sentMessage ) {
delete this . sentMessages [ msgId ] ;
const deferred = sentMessage . deferred ;
delete sentMessages [ msgId ] ;
delete this . pendingMessages [ msgId ] ;
delete this . pendingMessages [ msgId ] ;
shouldResolve ? deferred . resolve ( ) : deferred . reject ( ) ;
shouldResolve ? deferred . resolve ( ) : deferred . reject ( ) ;
}
}
@ -720,30 +789,33 @@ export default class MTPNetworker {
body : Uint8Array | number [ ] ,
body : Uint8Array | number [ ] ,
isAPI? : boolean
isAPI? : boolean
} , options : MTMessageOptions ) {
} , options : MTMessageOptions ) {
const promise = new Promise ( ( resolve , reject ) = > {
let promise : CancellablePromise < void > ;
this . sentMessages [ message . msg_id ] = Object . assign ( message , options , options . notContentRelated
if ( ! options . notContentRelated || options . noResponse ) {
? undefined
promise = deferredPromise ( ) ;
: {
}
deferred : { resolve , reject }
}
this . sentMessages [ message . msg_id ] = Object . assign (
) ;
message ,
options ,
promise ? { deferred : promise } : undefined
) ;
//this.log.error('Networker pushMessage:', this.sentMessages[message.msg_id]);
//this.log.error('Networker pushMessage:', this.sentMessages[message.msg_id]);
this . pendingMessages [ message . msg_id ] = 0 ;
this . pendingMessages [ message . msg_id ] = 0 ;
if ( ! options . noSchedule ) {
if ( ! options . noSchedule ) {
this . scheduleRequest ( ) ;
this . scheduleRequest ( ) ;
}
}
if ( isObject ( options ) ) {
if ( isObject ( options ) ) {
options . messageId = message . msg_id ;
options . messageId = message . msg_id ;
}
}
} ) ;
if ( ! options . notContentRelated && ! options . noResponse ) {
if ( promise ) {
const canIncrement = ! options . notContentRelated ;
const timeout = setTimeout ( ( ) = > {
const timeout = setTimeout ( ( ) = > {
if ( this . lastResponseTime && ( Date . now ( ) - this . lastResponseTime ) < CONNECTION_TIMEOUT ) {
if ( this . lastResponseTime && ( Date . now ( ) - this . lastResponseTime ) < this . delays . connectionTimeout ) {
return ;
return ;
}
}
@ -755,20 +827,24 @@ export default class MTPNetworker {
/ * t h i s . g e t E n c r y p t e d O u t p u t ( m e s s a g e ) . t h e n ( b y t e s = > {
/ * t h i s . g e t E n c r y p t e d O u t p u t ( m e s s a g e ) . t h e n ( b y t e s = > {
this . log . error ( 'timeout encrypted' , bytes ) ;
this . log . error ( 'timeout encrypted' , bytes ) ;
} ) ; * /
} ) ; * /
} , CONNECTION_TIMEOUT ) ;
} , this . delays . connectionTimeout ) ;
promise . catch ( noop ) . finally ( ( ) = > {
promise . catch ( noop ) . finally ( ( ) = > {
clearTimeout ( timeout ) ;
clearTimeout ( timeout ) ;
this . setConnectionStatus ( ConnectionStatus . Connected ) ;
this . setConnectionStatus ( ConnectionStatus . Connected ) ;
-- this . activeRequests ;
if ( canIncrement ) {
this . setDrainTimeout ( ) ;
-- this . activeRequests ;
this . setDrainTimeout ( ) ;
}
} ) ;
} ) ;
++ this . activeRequests ;
if ( canIncrement ) {
if ( this . onDrainTimeout !== undefined ) {
++ this . activeRequests ;
clearTimeout ( this . onDrainTimeout ) ;
if ( this . onDrainTimeout !== undefined ) {
this . onDrainTimeout = undefined ;
clearTimeout ( this . onDrainTimeout ) ;
this . onDrainTimeout = undefined ;
}
}
}
}
}
@ -809,11 +885,10 @@ export default class MTPNetworker {
this . scheduleRequest ( ) ;
this . scheduleRequest ( ) ;
}
}
// if((this.transport as TcpObfuscated).networker) {
if ( ( this . transport as TcpObfuscated ) . connection ) {
// this.sendPingDelayDisconnect();
this . clearPingDelayDisconnect ( ) ;
// }
this . sendPingDelayDisconnect ( ) ;
/ * t h i s . s e n t P i n g T i m e s = 0 ;
}
this . sendPingDelayDisconnect ( ) ; * /
}
}
/ * i f ( t h i s . o n C o n n e c t i o n S t a t u s C h a n g e ) {
/ * i f ( t h i s . o n C o n n e c t i o n S t a t u s C h a n g e ) {
this . onConnectionStatusChange ( this . isOnline ) ;
this . onConnectionStatusChange ( this . isOnline ) ;
@ -890,8 +965,6 @@ export default class MTPNetworker {
}
}
private performScheduledRequest() {
private performScheduledRequest() {
// this.log('scheduled', this.dcId, this.iii)
if ( this . isStopped ( ) ) {
if ( this . isStopped ( ) ) {
return false ;
return false ;
}
}
@ -909,27 +982,42 @@ export default class MTPNetworker {
} ) ;
} ) ;
}
}
if ( this . pendingResends . length ) {
const pendingResendReqLength = this . pendingResendReq . length ;
const resendMsgIds = this . pendingResends . slice ( ) ;
if ( pendingResendReqLength ) {
const resendOpts : MTMessageOptions = {
const options : MTMessageOptions = { . . . RESEND_OPTIONS } ;
noSchedule : true ,
const msgIds = this . pendingResendReq . splice ( 0 , pendingResendReqLength ) ;
notContentRelated : true ,
messageId : '' // will set in wrapMtpMessage->pushMessage
} ;
//this.log('resendReq messages', resendMsgIds);
this . wrapMtpMessage ( {
this . wrapMtpMessage ( {
_ : 'msg_resend_req' ,
_ : 'msg_resend_req' ,
msg_ids : resendMsgIds
msg_ids : msgIds
} , resendOpts ) ;
} , options ) ;
this . log ( 'resend: resending requests' , options . messageId , msgIds ) ;
/ * t h i s . l a s t R e s e n d R e q = {
reqMsgId : options.messageId ,
msgIds : msgIds
} ; * /
this . lastResendReq = {
// this.pendingResendReq.length = 0;
req_msg_id : resendOpts.messageId ,
resend_msg_ids : resendMsgIds
} ;
}
}
// if(this.pendingResendAnsReq.length) {
// const options: MTMessageOptions = {...RESEND_OPTIONS};
// const msgIds = this.pendingResendAnsReq.slice();
// this.wrapMtpMessage({
// _: 'msg_resend_ans_req',
// msg_ids: msgIds
// }, options);
// this.log('resend: requesting answers', options.messageId, msgIds);
// this.lastResendAnsReq = {
// reqMsgId: options.messageId,
// msgIds: msgIds
// };
// // this.pendingResendAnsReq.length = 0;
// }
let outMessage : MTPNetworker [ 'sentMessages' ] [ keyof MTPNetworker [ 'sentMessages' ] ] ;
let outMessage : MTMessage ;
const messages : typeof outMessage [ ] = [ ] ;
const messages : typeof outMessage [ ] = [ ] ;
//const currentTime = Date.now();
//const currentTime = Date.now();
@ -1197,45 +1285,45 @@ export default class MTPNetworker {
} ) ;
} ) ;
}
}
private sendEncryptedRequest ( message : MTMessage ) {
private async sendEncryptedRequest ( message : MTMessage ) {
return this . getEncryptedOutput ( message ) . then ( requestData = > {
const requestData = await this . getEncryptedOutput ( message ) ;
this . debug && this . log . debug ( 'sendEncryptedRequest: launching message into space:' , message , [ message . msg_id ] . concat ( message . inner || [ ] ) , requestData . length ) ;
const promise : Promise < Uint8Array > = this . transport . send ( requestData ) as any ;
this . debug && this . log . debug ( 'sending:' , message , [ message . msg_id ] . concat ( message . inner || [ ] ) , requestData . length ) ;
// this.debug && this.log.debug('sendEncryptedRequest: launched message into space:', message, promise);
const promise : Promise < Uint8Array > = this . transport . send ( requestData ) as any ;
// this.debug && this.log.debug('sendEncryptedRequest: launched message into space:', message, promise);
/// #if !MTPROTO_HAS_HTTP
return promise ;
/// #if !MTPROTO_HAS_HTTP
/// #else
return promise ;
/// #else
/// #if MTPROTO_HAS_WS
if ( ! ( this . transport instanceof HTTP ) ) return promise ;
/// #if MTPROTO_HAS_WS
/// #endif
if ( ! ( this . transport instanceof HTTP ) ) return promise ;
/// #endif
const baseError = {
code : 406 ,
const baseError = {
type : 'NETWORK_BAD_RESPONSE' ,
code : 406 ,
transport : this.transport
type : 'NETWORK_BAD_RESPONSE' ,
} ;
transport : this.transport
} ;
return promise . then ( ( result ) = > {
if ( ! result ? . byteLength ) {
throw baseError ;
}
return promise . then ( ( result ) = > {
// this.debug && this.log.debug('sendEncryptedRequest: got response for:', message, [message.msg_id].concat(message.inner || []));
if ( ! result ? . byteLength ) {
return result ;
throw baseError ;
} , ( error ) = > {
}
if ( ! error . message && ! error . type ) {
error = Object . assign ( baseError , {
// this.debug && this.log.debug('sendEncryptedRequest: got response for:', message, [message.msg_id].concat(message.inner || []));
type : 'NETWORK_BAD_REQUEST' ,
return result ;
originalError : error
} , ( error ) = > {
} ) ;
if ( ! error . message && ! error . type ) {
}
error = Object . assign ( baseError , {
type : 'NETWORK_BAD_REQUEST' ,
originalError : error
} ) ;
}
throw error ;
throw error ;
} ) ;
/// #endif
} ) ;
} ) ;
/// #endif
}
}
public parseResponse ( responseBuffer : Uint8Array ) {
public parseResponse ( responseBuffer : Uint8Array ) {
@ -1451,35 +1539,37 @@ export default class MTPNetworker {
this . scheduleRequest ( delay ) ;
this . scheduleRequest ( delay ) ;
}
}
private reqResendMessage ( msgId : MTLong ) {
private reqResend ( msgId : MTLong /* , isAnswer?: boolean */ ) {
if ( this . debug ) {
if ( this . debug ) {
this . log . debug ( 'Req resend' , msgId ) ;
this . log . debug ( 'Req resend' , msgId /* , isAnswer */ ) ;
}
}
this . pendingResends . push ( msgId ) ;
// (isAnswer ? this.pendingResendAnsReq : this.pendingResendReq).push(msgId);
this . pendingResendReq . push ( msgId ) ;
this . scheduleRequest ( 100 ) ;
this . scheduleRequest ( 100 ) ;
}
}
public cleanupSent() {
public cleanupSent() {
let notEmpty = false ;
let notEmpty = false ;
// this.log('clean start', this.dcId/*, this.sentMessages*/)
const sentMessages = this . sentMessages ;
Object . keys ( this . sentMessages ) . forEach ( ( msgId ) = > {
// this.log('clean start', this.dcId/*, sentMessages*/)
const message = this . sentMessages [ msgId ] ;
Object . keys ( sentMessages ) . forEach ( ( msgId ) = > {
const message = sentMessages [ msgId ] ;
// this.log('clean iter', msgID, message)
// this.log('clean iter', msgID, message)
if ( message . notContentRelated && this . pendingMessages [ msgId ] === undefined ) {
if ( message . notContentRelated && this . pendingMessages [ msgId ] === undefined ) {
// this.log('clean notContentRelated', msgID)
// this.log('clean notContentRelated', msgID)
delete this . sentMessages [ msgId ] ;
delete sentMessages [ msgId ] ;
} else if ( message . container ) {
} else if ( message . container ) {
for ( const innerMsgId of message . inner ) {
for ( const innerMsgId of message . inner ) {
if ( this . sentMessages [ innerMsgId ] !== undefined ) {
if ( sentMessages [ innerMsgId ] !== undefined ) {
// this.log('clean failed, found', msgID, message.inner[i], this. sentMessages[message.inner[i]].seq_no)
// this.log('clean failed, found', msgID, message.inner[i], sentMessages[message.inner[i]].seq_no)
notEmpty = true ;
notEmpty = true ;
return ;
return ;
}
}
}
}
// this.log('clean container', msgID)
// this.log('clean container', msgID)
delete this . sentMessages [ msgId ] ;
delete sentMessages [ msgId ] ;
} else {
} else {
notEmpty = true ;
notEmpty = true ;
}
}
@ -1513,12 +1603,18 @@ export default class MTPNetworker {
* TODO : consider about containers resend
* TODO : consider about containers resend
* /
* /
public resend() {
public resend() {
for ( const id in this . sentMessages ) {
const sentMessages = this . sentMessages ;
const msg = this . sentMessages [ id ] ;
for ( const id in sentMessages ) {
const msg = sentMessages [ id ] ;
if ( msg . body || msg . container ) {
if ( msg . body || msg . container ) {
this . pushResend ( id ) ;
this . pushResend ( id ) ;
}
}
}
}
if ( ( this . transport as TcpObfuscated ) . connection ) {
this . clearPingDelayDisconnect ( ) ;
this . sendPingDelayDisconnect ( ) ;
}
}
}
/ * p u b l i c r e q u e s t M e s s a g e S t a t u s ( ) {
/ * p u b l i c r e q u e s t M e s s a g e S t a t u s ( ) {
@ -1555,9 +1651,13 @@ export default class MTPNetworker {
return ;
return ;
}
}
/ * i f ( t h i s . d e b u g ) {
if ( this . debug ) {
this . log ( 'process message' , message , messageId , sessionId ) ;
this . log . debug ( 'process message' , message , messageId ) ;
} * /
}
if ( this . pingDelayDisconnectDeferred ) {
this . pingDelayDisconnectDeferred . resolve ( 'any message' ) ;
}
switch ( message . _ ) {
switch ( message . _ ) {
case 'msg_container' : {
case 'msg_container' : {
@ -1671,28 +1771,41 @@ export default class MTPNetworker {
break ;
break ;
}
}
case 'msg_detailed_info' :
case 'msg_detailed_info' : {
if ( ! this . sentMessages [ message . msg_id ] ) {
const sentMessage = this . sentMessages [ message . msg_id ] ;
if ( ! sentMessage ) {
this . ackMessage ( message . answer_msg_id ) ;
this . ackMessage ( message . answer_msg_id ) ;
break ;
break ;
} / * else if ( sentMessage . acked ) {
this . reqResend ( message . answer_msg_id , true ) ;
}
}
case 'msg_new_detailed_info' :
if ( this . pendingAcks . indexOf ( message . answer_msg_id ) ) {
break ; * /
}
case 'msg_new_detailed_info' : {
if ( this . pendingAcks . indexOf ( message . answer_msg_id ) !== - 1 ) {
break ;
break ;
}
}
this . reqResendMessage ( message . answer_msg_id ) ;
this . reqResend ( message . answer_msg_id ) ;
break ;
break ;
}
case 'msgs_state_info' : {
case 'msgs_state_info' : {
this . ackMessage ( message . answer_msg_id ) ;
this . ackMessage ( message . answer_msg_id ) ;
if ( this . lastResendReq &&
const arr = [
this . lastResendReq . req_msg_id === message . req_msg_id &&
[ this . lastResendReq , this . pendingResendReq ] as const
this . pendingResends . length
// [this.lastResendAnsReq, this.pendingResendAnsReq] as const
) {
] ;
for ( const badMsgId of this . lastResendReq . resend_msg_ids ) {
const pos = this . pendingResends . indexOf ( badMsgId ) ;
for ( const [ lastResend , pendingResend ] of arr ) {
if ( pos !== - 1 ) {
if ( lastResend ? . reqMsgId === message . req_msg_id && pendingResend . length ) {
this . pendingResends . splice ( pos , 1 ) ;
for ( const badMsgId of lastResend . msgIds ) {
const pos = pendingResend . indexOf ( badMsgId ) ;
if ( pos !== - 1 ) {
pendingResend . splice ( pos , 1 ) ;
}
}
}
}
}
}
}
@ -1706,6 +1819,10 @@ export default class MTPNetworker {
const sentMessageId = message . req_msg_id ;
const sentMessageId = message . req_msg_id ;
const sentMessage = this . sentMessages [ sentMessageId ] ;
const sentMessage = this . sentMessages [ sentMessageId ] ;
// if(this.debug) {
// this.log.debug('Rpc response', message.result, sentMessage);
// }
this . processMessageAck ( sentMessageId ) ;
this . processMessageAck ( sentMessageId ) ;
if ( sentMessage ) {
if ( sentMessage ) {
const deferred = sentMessage . deferred ;
const deferred = sentMessage . deferred ;
@ -1717,16 +1834,11 @@ export default class MTPNetworker {
}
}
} else {
} else {
if ( deferred ) {
if ( deferred ) {
/ * i f ( D E B U G ) {
this . log . debug ( 'Rpc response' , message . result , sentMessage ) ;
} * /
deferred . resolve ( message . result ) ;
deferred . resolve ( message . result ) ;
}
}
if ( sentMessage . isAPI && ! this . connectionInited ) {
if ( sentMessage . isAPI && ! this . connectionInited ) {
this . connectionInited = true ;
this . connectionInited = true ;
////this.log('Rpc set connectionInited to:', this.connectionInited);
}
}
}
}
@ -1741,12 +1853,16 @@ export default class MTPNetworker {
}
}
case 'pong' : { // * https://core.telegram.org/mtproto/service_messages#ping-messages-pingpong - These messages don't require acknowledgments
case 'pong' : { // * https://core.telegram.org/mtproto/service_messages#ping-messages-pingpong - These messages don't require acknowledgments
const sentMessageId = message . msg_id ;
/ * c o n s t s e n t M e s s a g e I d = m e s s a g e . m s g _ i d ;
const sentMessage = this . sentMessages [ sentMessageId ] ;
const sentMessage = this . sentMessages [ sentMessageId ] ;
if ( sentMessage ) {
if ( sentMessage ) {
sentMessage . deferred . resolve ( message ) ;
sentMessage . deferred . resolve ( message ) ;
delete this . sentMessages [ sentMessageId ] ;
delete this . sentMessages [ sentMessageId ] ;
} * /
const pingId = message . ping_id ;
if ( this . lastPingDelayDisconnectId === pingId ) {
this . pingDelayDisconnectDeferred . resolve ( 'pong' ) ;
}
}
break ;
break ;