fix: improved ping handling

This commit is contained in:
alina 🌸 2024-09-24 22:26:17 +03:00
parent 677c534fb2
commit 26d068eeb2
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
3 changed files with 23 additions and 7 deletions

View file

@ -167,7 +167,6 @@ export class MtprotoSession {
timers.clearTimeout(this.current429Timeout) timers.clearTimeout(this.current429Timeout)
this.resetState(withAuthKey) this.resetState(withAuthKey)
this.resetLastPing(true)
} }
resetAuthKey(): void { resetAuthKey(): void {
@ -231,6 +230,7 @@ export class MtprotoSession {
this.getStateSchedule.clear() this.getStateSchedule.clear()
this.chains.clear() this.chains.clear()
this.chainsPendingFails.clear() this.chainsPendingFails.clear()
this.resetLastPing(true)
} }
enqueueRpc(rpc: PendingRpc, force?: boolean): boolean { enqueueRpc(rpc: PendingRpc, force?: boolean): boolean {

View file

@ -108,6 +108,13 @@ export interface NetworkManagerExtraParams {
* > If you need to handle incoming updates, use a {@link Dispatcher} instead. * > If you need to handle incoming updates, use a {@link Dispatcher} instead.
*/ */
middlewares?: Middleware<RpcCallMiddlewareContext, unknown>[] middlewares?: Middleware<RpcCallMiddlewareContext, unknown>[]
/**
* Ping interval in milliseconds.
*
* @default 60000 (1 minute)
*/
pingInterval?: number
} }
/** Options that can be customized when making an RPC call */ /** Options that can be customized when making an RPC call */
@ -255,6 +262,7 @@ export class DcConnectionManager {
enableErrorReporting: this.manager.params.enableErrorReporting, enableErrorReporting: this.manager.params.enableErrorReporting,
salts: this._salts, salts: this._salts,
platform: this.manager.params.platform, platform: this.manager.params.platform,
pingInterval: this.manager.params.pingInterval ?? 60_000,
}) })
const mainParams = baseConnectionParams() const mainParams = baseConnectionParams()

View file

@ -27,6 +27,7 @@ import { TransportError } from './transports/abstract.js'
export interface SessionConnectionParams extends PersistentConnectionParams { export interface SessionConnectionParams extends PersistentConnectionParams {
initConnection: tl.RawInitConnectionRequest initConnection: tl.RawInitConnectionRequest
inactivityTimeout?: number inactivityTimeout?: number
pingInterval: number
enableErrorReporting: boolean enableErrorReporting: boolean
layer: number layer: number
disableUpdates?: boolean disableUpdates?: boolean
@ -43,7 +44,6 @@ export interface SessionConnectionParams extends PersistentConnectionParams {
} }
const TEMP_AUTH_KEY_EXPIRY = 86400 // 24 hours const TEMP_AUTH_KEY_EXPIRY = 86400 // 24 hours
const PING_INTERVAL = 60000 // 1 minute
const GET_STATE_INTERVAL = 1500 // 1.5 seconds const GET_STATE_INTERVAL = 1500 // 1.5 seconds
// destroy_auth_key#d1435160 = DestroyAuthKeyRes; // destroy_auth_key#d1435160 = DestroyAuthKeyRes;
@ -84,6 +84,10 @@ export class SessionConnection extends PersistentConnection {
private _crypto: ICryptoProvider private _crypto: ICryptoProvider
private _salts: ServerSaltManager private _salts: ServerSaltManager
// todo: we should probably do adaptive ping interval based on rtt like tdlib:
// https://github.com/tdlib/td/blob/91aa6c9e4d0774eabf4f8d7f3aa51239032059a6/td/mtproto/SessionConnection.h
private _pingInterval: number
constructor( constructor(
params: SessionConnectionParams, params: SessionConnectionParams,
readonly _session: MtprotoSession, readonly _session: MtprotoSession,
@ -91,6 +95,8 @@ export class SessionConnection extends PersistentConnection {
super(params, _session.log.create('conn')) super(params, _session.log.create('conn'))
this._flushTimer.onTimeout(this._flush.bind(this)) this._flushTimer.onTimeout(this._flush.bind(this))
this._pingInterval = params.pingInterval
this._readerMap = params.readerMap this._readerMap = params.readerMap
this._writerMap = params.writerMap this._writerMap = params.writerMap
this._crypto = params.crypto this._crypto = params.crypto
@ -1564,7 +1570,7 @@ export class SessionConnection extends PersistentConnection {
// between multiple connections using the same session // between multiple connections using the same session
this._flushTimer.emitWhenIdle() this._flushTimer.emitWhenIdle()
} else { } else {
const nextPingTime = this._session.lastPingTime + PING_INTERVAL const nextPingTime = this._session.lastPingTime + this._pingInterval
const nextGetScheduleTime = this._session.getStateSchedule.raw[0]?.getState || Infinity const nextGetScheduleTime = this._session.getStateSchedule.raw[0]?.getState || Infinity
this._flushTimer.emitBefore(Math.min(nextPingTime, nextGetScheduleTime)) this._flushTimer.emitBefore(Math.min(nextPingTime, nextGetScheduleTime))
@ -1629,17 +1635,19 @@ export class SessionConnection extends PersistentConnection {
messageCount += 1 messageCount += 1
} }
if (now - this._session.lastPingTime > PING_INTERVAL) { if (now - this._session.lastPingTime > this._pingInterval) {
if (!this._session.lastPingMsgId.isZero()) { if (!this._session.lastPingMsgId.isZero()) {
this.log.warn("didn't receive pong for previous ping (msg_id = %l)", this._session.lastPingMsgId) this.log.warn("didn't receive pong for previous ping (msg_id = %l). are we offline?", this._session.lastPingMsgId)
this._session.pendingMessages.delete(this._session.lastPingMsgId) this._resetSession()
return
} }
pingId = randomLong() pingId = randomLong()
const obj: mtp.RawMt_ping_delay_disconnect = { const obj: mtp.RawMt_ping_delay_disconnect = {
_: 'mt_ping_delay_disconnect', _: 'mt_ping_delay_disconnect',
pingId, pingId,
disconnectDelay: 75, // ÷ 1000 * 1.25
disconnectDelay: Math.round(this._pingInterval * 0.00125),
} }
this._session.lastPingTime = Date.now() this._session.lastPingTime = Date.now()