Bound listing capture and accept all server count-line formats
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <[email protected]>
This commit is contained in:
+17
-4
@@ -22,6 +22,11 @@ logger = logging.getLogger('namelist')
|
||||
# from the request: a large cvarlist (5000+ messages) takes seconds to process.
|
||||
CAPTURE_TIMEOUT = 5.0
|
||||
|
||||
# Absolute cap on a capture, measured from the request. The timeout above is
|
||||
# refreshed by every incoming message, so regular server output can keep a
|
||||
# stuck capture (count line never matches) alive indefinitely without this bound.
|
||||
CAPTURE_MAX_DURATION = 30.0
|
||||
|
||||
# Cvar line: the name is the word directly before the quoted value.
|
||||
# Example: 'S A sv_hostname "My Server"' -> sv_hostname
|
||||
CVARLIST_LINE = re.compile(r'([A-Za-z_]\w*)\s+"')
|
||||
@@ -31,8 +36,8 @@ CVARLIST_LINE = re.compile(r'([A-Za-z_]\w*)\s+"')
|
||||
CMDLIST_LINE = re.compile(r'^\s*([A-Za-z_]\w*)\s*$')
|
||||
|
||||
# Count line that ends a listing.
|
||||
# Examples: '1234 total cvars', '321 commands'
|
||||
END_LINE = re.compile(r'^\s*\d+\s+(total cvars|commands)\s*$')
|
||||
# Examples: '1234 total cvars', '321 commands', '321 total commands'
|
||||
END_LINE = re.compile(r'^\s*\d+\s+(total cvars|total commands|commands)\s*$')
|
||||
|
||||
|
||||
def unwrap(message):
|
||||
@@ -55,12 +60,14 @@ class NameCapture:
|
||||
self.names = set()
|
||||
self.listings_pending = 0 # count lines still expected; 0 = not capturing
|
||||
self.deadline = 0
|
||||
self.deadline_max = 0
|
||||
self.partial_line = ''
|
||||
|
||||
def request(self, rcon):
|
||||
"""Send cvarlist and cmdlist; their output is captured until both count lines arrived"""
|
||||
self.listings_pending = 2
|
||||
self.deadline = time.time() + CAPTURE_TIMEOUT
|
||||
self.deadline_max = time.time() + CAPTURE_MAX_DURATION
|
||||
self.partial_line = ''
|
||||
rcon.send_command(b'cvarlist')
|
||||
rcon.send_command(b'cmdlist')
|
||||
@@ -73,12 +80,18 @@ class NameCapture:
|
||||
"""
|
||||
if self.listings_pending == 0:
|
||||
return False
|
||||
if time.time() > self.deadline:
|
||||
now = time.time()
|
||||
if now > self.deadline_max:
|
||||
logger.warning(f'Capture exceeded {CAPTURE_MAX_DURATION:.0f}s, '
|
||||
f'stopping capture with {len(self.names)} names')
|
||||
self.listings_pending = 0
|
||||
return False
|
||||
if now > self.deadline:
|
||||
logger.warning(f'No listing output for {CAPTURE_TIMEOUT:.0f}s, '
|
||||
f'stopping capture with {len(self.names)} names')
|
||||
self.listings_pending = 0
|
||||
return False
|
||||
self.deadline = time.time() + CAPTURE_TIMEOUT
|
||||
self.deadline = now + CAPTURE_TIMEOUT
|
||||
|
||||
# A line can arrive in several messages (the server sends each flag column of
|
||||
# a cvarlist row as its own 1-byte message), so keep the unfinished tail
|
||||
|
||||
Reference in New Issue
Block a user