implement client-to-server read timeout PINGs

This commit is contained in:
jesopo 2020-04-26 15:07:05 +01:00
parent f33a0ad369
commit ba57d06a56
3 changed files with 22 additions and 1 deletions

View file

@ -76,6 +76,7 @@ class IServer(Server):
disconnected: bool disconnected: bool
params: ConnectionParams params: ConnectionParams
desired_caps: Set[ICapability] desired_caps: Set[ICapability]
last_read: float
def send_raw(self, line: str, priority=SendPriority.DEFAULT def send_raw(self, line: str, priority=SendPriority.DEFAULT
) -> Awaitable[SentLine]: ) -> Awaitable[SentLine]:

View file

@ -2,8 +2,10 @@ import asyncio
from asyncio import Future, PriorityQueue from asyncio import Future, PriorityQueue
from typing import Awaitable, Deque, Dict, List, Optional, Set, Tuple from typing import Awaitable, Deque, Dict, List, Optional, Set, Tuple
from collections import deque from collections import deque
from time import monotonic
from asyncio_throttle import Throttler from asyncio_throttle import Throttler
from async_timeout import timeout
from ircstates import Emit, Channel from ircstates import Emit, Channel
from ircstates.numerics import * from ircstates.numerics import *
from ircstates.server import ServerDisconnectedException from ircstates.server import ServerDisconnectedException
@ -23,6 +25,7 @@ from .interface import ITCPTransport, ITCPReader, ITCPWriter
THROTTLE_RATE = 4 # lines THROTTLE_RATE = 4 # lines
THROTTLE_TIME = 2 # seconds THROTTLE_TIME = 2 # seconds
PING_TIMEOUT = 60 # seconds
class Server(IServer): class Server(IServer):
_reader: ITCPReader _reader: ITCPReader
@ -39,6 +42,8 @@ class Server(IServer):
rate_limit=100, period=THROTTLE_TIME) rate_limit=100, period=THROTTLE_TIME)
self.sasl_state = SASLResult.NONE self.sasl_state = SASLResult.NONE
self.last_read = -1.0
self._ping_sent = False
self._sent_count: int = 0 self._sent_count: int = 0
self._write_queue: PriorityQueue[SentLine] = PriorityQueue() self._write_queue: PriorityQueue[SentLine] = PriorityQueue()
@ -174,7 +179,21 @@ class Server(IServer):
both = self._read_queue.popleft() both = self._read_queue.popleft()
else: else:
while True: while True:
data = await self._reader.read(1024)
try:
async with timeout(PING_TIMEOUT):
data = await self._reader.read(1024)
except asyncio.exceptions.TimeoutError:
if self._ping_sent:
data = b"" # empty data means the socket disconnected
else:
self._ping_sent = True
await self.send(build("PING", ["hello"]))
continue
self.last_read = monotonic()
self._ping_sent = False
try: try:
lines = self.recv(data) lines = self.recv(data)
except ServerDisconnectedException: except ServerDisconnectedException:

View file

@ -3,3 +3,4 @@ asyncio-throttle ==1.0.1
dataclasses ==0.6 dataclasses ==0.6
ircstates ==0.9.6 ircstates ==0.9.6
async_stagger ==0.3.0 async_stagger ==0.3.0
async_timeout ==3.0.1