Skip to content
Permalink
Browse files

Start reconnect if a second ping is sent without a pong for the first

May help with #1564.
  • Loading branch information
Lonami committed Dec 11, 2020
1 parent 0a4d54f commit becfe2ce7a713fc90435c22197de8eab81f508e4
Showing with 21 additions and 4 deletions.
  1. +2 −2 telethon/client/updates.py
  2. +19 −2 telethon/network/mtprotosender.py
@@ -348,7 +348,7 @@ async def _update_loop(self: 'TelegramClient'):
# We also don't really care about their result.
# Just send them periodically.
try:
self._sender.send(functions.PingRequest(rnd()))
self._sender._keepalive_ping(rnd())
except (ConnectionError, asyncio.CancelledError):
return

@@ -399,7 +399,7 @@ async def _dispatch_update(self: 'TelegramClient', update, others, channel_id, p
pass
except ValueError:
# There is a chance that GetFullChannelRequest and GetDifferenceRequest
# inside the _get_difference() function will end up with
# inside the _get_difference() function will end up with
# ValueError("Request was unsuccessful N time(s)") for whatever reasons.
pass

@@ -16,6 +16,7 @@
from ..extensions import BinaryReader
from ..tl.core import RpcResult, MessageContainer, GzipPacked
from ..tl.functions.auth import LogOutRequest
from ..tl.functions import PingRequest
from ..tl.types import (
MsgsAck, Pong, BadServerSalt, BadMsgNotification, FutureSalts,
MsgNewDetailedInfo, NewSessionCreated, MsgDetailedInfo, MsgsStateReq,
@@ -55,6 +56,7 @@ def __init__(self, auth_key, *, loggers,
self._update_callback = update_callback
self._auto_reconnect_callback = auto_reconnect_callback
self._connect_lock = asyncio.Lock()
self._ping = None

# Whether the user has explicitly connected or disconnected.
#
@@ -217,7 +219,7 @@ async def _connect(self):
self._log.info('Connecting to %s...', self._connection)

connected = False

for attempt in retry_range(self._retries):
if not connected:
connected = await self._try_connect(attempt)
@@ -358,7 +360,7 @@ async def _reconnect(self, last_error):
self._state.reset()

retries = self._retries if self._auto_reconnect else 0

attempt = 0
ok = True
# We're already "retrying" to connect, so we don't want to force retries
@@ -419,6 +421,18 @@ def _start_reconnect(self, error):
self._reconnecting = True
asyncio.get_event_loop().create_task(self._reconnect(error))

def _keepalive_ping(self, rnd_id):
"""
Send a keep-alive ping. If a pong for the last ping was not received
yet, this means we're probably not connected.
"""
# TODO this is ugly, update loop shouldn't worry about this, sender should
if self._ping is None:
self._ping = rnd_id
self.send(PingRequest(rnd_id))
else:
self._start_reconnect(None)

# Loops

async def _send_loop(self):
@@ -641,6 +655,9 @@ async def _handle_pong(self, message):
"""
pong = message.obj
self._log.debug('Handling pong for message %d', pong.msg_id)
if self._ping == pong.ping_id:
self._ping = None

state = self._pending_state.pop(pong.msg_id, None)
if state:
state.future.set_result(pong)

0 comments on commit becfe2c

Please sign in to comment.