~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to scripts/python-console

  • Committer: dcoles
  • Date: 2008-07-03 04:20:54 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:803
Setup: Modularised setup.py so it is now no longer over 1000 lines. This should 
allow us to get in there and tidy up each module much easier. Also removed 
updatejails since this functionality seems to be duplicated with remakeuser.py 
and remakealluser.py scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
# usage:
 
4
#   python-console <port> <magic> [<working-dir>]
 
5
 
 
6
import cjson
 
7
import codeop
 
8
import md5
 
9
import os
 
10
import Queue
 
11
import signal
 
12
import socket
 
13
import sys
 
14
from threading import Thread
 
15
from functools import partial
 
16
 
 
17
import common.chat
 
18
 
 
19
class Interrupt(Exception):
 
20
    def __init__(self):
 
21
        Exception.__init__(self, "Interrupted!")
 
22
 
 
23
class ExpiryTimer(object):
 
24
    def __init__(self, idle):
 
25
        self.idle = idle
 
26
        signal.signal(signal.SIGALRM, partial(self.timeout))
 
27
 
 
28
    def ping(self):
 
29
        signal.alarm(self.idle)
 
30
 
 
31
    def start(self, time):
 
32
        signal.alarm(time)
 
33
 
 
34
    def stop(self):
 
35
        self.ping()
 
36
 
 
37
    def timeout(self, signum, frame):
 
38
        sys.exit(1)
 
39
        
 
40
class StdinFromWeb(object):
 
41
    def __init__(self, cmdQ, lineQ):
 
42
        self.cmdQ = cmdQ
 
43
        self.lineQ = lineQ
 
44
 
 
45
    def readline(self):
 
46
        self.cmdQ.put({"input":None})
 
47
        expiry.ping()
 
48
        ln = self.lineQ.get()
 
49
        if 'chat' in ln:
 
50
            return ln['chat']
 
51
        if 'interrupt' in ln:
 
52
            raise Interrupt()
 
53
 
 
54
class StdoutToWeb(object):
 
55
    def __init__(self, cmdQ, lineQ):
 
56
        self.cmdQ = cmdQ
 
57
        self.lineQ = lineQ
 
58
        self.remainder = ''
 
59
 
 
60
    def write(self, stuff):
 
61
        self.remainder = self.remainder + stuff
 
62
 
 
63
        # if there's less than 128 bytes, buffer
 
64
        if len(self.remainder) < 128:
 
65
            return
 
66
 
 
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})
 
71
            expiry.ping()
 
72
            ln = self.lineQ.get()
 
73
            self.remainder = self.remainder[512:]
 
74
 
 
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]
 
79
        del lines[-1]
 
80
 
 
81
        if len(lines) > 0:
 
82
            lines.append('')
 
83
            text = "\n".join(lines)
 
84
            self.cmdQ.put({"output":text})
 
85
            expiry.ping()
 
86
            ln = self.lineQ.get()
 
87
            if 'interrupt' in ln:
 
88
                raise Interrupt()
 
89
 
 
90
    def flush(self):
 
91
        if len(self.remainder) > 0:
 
92
            self.cmdQ.put({"output":self.remainder})
 
93
            expiry.ping()
 
94
            ln = self.lineQ.get()
 
95
            self.remainder = ''
 
96
            if 'interrupt' in ln:
 
97
                raise Interrupt()
 
98
 
 
99
class WebIO(object):
 
100
    """Provides a file like interface to the Web front end of the console.
 
101
    You may print text to the console using write(), flush any buffered output 
 
102
    using flush(), or request text from the console using readline()"""
 
103
    
 
104
    def __init__(self, cmdQ, lineQ):
 
105
        self.cmdQ = cmdQ
 
106
        self.lineQ = lineQ
 
107
        self.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
 
108
        self.stdout = StdoutToWeb(self.cmdQ, self.lineQ)
 
109
 
 
110
    def write(self, stuff):
 
111
        self.stdout.write(stuff)
 
112
 
 
113
    def flush(self):
 
114
        self.stdout.flush()
 
115
 
 
116
    def readline(self):
 
117
        self.stdout.flush()
 
118
        return self.stdin.readline()
 
119
 
 
120
class PythonRunner(Thread):
 
121
    def __init__(self, cmdQ, lineQ):
 
122
        self.cmdQ = cmdQ
 
123
        self.lineQ = lineQ
 
124
        self.webio = WebIO(self.cmdQ, self.lineQ)
 
125
        Thread.__init__(self)
 
126
 
 
127
    def execCmd(self, cmd):
 
128
        try:
 
129
            sys.stdin = self.webio
 
130
            sys.stdout = self.webio
 
131
            sys.stderr = self.webio
 
132
            res = eval(cmd, self.globs)
 
133
            self.webio.flush()
 
134
            self.cmdQ.put({"okay":res})
 
135
            self.curr_cmd = ''
 
136
        except Exception, exc:
 
137
            self.webio.flush()
 
138
            exc_classname = exc.__class__.__name__
 
139
            self.cmdQ.put({"exc": exc_classname + ": " + str(exc)})
 
140
            self.curr_cmd = ''
 
141
 
 
142
    def run(self):
 
143
        self.globs = {}
 
144
        self.globs['__builtins__'] = globals()['__builtins__']
 
145
        self.curr_cmd = ''
 
146
        compiler = codeop.CommandCompiler()
 
147
 
 
148
        while True:
 
149
            ln = self.lineQ.get()
 
150
            if 'chat' in ln:
 
151
                if self.curr_cmd == '':
 
152
                    self.curr_cmd = ln['chat']
 
153
                else:
 
154
                    self.curr_cmd = self.curr_cmd + '\n' + ln['chat']
 
155
                try:
 
156
                    cmd = compiler(self.curr_cmd)
 
157
                    if cmd is None:
 
158
                        # The command was incomplete,
 
159
                        # so send back a None, so the
 
160
                        # client can print a '...'
 
161
                        self.cmdQ.put({"more":None})
 
162
                    else:
 
163
                        self.execCmd(cmd)
 
164
                except Exception, exc:
 
165
                    self.webio.flush()
 
166
                    self.cmdQ.put({"exc":str(exc)})
 
167
                    self.curr_cmd = ''
 
168
            if 'block' in ln:
 
169
                # throw away a partial command.
 
170
                try:
 
171
                    cmd = compile(ln['block'], "<web session>", 'exec');
 
172
                    self.execCmd(cmd)
 
173
                except Exception, exc:
 
174
                    self.webio.flush()
 
175
                    self.cmdQ.put({"exc":str(exc)})
 
176
                    self.curr_cmd = ''
 
177
 
 
178
def daemonize():
 
179
    if os.fork():   # launch child and...
 
180
        os._exit(0) # kill off parent
 
181
    os.setsid()
 
182
    if os.fork():   # launch child and...
 
183
        os._exit(0) # kill off parent again.
 
184
    os.umask(077)
 
185
 
 
186
# The global 'magic' is the secret that the client and server share
 
187
# which is used to create and md5 digest to authenticate requests.
 
188
# It is assigned a real value at startup.
 
189
magic = ''
 
190
 
 
191
cmdQ = Queue.Queue()
 
192
lineQ = Queue.Queue()
 
193
interpThread = PythonRunner(cmdQ, lineQ)
 
194
 
 
195
# Default expiry time of 15 minutes
 
196
expiry = ExpiryTimer(15 * 60)
 
197
 
 
198
def initializer():
 
199
    interpThread.setDaemon(True)
 
200
    interpThread.start()
 
201
    expiry.ping()
 
202
 
 
203
def dispatch_msg(msg):
 
204
    expiry.ping()
 
205
    lineQ.put({msg['cmd']:msg['text']})
 
206
    return cmdQ.get()
 
207
 
 
208
if __name__ == "__main__":
 
209
    port = int(sys.argv[1])
 
210
    magic = sys.argv[2]
 
211
    if len(sys.argv) >= 4:
 
212
        # working_dir
 
213
        os.chdir(sys.argv[3])
 
214
        # Make python's search path follow the cwd
 
215
        sys.path[0] = ''
 
216
        os.environ['HOME'] = sys.argv[3]
 
217
 
 
218
    common.chat.start_server(port, magic, True, dispatch_msg, initializer)