Network:
Fix reconnecting Fix resending answers Try ping_disconnect_delay again
This commit is contained in:
parent
4350adcfed
commit
fa4df7ee4b
@ -76,6 +76,8 @@ export type ApiError = Partial<{
|
|||||||
}
|
}
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
const FILE_NETWORKERS_COUNT = 3;
|
||||||
|
|
||||||
export class ApiManager {
|
export class ApiManager {
|
||||||
private cachedNetworkers: {
|
private cachedNetworkers: {
|
||||||
[transportType in TransportType]: {
|
[transportType in TransportType]: {
|
||||||
@ -321,7 +323,7 @@ export class ApiManager {
|
|||||||
|
|
||||||
const networkers = cache[dcId];
|
const networkers = cache[dcId];
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const maxNetworkers = connectionType === 'client' || transportType === 'https' ? 1 : (connectionType === 'download' ? 3 : 3);
|
const maxNetworkers = connectionType === 'client' || transportType === 'https' ? 1 : FILE_NETWORKERS_COUNT;
|
||||||
if(networkers.length >= maxNetworkers) {
|
if(networkers.length >= maxNetworkers) {
|
||||||
let i = networkers.length - 1, found = false;
|
let i = networkers.length - 1, found = false;
|
||||||
for(; i >= 0; --i) {
|
for(; i >= 0; --i) {
|
||||||
|
@ -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,10 +451,20 @@ export default class MTPNetworker {
|
|||||||
/// #endif
|
/// #endif
|
||||||
/// #endif
|
/// #endif
|
||||||
|
|
||||||
if(transport.connected && (transport as TcpObfuscated).connection) {
|
/// #if MTPROTO_HAS_WS
|
||||||
|
// * handle outcoming dead socket, server will close the connection
|
||||||
|
if((transport as TcpObfuscated).connection) {
|
||||||
|
// this.sendPingDelayDisconnect();
|
||||||
|
|
||||||
|
if(transport.connected) {
|
||||||
this.setConnectionStatus(ConnectionStatus.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 = () => {
|
/* private clearPing() {
|
||||||
// if(this.pingPromise || true) return;
|
if(this.pingPromise) {
|
||||||
|
this.pingPromise = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// if(!this.isOnline) {
|
this.lastPingTime = undefined;
|
||||||
// if((this.transport as TcpObfuscated).connected) {
|
}
|
||||||
// (this.transport as TcpObfuscated).handleClose();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
private sendPing = () => {
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// if(!(this.transport as TcpObfuscated).connected) {
|
||||||
|
// this.clearPing();
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// this.log('sendPingDelayDisconnect', this.sentPingTimes);
|
if(this.pingPromise) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// /* if(this.tt) clearTimeout(this.tt);
|
const startTime = Date.now();
|
||||||
// this.tt = self.setTimeout(() => {
|
this.log('sendPing: ping', startTime);
|
||||||
// (this.transport as any).ws.close(1000);
|
const promise = this.pingPromise = this.wrapMtpCall('ping', {
|
||||||
// this.tt = 0;
|
ping_id: randomLong()
|
||||||
// }, this.disconnectDelay * 1000); */
|
}, {
|
||||||
// /* this.wrapMtpCall('ping_delay_disconnect', {
|
notContentRelated: true
|
||||||
// ping_id: randomLong(),
|
}).then(() => {
|
||||||
// disconnect_delay: this.disconnectDelay
|
const elapsedTime = Date.now() - startTime;
|
||||||
// }, {
|
this.lastPingTime = elapsedTime / 1000;
|
||||||
// noResponse: true,
|
this.log('sendPing: pong', elapsedTime);
|
||||||
// notContentRelated: true
|
|
||||||
// }); */
|
|
||||||
// const deferred = this.pingPromise = deferredPromise<void>();
|
|
||||||
|
|
||||||
// const timeoutTime = this.disconnectDelay * 1000;
|
setTimeout(() => {
|
||||||
|
if(this.pingPromise !== promise) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// /* if(!this.sentPingTimes || true) {
|
this.pingPromise = undefined;
|
||||||
// ++this.sentPingTimes; */
|
this.sendPing();
|
||||||
// const startTime = Date.now();
|
}, Math.max(0, PING_INTERVAL - elapsedTime));
|
||||||
// this.wrapMtpCall('ping', {
|
});
|
||||||
// ping_id: randomLong()
|
}; */
|
||||||
// }, {}).then(pong => {
|
|
||||||
// const elapsedTime = Date.now() - startTime;
|
|
||||||
// this.log('sendPingDelayDisconnect: response', pong, elapsedTime > timeoutTime);
|
|
||||||
|
|
||||||
// if(elapsedTime > timeoutTime) {
|
private clearPingDelayDisconnect() {
|
||||||
// deferred.reject();
|
const deferred = this.pingDelayDisconnectDeferred;
|
||||||
// } else {
|
this.pingDelayDisconnectDeferred = undefined;
|
||||||
// setTimeout(deferred.resolve, timeoutTime - elapsedTime);
|
this.lastPingDelayDisconnectId = undefined;
|
||||||
// }
|
|
||||||
// }, deferred.reject).finally(() => {
|
|
||||||
// clearTimeout(rejectTimeout);
|
|
||||||
// //--this.sentPingTimes;
|
|
||||||
// });
|
|
||||||
// //}
|
|
||||||
|
|
||||||
// const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime);
|
if(deferred) {
|
||||||
|
deferred.reject();
|
||||||
// deferred.catch(() => {
|
}
|
||||||
// (this.transport as Socket).handleClose();
|
}
|
||||||
// });
|
|
||||||
|
|
||||||
// deferred.finally(() => {
|
|
||||||
// this.pingPromise = null;
|
|
||||||
// this.sendPingDelayDisconnect();
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// private sendPingDelayDisconnect = () => {
|
|
||||||
// if(this.pingPromise || true) return;
|
|
||||||
|
|
||||||
// /* if(!this.isOnline) {
|
|
||||||
// if((this.transport as TcpObfuscated).connected) {
|
|
||||||
// (this.transport as TcpObfuscated).connection.close();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
private sendPingDelayDisconnect = () => {
|
||||||
// return;
|
// return;
|
||||||
// } */
|
|
||||||
|
|
||||||
// const deferred = this.pingPromise = deferredPromise<void>();
|
if(this.pingDelayDisconnectDeferred || !this.transport || !this.transport.connected) return;
|
||||||
|
|
||||||
// const timeoutTime = this.disconnectDelay * 1000;
|
/* if(!this.isOnline) {
|
||||||
|
if((this.transport as TcpObfuscated).connected) {
|
||||||
|
(this.transport as TcpObfuscated).connection.close();
|
||||||
|
}
|
||||||
|
|
||||||
// const startTime = Date.now();
|
return;
|
||||||
// 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) {
|
const deferred = this.pingDelayDisconnectDeferred = deferredPromise();
|
||||||
// deferred.reject();
|
const delays = this.delays;
|
||||||
// } else {
|
const pingMaxTime = this.delays.pingMaxTime;
|
||||||
// setTimeout(deferred.resolve, timeoutTime - elapsedTime);
|
const lastPingTime = Math.min(this.lastPingTime ?? 0, pingMaxTime);
|
||||||
// }
|
const disconnectDelay = Math.round(delays.disconnectDelayMin + lastPingTime / pingMaxTime * (delays.disconnectDelayMax - delays.disconnectDelayMin));
|
||||||
// }, deferred.reject).finally(() => {
|
const timeoutTime = disconnectDelay * 1000;
|
||||||
// clearTimeout(rejectTimeout);
|
const startTime = Date.now();
|
||||||
// //--this.sentPingTimes;
|
const pingId = this.lastPingDelayDisconnectId = randomLong();
|
||||||
// });
|
const options: MTMessageOptions = {notContentRelated: true};
|
||||||
|
this.wrapMtpCall('ping_delay_disconnect', {
|
||||||
|
ping_id: pingId,
|
||||||
|
disconnect_delay: disconnectDelay
|
||||||
|
}, options);
|
||||||
|
|
||||||
// const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime);
|
this.log(`sendPingDelayDisconnect: ping, timeout=${timeoutTime}, lastPingTime=${this.lastPingTime}, msgId=${options.messageId}`);
|
||||||
|
const rejectTimeout = self.setTimeout(deferred.reject, timeoutTime);
|
||||||
|
|
||||||
// deferred.catch(() => {
|
const onResolved = (reason: string) => {
|
||||||
// this.log.error('sendPingDelayDisconnect: catch, closing connection if exists');
|
clearTimeout(rejectTimeout);
|
||||||
// (this.transport as TcpObfuscated).connection.close();
|
const elapsedTime = Date.now() - startTime;
|
||||||
// });
|
this.lastPingTime = elapsedTime / 1000;
|
||||||
|
this.log(`sendPingDelayDisconnect: pong, reason='${reason}', time=${lastPingTime}, msgId=${options.messageId}`);
|
||||||
|
if(elapsedTime > timeoutTime) {
|
||||||
|
throw undefined;
|
||||||
|
} else {
|
||||||
|
return pause(Math.max(0, this.delays.pingInterval - elapsedTime/* timeoutTime - elapsedTime - PING_INTERVAL */));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// deferred.finally(() => {
|
const onTimeout = () => {
|
||||||
// this.pingPromise = null;
|
clearTimeout(rejectTimeout);
|
||||||
// this.sendPingDelayDisconnect();
|
const transport = this.transport as TcpObfuscated;
|
||||||
// });
|
if(this.pingDelayDisconnectDeferred !== deferred || !transport?.connection) {
|
||||||
// };
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log.error('sendPingDelayDisconnect: catch, closing connection', this.lastPingTime, options.messageId);
|
||||||
|
transport.connection.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
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,12 +789,15 @@ 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]);
|
||||||
@ -739,11 +811,11 @@ export default class MTPNetworker {
|
|||||||
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,22 +827,26 @@ export default class MTPNetworker {
|
|||||||
/* this.getEncryptedOutput(message).then(bytes => {
|
/* this.getEncryptedOutput(message).then(bytes => {
|
||||||
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);
|
||||||
|
|
||||||
|
if(canIncrement) {
|
||||||
--this.activeRequests;
|
--this.activeRequests;
|
||||||
this.setDrainTimeout();
|
this.setDrainTimeout();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(canIncrement) {
|
||||||
++this.activeRequests;
|
++this.activeRequests;
|
||||||
if(this.onDrainTimeout !== undefined) {
|
if(this.onDrainTimeout !== undefined) {
|
||||||
clearTimeout(this.onDrainTimeout);
|
clearTimeout(this.onDrainTimeout);
|
||||||
this.onDrainTimeout = undefined;
|
this.onDrainTimeout = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
@ -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();
|
||||||
/* this.sentPingTimes = 0;
|
}
|
||||||
this.sendPingDelayDisconnect(); */
|
|
||||||
}
|
}
|
||||||
/* if(this.onConnectionStatusChange) {
|
/* if(this.onConnectionStatusChange) {
|
||||||
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.lastResendReq = {
|
this.log('resend: resending requests', options.messageId, msgIds);
|
||||||
req_msg_id: resendOpts.messageId,
|
/* this.lastResendReq = {
|
||||||
resend_msg_ids: resendMsgIds
|
reqMsgId: options.messageId,
|
||||||
};
|
msgIds: msgIds
|
||||||
|
}; */
|
||||||
|
|
||||||
|
// this.pendingResendReq.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let outMessage: MTPNetworker['sentMessages'][keyof MTPNetworker['sentMessages']];
|
// 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: MTMessage;
|
||||||
const messages: typeof outMessage[] = [];
|
const messages: typeof outMessage[] = [];
|
||||||
|
|
||||||
//const currentTime = Date.now();
|
//const currentTime = Date.now();
|
||||||
@ -1197,9 +1285,10 @@ 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);
|
|
||||||
|
this.debug && this.log.debug('sending:', message, [message.msg_id].concat(message.inner || []), requestData.length);
|
||||||
const promise: Promise<Uint8Array> = this.transport.send(requestData) as any;
|
const promise: Promise<Uint8Array> = this.transport.send(requestData) as any;
|
||||||
// this.debug && this.log.debug('sendEncryptedRequest: launched message into space:', message, promise);
|
// this.debug && this.log.debug('sendEncryptedRequest: launched message into space:', message, promise);
|
||||||
|
|
||||||
@ -1235,7 +1324,6 @@ export default class MTPNetworker {
|
|||||||
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public requestMessageStatus() {
|
/* public requestMessageStatus() {
|
||||||
@ -1555,9 +1651,13 @@ export default class MTPNetworker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if(this.debug) {
|
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(lastResend?.reqMsgId === message.req_msg_id && pendingResend.length) {
|
||||||
|
for(const badMsgId of lastResend.msgIds) {
|
||||||
|
const pos = pendingResend.indexOf(badMsgId);
|
||||||
if(pos !== -1) {
|
if(pos !== -1) {
|
||||||
this.pendingResends.splice(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) {
|
||||||
/* if(DEBUG) {
|
|
||||||
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;
|
/* const sentMessageId = message.msg_id;
|
||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user