"""
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()
|