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

May help with #1564.
This commit is contained in:
Lonami Exo 2020-12-11 17:18:25 +01:00
parent 0a4d54fca4
commit becfe2ce7a
2 changed files with 21 additions and 4 deletions

View File

@ -348,7 +348,7 @@ class UpdateMethods:
# We also don't really care about their result. # We also don't really care about their result.
# Just send them periodically. # Just send them periodically.
try: try:
self._sender.send(functions.PingRequest(rnd())) self._sender._keepalive_ping(rnd())
except (ConnectionError, asyncio.CancelledError): except (ConnectionError, asyncio.CancelledError):
return return
@ -399,7 +399,7 @@ class UpdateMethods:
pass pass
except ValueError: except ValueError:
# There is a chance that GetFullChannelRequest and GetDifferenceRequest # 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. # ValueError("Request was unsuccessful N time(s)") for whatever reasons.
pass pass

View File

@ -16,6 +16,7 @@ from ..errors import (
from ..extensions import BinaryReader from ..extensions import BinaryReader
from ..tl.core import RpcResult, MessageContainer, GzipPacked from ..tl.core import RpcResult, MessageContainer, GzipPacked
from ..tl.functions.auth import LogOutRequest from ..tl.functions.auth import LogOutRequest
from ..tl.functions import PingRequest
from ..tl.types import ( from ..tl.types import (
MsgsAck, Pong, BadServerSalt, BadMsgNotification, FutureSalts, MsgsAck, Pong, BadServerSalt, BadMsgNotification, FutureSalts,
MsgNewDetailedInfo, NewSessionCreated, MsgDetailedInfo, MsgsStateReq, MsgNewDetailedInfo, NewSessionCreated, MsgDetailedInfo, MsgsStateReq,
@ -55,6 +56,7 @@ class MTProtoSender:
self._update_callback = update_callback self._update_callback = update_callback
self._auto_reconnect_callback = auto_reconnect_callback self._auto_reconnect_callback = auto_reconnect_callback
self._connect_lock = asyncio.Lock() self._connect_lock = asyncio.Lock()
self._ping = None
# Whether the user has explicitly connected or disconnected. # Whether the user has explicitly connected or disconnected.
# #
@ -217,7 +219,7 @@ class MTProtoSender:
self._log.info('Connecting to %s...', self._connection) self._log.info('Connecting to %s...', self._connection)
connected = False connected = False
for attempt in retry_range(self._retries): for attempt in retry_range(self._retries):
if not connected: if not connected:
connected = await self._try_connect(attempt) connected = await self._try_connect(attempt)
@ -358,7 +360,7 @@ class MTProtoSender:
self._state.reset() self._state.reset()
retries = self._retries if self._auto_reconnect else 0 retries = self._retries if self._auto_reconnect else 0
attempt = 0 attempt = 0
ok = True ok = True
# We're already "retrying" to connect, so we don't want to force retries # We're already "retrying" to connect, so we don't want to force retries
@ -419,6 +421,18 @@ class MTProtoSender:
self._reconnecting = True self._reconnecting = True
asyncio.get_event_loop().create_task(self._reconnect(error)) 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 # Loops
async def _send_loop(self): async def _send_loop(self):
@ -641,6 +655,9 @@ class MTProtoSender:
""" """
pong = message.obj pong = message.obj
self._log.debug('Handling pong for message %d', pong.msg_id) 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) state = self._pending_state.pop(pong.msg_id, None)
if state: if state:
state.future.set_result(pong) state.future.set_result(pong)