Browse Source

Network:

Fix reconnecting
Fix resending answers
Try ping_disconnect_delay again
master
Eduard Kuzmenko 3 years ago
parent
commit
fa4df7ee4b
  1. 4
      src/lib/mtproto/apiManager.ts
  2. 614
      src/lib/mtproto/networker.ts

4
src/lib/mtproto/apiManager.ts

@ -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) {

614
src/lib/mtproto/networker.ts

@ -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 = () => { /* private clearPing() {
// 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(); /* if(!this.isOnline) {
// }); 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 {
/* 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);
--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();
/* 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.log('resend: resending requests', options.messageId, msgIds);
/* this.lastResendReq = {
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();
}
} }
/* 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(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) {
/* 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…
Cancel
Save