""" Basic usage: start_console_thread(port) then just connect to the port you specified and hack away. """ import socket, code, threading, sys # something internal in CodeCompiler writes to # stdout; we don't want to clobber stdout for the rest of the app, # so we have to do this as a workaround class DummyWriter: def __init__(self, sc, other_stream, threadname): self.sc = sc self.other_stream = other_stream self.threadname = threadname def write(self, s): if threading.currentThread().getName() == self.threadname: self.sc.write(s) else: self.other_stream.write(s) class SocketConsole(code.InteractiveConsole): def __init__(self, sock, locals=None): code.InteractiveConsole.__init__(self, locals, 'socketconsole') self.sock = sock self.rfile = self.sock.makefile() sys.stdout = DummyWriter(self, sys.stdout, 'socketconsole') # stderr too, for completeness sys.stderr = DummyWriter(self, sys.stderr, 'socketconsole') def __del__(self): sys.stdout = sys.stdout.other_stream sys.stderr = sys.stderr.other_stream def raw_input(self, prompt=''): self.write(prompt) s = self.rfile.readline() if not s: raise EOFError() return s.rstrip() def write(self, s): self.sock.sendall(s) class MetaConsole: """ Hands incomming connections off to a SocketConsole. No extra threading is done; only one SocketConsole will be active at a time. """ def __init__(self, port): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind(('', port)) self.sock.listen(1) def one_session(self): s, _ = self.sock.accept() sc = SocketConsole(s) sc.interact() def run(self): while True: try: self.one_session() except socket.error: pass def start_console_thread(port=9999): mc = MetaConsole(port) t = threading.Thread(target=mc.run, name='socketconsole') t.setDaemon(True) t.start()