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

« back to all changes in this revision

Viewing changes to scripts/python-console

  • Committer: dcoles
  • Date: 2008-07-01 01:05:50 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:795
ConsoleService: Small change in error message. Previous message would warn user 
that a free port could not be found if the console service couldn't be started 
after 5 attemps, but other issues (syntax errors seem to be my main culprit) 
can cause this exception to be triggered and can make the error misleading.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
 
3
3
# usage:
4
 
#   python-console <port> <magic>
 
4
#   python-console <port> <magic> [<working-dir>]
5
5
 
6
6
import cjson
7
7
import codeop
8
 
import cStringIO
9
8
import md5
10
9
import os
11
10
import Queue
13
12
import socket
14
13
import sys
15
14
from threading import Thread
 
15
from functools import partial
16
16
 
17
17
import common.chat
18
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
        
19
40
class StdinFromWeb(object):
20
41
    def __init__(self, cmdQ, lineQ):
21
42
        self.cmdQ = cmdQ
22
43
        self.lineQ = lineQ
23
44
 
24
45
    def readline(self):
25
 
        # stop the clock!
26
 
        signal.alarm(0)
27
46
        self.cmdQ.put({"input":None})
 
47
        expiry.ping()
28
48
        ln = self.lineQ.get()
29
49
        if 'chat' in ln:
30
 
            # restart the clock:
31
 
            # Some of our 5 seconds may have elapsed, but never mind.
32
 
            signal.alarm(5)
33
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()
34
119
 
35
120
class PythonRunner(Thread):
36
121
    def __init__(self, cmdQ, lineQ):
37
122
        self.cmdQ = cmdQ
38
123
        self.lineQ = lineQ
39
 
        self.out = cStringIO.StringIO()
 
124
        self.webio = WebIO(self.cmdQ, self.lineQ)
40
125
        Thread.__init__(self)
41
126
 
42
127
    def execCmd(self, cmd):
43
128
        try:
44
 
            sys.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
45
 
            sys.stdout = self.out
46
 
            sys.stderr = self.out
47
 
            signal.alarm(5)
48
 
            res = eval(cmd, self.globs, self.locls)
49
 
            signal.alarm(0)
50
 
            self.cmdQ.put({"okay":(self.out.getvalue(),res)})
 
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})
51
135
            self.curr_cmd = ''
52
 
            self.out = cStringIO.StringIO()
53
136
        except Exception, exc:
54
 
            signal.alarm(0)
55
 
            self.cmdQ.put({"exc":(self.out.getvalue(),str(exc))})
 
137
            self.webio.flush()
 
138
            exc_classname = exc.__class__.__name__
 
139
            self.cmdQ.put({"exc": exc_classname + ": " + str(exc)})
56
140
            self.curr_cmd = ''
57
 
            self.out = cStringIO.StringIO()
58
141
 
59
142
    def run(self):
60
 
        self.init_state()
 
143
        self.globs = {}
 
144
        self.globs['__builtins__'] = globals()['__builtins__']
 
145
        self.curr_cmd = ''
61
146
        compiler = codeop.CommandCompiler()
62
147
 
63
148
        while True:
77
162
                    else:
78
163
                        self.execCmd(cmd)
79
164
                except Exception, exc:
80
 
                    signal.alarm(0)
81
 
                    self.cmdQ.put({"exc":(self.out.getvalue(),str(exc))})
 
165
                    self.webio.flush()
 
166
                    self.cmdQ.put({"exc":str(exc)})
82
167
                    self.curr_cmd = ''
83
 
                    self.out = cStringIO.StringIO()
84
168
            if 'block' in ln:
85
169
                # throw away a partial command.
86
170
                try:
87
171
                    cmd = compile(ln['block'], "<web session>", 'exec');
88
172
                    self.execCmd(cmd)
89
173
                except Exception, exc:
90
 
                    signal.alarm(0)
91
 
                    self.cmdQ.put({"exc":(self.out.getvalue(),str(exc))})
 
174
                    self.webio.flush()
 
175
                    self.cmdQ.put({"exc":str(exc)})
92
176
                    self.curr_cmd = ''
93
 
                    self.out = cStringIO.StringIO()
94
 
 
95
 
    def init_state(self):
96
 
        self.globs = {}
97
 
        self.globs['__builtins__'] = globals()['__builtins__']
98
 
        self.locls = {}
99
 
        self.curr_cmd = ''
100
177
 
101
178
def daemonize():
102
179
    if os.fork():   # launch child and...
115
192
lineQ = Queue.Queue()
116
193
interpThread = PythonRunner(cmdQ, lineQ)
117
194
 
 
195
# Default expiry time of 15 minutes
 
196
expiry = ExpiryTimer(15 * 60)
 
197
 
118
198
def initializer():
119
199
    interpThread.setDaemon(True)
120
200
    interpThread.start()
 
201
    expiry.ping()
121
202
 
122
203
def dispatch_msg(msg):
 
204
    expiry.ping()
123
205
    lineQ.put({msg['cmd']:msg['text']})
124
206
    return cmdQ.get()
125
207
 
126
208
if __name__ == "__main__":
127
209
    port = int(sys.argv[1])
128
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]
129
217
 
130
218
    common.chat.start_server(port, magic, True, dispatch_msg, initializer)