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

« back to all changes in this revision

Viewing changes to scripts/python-console

  • Committer: dcoles
  • Date: 2008-04-18 07:28:21 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:740
Libs: Python Imaging Library

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 PythonRunner(Thread):
 
100
    def __init__(self, cmdQ, lineQ):
 
101
        self.cmdQ = cmdQ
 
102
        self.lineQ = lineQ
 
103
        self.stdout = StdoutToWeb(self.cmdQ, self.lineQ)
 
104
        Thread.__init__(self)
 
105
 
 
106
    def execCmd(self, cmd):
 
107
        try:
 
108
            sys.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
 
109
            sys.stdout = self.stdout
 
110
            sys.stderr = self.stdout
 
111
            res = eval(cmd, self.globs)
 
112
            self.stdout.flush()
 
113
            self.cmdQ.put({"okay":res})
 
114
            self.curr_cmd = ''
 
115
        except Exception, exc:
 
116
            self.stdout.flush()
 
117
            exc_classname = exc.__class__.__name__
 
118
            self.cmdQ.put({"exc": exc_classname + ": " + exc.message})
 
119
            self.curr_cmd = ''
 
120
 
 
121
    def run(self):
 
122
        self.globs = {}
 
123
        self.globs['__builtins__'] = globals()['__builtins__']
 
124
        self.curr_cmd = ''
 
125
        compiler = codeop.CommandCompiler()
 
126
 
 
127
        while True:
 
128
            ln = self.lineQ.get()
 
129
            if 'chat' in ln:
 
130
                if self.curr_cmd == '':
 
131
                    self.curr_cmd = ln['chat']
 
132
                else:
 
133
                    self.curr_cmd = self.curr_cmd + '\n' + ln['chat']
 
134
                try:
 
135
                    cmd = compiler(self.curr_cmd)
 
136
                    if cmd is None:
 
137
                        # The command was incomplete,
 
138
                        # so send back a None, so the
 
139
                        # client can print a '...'
 
140
                        self.cmdQ.put({"more":None})
 
141
                    else:
 
142
                        self.execCmd(cmd)
 
143
                except Exception, exc:
 
144
                    self.stdout.flush()
 
145
                    self.cmdQ.put({"exc":str(exc)})
 
146
                    self.curr_cmd = ''
 
147
            if 'block' in ln:
 
148
                # throw away a partial command.
 
149
                try:
 
150
                    cmd = compile(ln['block'], "<web session>", 'exec');
 
151
                    self.execCmd(cmd)
 
152
                except Exception, exc:
 
153
                    self.stdout.flush()
 
154
                    self.cmdQ.put({"exc":str(exc)})
 
155
                    self.curr_cmd = ''
 
156
 
 
157
def daemonize():
 
158
    if os.fork():   # launch child and...
 
159
        os._exit(0) # kill off parent
 
160
    os.setsid()
 
161
    if os.fork():   # launch child and...
 
162
        os._exit(0) # kill off parent again.
 
163
    os.umask(077)
 
164
 
 
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.
 
168
magic = ''
 
169
 
 
170
cmdQ = Queue.Queue()
 
171
lineQ = Queue.Queue()
 
172
interpThread = PythonRunner(cmdQ, lineQ)
 
173
 
 
174
# Default expiry time of 15 minutes
 
175
expiry = ExpiryTimer(15 * 60)
 
176
 
 
177
def initializer():
 
178
    interpThread.setDaemon(True)
 
179
    interpThread.start()
 
180
    expiry.ping()
 
181
 
 
182
def dispatch_msg(msg):
 
183
    expiry.ping()
 
184
    lineQ.put({msg['cmd']:msg['text']})
 
185
    return cmdQ.get()
 
186
 
 
187
if __name__ == "__main__":
 
188
    port = int(sys.argv[1])
 
189
    magic = sys.argv[2]
 
190
    if len(sys.argv) >= 4:
 
191
        # working_dir
 
192
        os.chdir(sys.argv[3])
 
193
        os.environ['HOME'] = sys.argv[3]
 
194
 
 
195
    common.chat.start_server(port, magic, True, dispatch_msg, initializer)