4
# python-console <port> <magic> [<working-dir>]
14
from threading import Thread
15
from functools import partial
19
class Interrupt(Exception):
21
Exception.__init__(self, "Interrupted!")
23
class ExpiryTimer(object):
24
def __init__(self, idle):
26
signal.signal(signal.SIGALRM, partial(self.timeout))
29
signal.alarm(self.idle)
31
def start(self, time):
37
def timeout(self, signum, frame):
40
class StdinFromWeb(object):
41
def __init__(self, cmdQ, lineQ):
46
self.cmdQ.put({"input":None})
54
class StdoutToWeb(object):
55
def __init__(self, cmdQ, lineQ):
60
def write(self, stuff):
61
self.remainder = self.remainder + stuff
63
# if there's less than 128 bytes, buffer
64
if len(self.remainder) < 128:
67
# if there's lots, then send it in 1/2K blocks
68
while len(self.remainder) > 512:
69
blk = self.remainder[0:512]
70
self.cmdQ.put({"output":blk})
73
self.remainder = self.remainder[512:]
75
# Finally, split the remainder up into lines, and ship all the
76
# completed lines off to the server.
77
lines = self.remainder.split("\n")
78
self.remainder = lines[-1]
83
text = "\n".join(lines)
84
self.cmdQ.put({"output":text})
91
if len(self.remainder) > 0:
92
self.cmdQ.put({"output":self.remainder})
99
class PythonRunner(Thread):
100
def __init__(self, cmdQ, lineQ):
103
self.stdout = StdoutToWeb(self.cmdQ, self.lineQ)
104
Thread.__init__(self)
106
def execCmd(self, cmd):
108
sys.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
109
sys.stdout = self.stdout
110
sys.stderr = self.stdout
111
res = eval(cmd, self.globs)
113
self.cmdQ.put({"okay":res})
115
except Exception, exc:
117
exc_classname = exc.__class__.__name__
118
self.cmdQ.put({"exc": exc_classname + ": " + exc.message})
123
self.globs['__builtins__'] = globals()['__builtins__']
125
compiler = codeop.CommandCompiler()
128
ln = self.lineQ.get()
130
if self.curr_cmd == '':
131
self.curr_cmd = ln['chat']
133
self.curr_cmd = self.curr_cmd + '\n' + ln['chat']
135
cmd = compiler(self.curr_cmd)
137
# The command was incomplete,
138
# so send back a None, so the
139
# client can print a '...'
140
self.cmdQ.put({"more":None})
143
except Exception, exc:
145
self.cmdQ.put({"exc":str(exc)})
148
# throw away a partial command.
150
cmd = compile(ln['block'], "<web session>", 'exec');
152
except Exception, exc:
154
self.cmdQ.put({"exc":str(exc)})
158
if os.fork(): # launch child and...
159
os._exit(0) # kill off parent
161
if os.fork(): # launch child and...
162
os._exit(0) # kill off parent again.
165
# The global 'magic' is the secret that the client and server share
166
# which is used to create and md5 digest to authenticate requests.
167
# It is assigned a real value at startup.
171
lineQ = Queue.Queue()
172
interpThread = PythonRunner(cmdQ, lineQ)
174
# Default expiry time of 15 minutes
175
expiry = ExpiryTimer(15 * 60)
178
interpThread.setDaemon(True)
182
def dispatch_msg(msg):
184
lineQ.put({msg['cmd']:msg['text']})
187
if __name__ == "__main__":
188
port = int(sys.argv[1])
190
if len(sys.argv) >= 4:
192
os.chdir(sys.argv[3])
193
os.environ['HOME'] = sys.argv[3]
195
common.chat.start_server(port, magic, True, dispatch_msg, initializer)