Skip to content

Commit f482042

Browse files
committed
REPL client: prepare for prompt detector
1 parent d0a771d commit f482042

File tree

1 file changed

+29
-20
lines changed

1 file changed

+29
-20
lines changed

unpythonic/net/client.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
import threading
4141

4242
from .msg import MessageDecoder
43-
from .util import socketsource
43+
from .util import socketsource, ReceiveBuffer
4444
from .common import ApplevelProtocolMixin
4545

4646
__all__ = ["connect"]
@@ -181,32 +181,41 @@ class SessionExit(Exception):
181181
# Set up remote tab completion, using a custom completer for readline.
182182
# https://stackoverflow.com/questions/35115208/is-there-any-way-to-combine-readline-rlcompleter-and-interactiveconsole-in-pytho
183183
readline.set_completer(controller.complete)
184-
readline.parse_and_bind("tab: complete")
184+
readline.parse_and_bind("tab: complete") # TODO: do we need this, PyPy doesn't support it?
185185

186186
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # remote REPL session
187187
sock.connect(addrspec)
188188

189-
# TODO: refactor
189+
# TODO: refactor. This is partial copypasta from unpythonic.net.msg.decodemsg.
190+
src = socketsource(sock)
191+
buf = ReceiveBuffer()
192+
def read_more_input():
193+
try:
194+
data = next(src)
195+
except StopIteration:
196+
raise EOFError
197+
buf.append(data)
198+
return buf.getvalue()
199+
190200
# The first line of text contains the session id.
191201
# We can't use the message protocol; this information must arrive on the primary channel.
192-
rs, ws, es = select.select([sock], [], [])
193-
for r in rs:
194-
data = sock.recv(4096)
195-
if len(data) == 0:
196-
print("unpythonic.net.client: disconnected by server.")
197-
raise SessionExit
198-
text = data.decode("utf-8")
199-
sys.stdout.write(text)
200-
if "\n" in text:
201-
first_line, *rest = text.split("\n")
202-
import re
203-
matches = re.findall(r"session (\d+) connected", first_line)
204-
assert len(matches) == 1, "Expected server to print session id on the first line"
205-
repl_session_id = int(matches[0])
206-
else:
207-
# TODO: make sure we always receive a whole line
208-
assert False
202+
try:
203+
val = buf.getvalue()
204+
while True:
205+
if b"\n" in val:
206+
text = val.decode("utf-8")
207+
first_line, *rest = text.split("\n")
208+
import re
209+
matches = re.findall(r"session (\d+) connected", first_line)
210+
assert len(matches) == 1, "Expected server to print session id on the first line"
211+
repl_session_id = int(matches[0])
212+
break
213+
val = read_more_input()
214+
except EOFError:
215+
print("unpythonic.net.client: disconnected by server.")
216+
raise SessionExit
209217
controller.pair_with_session(repl_session_id)
218+
sys.stdout.write(text)
210219

211220
# TODO: This can't be a separate thread, we must listen for input only when a prompt has appeared.
212221
def sock_to_stdout():

0 commit comments

Comments
 (0)