5
5
from asyncio import new_event_loop , gather , get_event_loop , sleep
6
6
7
7
from . import connection , protocol
8
+ import warnings
8
9
9
10
__all__ = ['Error' , 'AlreadyInChannel' , 'NotInChannel' , 'BasicClient' , 'ClientPool' ]
10
11
DEFAULT_NICKNAME = '<unregistered>'
@@ -32,12 +33,29 @@ class BasicClient:
32
33
Base IRC client class.
33
34
This class on its own is not complete: in order to be able to run properly, _has_message, _parse_message and _create_message have to be overloaded.
34
35
"""
35
- PING_TIMEOUT = 300
36
+ READ_TIMEOUT = 300
36
37
RECONNECT_ON_ERROR = True
37
38
RECONNECT_MAX_ATTEMPTS = 3
38
39
RECONNECT_DELAYED = True
39
40
RECONNECT_DELAYS = [5 , 5 , 10 , 30 , 120 , 600 ]
40
41
42
+ @property
43
+ def PING_TIMEOUT (self ):
44
+ warnings .warn (
45
+ "PING_TIMEOUT has been moved to READ_TIMEOUT and may be removed in a future version. "
46
+ "Please migrate to READ_TIMEOUT." ,
47
+ DeprecationWarning
48
+ )
49
+ return self .READ_TIMEOUT
50
+
51
+ @PING_TIMEOUT .setter
52
+ def PING_TIMEOUT (self , value ):
53
+ warnings .warn (
54
+ "PING_TIMEOUT has been moved to READ_TIMEOUT and may be removed in a future version" ,
55
+ DeprecationWarning
56
+ )
57
+ self .READ_TIMEOUT = value
58
+
41
59
def __init__ (self , nickname , fallback_nicknames = [], username = None , realname = None ,
42
60
eventloop = None , ** kwargs ):
43
61
""" Create a client. """
@@ -66,7 +84,6 @@ def _reset_attributes(self):
66
84
self ._receive_buffer = b''
67
85
self ._pending = {}
68
86
self ._handler_top_level = False
69
- self ._ping_checker_handle = None
70
87
71
88
# Misc.
72
89
self .logger = logging .getLogger (__name__ )
@@ -115,10 +132,6 @@ async def connect(self, hostname=None, port=None, reconnect=False, **kwargs):
115
132
async def disconnect (self , expected = True ):
116
133
""" Disconnect from server. """
117
134
if self .connected :
118
- # Unschedule ping checker.
119
- if self ._ping_checker_handle :
120
- self ._ping_checker_handle .cancel ()
121
-
122
135
# Schedule disconnect.
123
136
await self ._disconnect (expected )
124
137
@@ -159,21 +172,6 @@ def _reconnect_delay(self):
159
172
else :
160
173
return 0
161
174
162
- async def _perform_ping_timeout (self , delay : int ):
163
- """ Handle timeout gracefully.
164
-
165
- Args:
166
- delay (int): delay before raising the timeout (in seconds)
167
- """
168
-
169
- # pause for delay seconds
170
- await sleep (delay )
171
- # then continue
172
- error = TimeoutError (
173
- 'Ping timeout: no data received from server in {timeout} seconds.' .format (
174
- timeout = self .PING_TIMEOUT ))
175
- await self .on_data_error (error )
176
-
177
175
## Internal database management.
178
176
179
177
def _create_channel (self , channel ):
@@ -365,7 +363,18 @@ async def _send(self, input):
365
363
async def handle_forever (self ):
366
364
""" Handle data forever. """
367
365
while self .connected :
368
- data = await self .connection .recv ()
366
+ try :
367
+ data = await self .connection .recv (timeout = self .READ_TIMEOUT )
368
+ except asyncio .TimeoutError :
369
+ self .logger .warning (
370
+ '>> Receive timeout reached, sending ping to check connection state...' )
371
+
372
+ try :
373
+ await self .rawmsg ("PING" , self .server_tag )
374
+ data = await self .connection .recv (timeout = self .READ_TIMEOUT )
375
+ except asyncio .TimeoutError :
376
+ data = None
377
+
369
378
if not data :
370
379
if self .connected :
371
380
await self .disconnect (expected = False )
@@ -378,19 +387,10 @@ async def on_data(self, data):
378
387
""" Handle received data. """
379
388
self ._receive_buffer += data
380
389
381
- # Schedule new timeout event.
382
- if self ._ping_checker_handle :
383
- self ._ping_checker_handle .cancel ()
384
-
385
- # create a task for the ping checker
386
- self ._ping_checker_handle = self .eventloop .create_task (
387
- self ._perform_ping_timeout (self .PING_TIMEOUT ))
388
-
389
390
while self ._has_message ():
390
391
message = self ._parse_message ()
391
392
self .eventloop .create_task (self .on_raw (message ))
392
393
393
-
394
394
async def on_data_error (self , exception ):
395
395
""" Handle error. """
396
396
self .logger .error ('Encountered error on socket.' ,
0 commit comments