1+ import socket
12import time
23from typing import Iterator
34
5+ from .error import VBANCMDConnectionError
6+
47
58def ratelimit (func ):
69 """ratelimit decorator for {VbanCmd}.sendtext, to prevent flooding the network with script requests."""
@@ -18,6 +21,54 @@ def wrapper(*args, **kwargs):
1821 return wrapper
1922
2023
24+ def ping_timeout (func ):
25+ """ping_timeout decorator for {VbanCmd}._ping, to handle timeout logic and socket management."""
26+
27+ def wrapper (self , timeout : float = None ):
28+ if timeout is None :
29+ timeout = min (self .timeout , 3.0 )
30+
31+ original_timeout = self .sock .gettimeout ()
32+ self .sock .settimeout (0.5 )
33+
34+ try :
35+ func (self )
36+
37+ start_time = time .time ()
38+ response_count = 0
39+
40+ while time .time () - start_time < timeout :
41+ try :
42+ data , addr = self .sock .recvfrom (2048 )
43+ response_count += 1
44+
45+ self .logger .debug (
46+ f'Received packet #{ response_count } from { addr } : { len (data )} bytes'
47+ )
48+ self .logger .debug (
49+ f'Response header: { data [: min (32 , len (data ))].hex ()} '
50+ )
51+
52+ result = func (self , data , addr )
53+ if result is True :
54+ return
55+
56+ except socket .timeout :
57+ continue
58+
59+ self .logger .debug (
60+ f'PING timeout after { timeout } s, received { response_count } non-PONG packets'
61+ )
62+ raise VBANCMDConnectionError (
63+ f'PING timeout: No response from { self .host } :{ self .port } after { timeout } s'
64+ )
65+
66+ finally :
67+ self .sock .settimeout (original_timeout )
68+
69+ return wrapper
70+
71+
2172def cache_bool (func , param ):
2273 """Check cache for a bool prop"""
2374
0 commit comments