Speed up IF reads with chunked I/O and short idle timeout

This commit is contained in:
Jared Miller 2026-02-09 17:05:27 -05:00
parent 43fce6a4ed
commit e8f16ca18a
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -170,34 +170,38 @@ class IFSession:
if not self.process or not self.process.stdout:
return ""
output = []
buf = b""
idle_timeout = 0.1 # return quickly once data stops flowing
overall_deadline = asyncio.get_event_loop().time() + 5.0
try:
# Read byte by byte until we see "\n>"
while True:
byte = await asyncio.wait_for(self.process.stdout.read(1), timeout=5.0)
if not byte:
remaining = overall_deadline - asyncio.get_event_loop().time()
if remaining <= 0:
break
char = byte.decode("latin-1")
output.append(char)
# Check if we've hit the prompt
# Prompt is "\n>" or just ">" at start
if len(output) >= 2:
if output[-2] == "\n" and output[-1] == ">":
# Strip the trailing "\n>"
output = output[:-2]
break
elif len(output) == 1 and output[0] == ">":
# Prompt at very start
output = []
timeout = min(idle_timeout, remaining)
try:
chunk = await asyncio.wait_for(
self.process.stdout.read(1024), timeout=timeout
)
except TimeoutError:
# No data for idle_timeout - dfrotz is done talking
break
if not chunk:
break
buf += chunk
# Check for prompt at end of buffer
text = buf.decode("latin-1")
if text.endswith("\n>"):
text = text[:-2]
return text.rstrip()
if text == ">":
return ""
except TimeoutError:
# If we timeout, return what we got
pass
result = "".join(output)
return result.rstrip()
return buf.decode("latin-1").rstrip()
async def broadcast_to_spectators(player: "Player", message: str) -> None: