aiorepl: Use blocking reads for raw REPL and raw paste.

Raw REPL mode is generally used as a command channel where all stdio
traffic is related directly to the raw commands and responses sent.

For this to work in aiorepl we need to ensure background tasks don't sent/
receive anything on stdio else the command channel will be corrupted.

The simplest way to achieve this is to make the raw commands blocking and
atomic rather than asyncio, assuming the user wont leave the device in raw
mode for too long at any one time.

Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
pull/1005/head
Andrew Leech 2025-05-05 21:03:14 +10:00 zatwierdzone przez Damien George
rodzic 96bd01ec04
commit aad2e48098
2 zmienionych plików z 12 dodań i 7 usunięć

Wyświetl plik

@ -161,7 +161,7 @@ async def task(g=None, prompt="--> "):
cmd = cmd[:-1] cmd = cmd[:-1]
sys.stdout.write("\x08 \x08") sys.stdout.write("\x08 \x08")
elif c == CHAR_CTRL_A: elif c == CHAR_CTRL_A:
await raw_repl(s, g) raw_repl(sys.stdin, g)
break break
elif c == CHAR_CTRL_B: elif c == CHAR_CTRL_B:
continue continue
@ -239,7 +239,7 @@ async def task(g=None, prompt="--> "):
micropython.kbd_intr(3) micropython.kbd_intr(3)
async def raw_paste(s, g, window=512): def raw_paste(s, window=512):
sys.stdout.write("R\x01") # supported sys.stdout.write("R\x01") # supported
sys.stdout.write(bytearray([window & 0xFF, window >> 8, 0x01]).decode()) sys.stdout.write(bytearray([window & 0xFF, window >> 8, 0x01]).decode())
eof = False eof = False
@ -248,7 +248,7 @@ async def raw_paste(s, g, window=512):
file = b"" file = b""
while not eof: while not eof:
for idx in range(window): for idx in range(window):
b = await s.read(1) b = s.read(1)
c = ord(b) c = ord(b)
if c == CHAR_CTRL_C or c == CHAR_CTRL_D: if c == CHAR_CTRL_C or c == CHAR_CTRL_D:
# end of file # end of file
@ -267,7 +267,12 @@ async def raw_paste(s, g, window=512):
return file return file
async def raw_repl(s: asyncio.StreamReader, g: dict): def raw_repl(s, g: dict):
"""
This function is blocking to prevent other
async tasks from writing to the stdio stream and
breaking the raw repl session.
"""
heading = "raw REPL; CTRL-B to exit\n" heading = "raw REPL; CTRL-B to exit\n"
line = "" line = ""
sys.stdout.write(heading) sys.stdout.write(heading)
@ -276,7 +281,7 @@ async def raw_repl(s: asyncio.StreamReader, g: dict):
line = "" line = ""
sys.stdout.write(">") sys.stdout.write(">")
while True: while True:
b = await s.read(1) b = s.read(1)
c = ord(b) c = ord(b)
if c == CHAR_CTRL_A: if c == CHAR_CTRL_A:
rline = line rline = line
@ -284,7 +289,7 @@ async def raw_repl(s: asyncio.StreamReader, g: dict):
if len(rline) == 2 and ord(rline[0]) == CHAR_CTRL_E: if len(rline) == 2 and ord(rline[0]) == CHAR_CTRL_E:
if rline[1] == "A": if rline[1] == "A":
line = await raw_paste(s, g) line = raw_paste(s)
break break
else: else:
# reset raw REPL # reset raw REPL

Wyświetl plik

@ -1,5 +1,5 @@
metadata( metadata(
version="0.2.0", version="0.2.1",
description="Provides an asynchronous REPL that can run concurrently with an asyncio, also allowing await expressions.", description="Provides an asynchronous REPL that can run concurrently with an asyncio, also allowing await expressions.",
) )