|
40 | 40 | import threading |
41 | 41 |
|
42 | 42 | from .msg import MessageDecoder |
43 | | -from .util import socketsource |
| 43 | +from .util import socketsource, ReceiveBuffer |
44 | 44 | from .common import ApplevelProtocolMixin |
45 | 45 |
|
46 | 46 | __all__ = ["connect"] |
@@ -181,32 +181,41 @@ class SessionExit(Exception): |
181 | 181 | # Set up remote tab completion, using a custom completer for readline. |
182 | 182 | # https://stackoverflow.com/questions/35115208/is-there-any-way-to-combine-readline-rlcompleter-and-interactiveconsole-in-pytho |
183 | 183 | 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? |
185 | 185 |
|
186 | 186 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: # remote REPL session |
187 | 187 | sock.connect(addrspec) |
188 | 188 |
|
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 | + |
190 | 200 | # The first line of text contains the session id. |
191 | 201 | # 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 |
209 | 217 | controller.pair_with_session(repl_session_id) |
| 218 | + sys.stdout.write(text) |
210 | 219 |
|
211 | 220 | # TODO: This can't be a separate thread, we must listen for input only when a prompt has appeared. |
212 | 221 | def sock_to_stdout(): |
|
0 commit comments