diff options
Diffstat (limited to 'Tools/idle/RemoteInterp.py')
-rw-r--r-- | Tools/idle/RemoteInterp.py | 341 |
1 files changed, 0 insertions, 341 deletions
diff --git a/Tools/idle/RemoteInterp.py b/Tools/idle/RemoteInterp.py deleted file mode 100644 index e6f7671..0000000 --- a/Tools/idle/RemoteInterp.py +++ /dev/null @@ -1,341 +0,0 @@ -import select -import socket -import struct -import sys -import types - -VERBOSE = None - -class SocketProtocol: - """A simple protocol for sending strings across a socket""" - BUF_SIZE = 8192 - - def __init__(self, sock): - self.sock = sock - self._buffer = '' - self._closed = 0 - - def close(self): - self._closed = 1 - self.sock.close() - - def send(self, buf): - """Encode buf and write it on the socket""" - if VERBOSE: - VERBOSE.write('send %d:%s\n' % (len(buf), `buf`)) - self.sock.send('%d:%s' % (len(buf), buf)) - - def receive(self, timeout=0): - """Get next complete string from socket or return None - - Raise EOFError on EOF - """ - buf = self._read_from_buffer() - if buf is not None: - return buf - recvbuf = self._read_from_socket(timeout) - if recvbuf is None: - return None - if recvbuf == '' and self._buffer == '': - raise EOFError - if VERBOSE: - VERBOSE.write('recv %s\n' % `recvbuf`) - self._buffer = self._buffer + recvbuf - r = self._read_from_buffer() - return r - - def _read_from_socket(self, timeout): - """Does not block""" - if self._closed: - return '' - if timeout is not None: - r, w, x = select.select([self.sock], [], [], timeout) - if timeout is None or r: - return self.sock.recv(self.BUF_SIZE) - else: - return None - - def _read_from_buffer(self): - buf = self._buffer - i = buf.find(':') - if i == -1: - return None - buflen = int(buf[:i]) - enclen = i + 1 + buflen - if len(buf) >= enclen: - s = buf[i+1:enclen] - self._buffer = buf[enclen:] - return s - else: - self._buffer = buf - return None - -# helpers for registerHandler method below - -def get_methods(obj): - methods = [] - for name in dir(obj): - attr = getattr(obj, name) - if callable(attr): - methods.append(name) - if type(obj) == types.InstanceType: - methods = methods + get_methods(obj.__class__) - if type(obj) == types.ClassType: - for super in obj.__bases__: - methods = methods + get_methods(super) - return methods - -class CommandProtocol: - def __init__(self, sockp): - self.sockp = sockp - self.seqno = 0 - self.handlers = {} - - def close(self): - self.sockp.close() - self.handlers.clear() - - def registerHandler(self, handler): - """A Handler is an object with handle_XXX methods""" - for methname in get_methods(handler): - if methname[:7] == "handle_": - name = methname[7:] - self.handlers[name] = getattr(handler, methname) - - def send(self, cmd, arg='', seqno=None): - if arg: - msg = "%s %s" % (cmd, arg) - else: - msg = cmd - if seqno is None: - seqno = self.get_seqno() - msgbuf = self.encode_seqno(seqno) + msg - self.sockp.send(msgbuf) - if cmd == "reply": - return - reply = self.sockp.receive(timeout=None) - r_cmd, r_arg, r_seqno = self._decode_msg(reply) - assert r_seqno == seqno and r_cmd == "reply", "bad reply" - return r_arg - - def _decode_msg(self, msg): - seqno = self.decode_seqno(msg[:self.SEQNO_ENC_LEN]) - msg = msg[self.SEQNO_ENC_LEN:] - parts = msg.split(" ", 2) - if len(parts) == 1: - cmd = msg - arg = '' - else: - cmd = parts[0] - arg = parts[1] - return cmd, arg, seqno - - def dispatch(self): - msg = self.sockp.receive() - if msg is None: - return - cmd, arg, seqno = self._decode_msg(msg) - self._current_reply = seqno - h = self.handlers.get(cmd, self.default_handler) - try: - r = h(arg) - except TypeError, msg: - raise TypeError, "handle_%s: %s" % (cmd, msg) - if self._current_reply is None: - if r is not None: - sys.stderr.write("ignoring %s return value type %s\n" % \ - (cmd, type(r).__name__)) - return - if r is None: - r = '' - if type(r) != types.StringType: - raise ValueError, "invalid return type for %s" % cmd - self.send("reply", r, seqno=seqno) - - def reply(self, arg=''): - """Send a reply immediately - - otherwise reply will be sent when handler returns - """ - self.send("reply", arg, self._current_reply) - self._current_reply = None - - def default_handler(self, arg): - sys.stderr.write("WARNING: unhandled message %s\n" % arg) - return '' - - SEQNO_ENC_LEN = 4 - - def get_seqno(self): - seqno = self.seqno - self.seqno = seqno + 1 - return seqno - - def encode_seqno(self, seqno): - return struct.pack("I", seqno) - - def decode_seqno(self, buf): - return struct.unpack("I", buf)[0] - - -class StdioRedirector: - """Redirect sys.std{in,out,err} to a set of file-like objects""" - - def __init__(self, stdin, stdout, stderr): - self.stdin = stdin - self.stdout = stdout - self.stderr = stderr - - def redirect(self): - self.save() - sys.stdin = self.stdin - sys.stdout = self.stdout - sys.stderr = self.stderr - - def save(self): - self._stdin = sys.stdin - self._stdout = sys.stdout - self._stderr = sys.stderr - - def restore(self): - sys.stdin = self._stdin - sys.stdout = self._stdout - sys.stderr = self._stderr - -class IOWrapper: - """Send output from a file-like object across a SocketProtocol - - XXX Should this be more tightly integrated with the CommandProtocol? - """ - - def __init__(self, name, cmdp): - self.name = name - self.cmdp = cmdp - self.buffer = [] - -class InputWrapper(IOWrapper): - def write(self, buf): - # XXX what should this do on Windows? - raise IOError, (9, '[Errno 9] Bad file descriptor') - - def read(self, arg=None): - if arg is not None: - if arg <= 0: - return '' - else: - arg = 0 - return self.cmdp.send(self.name, "read,%s" % arg) - - def readline(self): - return self.cmdp.send(self.name, "readline") - -class OutputWrapper(IOWrapper): - def write(self, buf): - self.cmdp.send(self.name, buf) - - def read(self, arg=None): - return '' - -class RemoteInterp: - def __init__(self, sock): - self._sock = SocketProtocol(sock) - self._cmd = CommandProtocol(self._sock) - self._cmd.registerHandler(self) - - def run(self): - try: - while 1: - self._cmd.dispatch() - except EOFError: - pass - - def handle_execfile(self, arg): - self._cmd.reply() - io = StdioRedirector(InputWrapper("stdin", self._cmd), - OutputWrapper("stdout", self._cmd), - OutputWrapper("stderr", self._cmd)) - io.redirect() - execfile(arg, {'__name__':'__main__'}) - io.restore() - self._cmd.send("terminated") - - def handle_quit(self, arg): - self._cmd.reply() - self._cmd.close() - -def startRemoteInterp(id): - import os - # UNIX domain sockets are simpler for starters - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.bind("/var/tmp/ri.%s" % id) - try: - sock.listen(1) - cli, addr = sock.accept() - rinterp = RemoteInterp(cli) - rinterp.run() - finally: - os.unlink("/var/tmp/ri.%s" % id) - -class RIClient: - """Client of the remote interpreter""" - def __init__(self, sock): - self._sock = SocketProtocol(sock) - self._cmd = CommandProtocol(self._sock) - self._cmd.registerHandler(self) - - def execfile(self, file): - self._cmd.send("execfile", file) - - def run(self): - try: - while 1: - self._cmd.dispatch() - except EOFError: - pass - - def handle_stdout(self, buf): - sys.stdout.write(buf) -## sys.stdout.flush() - - def handle_stderr(self, buf): - sys.stderr.write(buf) - - def handle_stdin(self, arg): - if arg == "readline": - return sys.stdin.readline() - i = arg.find(",") + 1 - bytes = int(arg[i:]) - if bytes == 0: - return sys.stdin.read() - else: - return sys.stdin.read(bytes) - - def handle_terminated(self, arg): - self._cmd.reply() - self._cmd.send("quit") - self._cmd.close() - -def riExec(id, file): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect("/var/tmp/ri.%s" % id) - cli = RIClient(sock) - cli.execfile(file) - cli.run() - -if __name__ == "__main__": - import getopt - - SERVER = 1 - opts, args = getopt.getopt(sys.argv[1:], 'cv') - for o, v in opts: - if o == '-c': - SERVER = 0 - elif o == '-v': - VERBOSE = sys.stderr - id = args[0] - - if SERVER: - startRemoteInterp(id) - else: - file = args[1] - riExec(id, file) |