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

95 by mattgiuca
Moved some things out of www into their respective dirs, console and
1
#!/usr/bin/python
2
3
# usage:
4
#   python-console <port> <magic>
5
126 by drtomc
A basic version of the console going!
6
import sys
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
7
import web
8
import md5
9
import codeop
10
import cjson
126 by drtomc
A basic version of the console going!
11
import cgi
12
import cStringIO
13
import signal
212 by drtomc
Gosh, it all looks pretty simple in the end!
14
import Queue
15
from threading import Thread
16
17
class StdinFromWeb(object):
18
    def __init__(self, cmdQ, lineQ):
19
        self.cmdQ = cmdQ
20
        self.lineQ = lineQ
21
22
    def readline(self):
23
        # stop the clock!
128 by drtomc
A couple of bug fixes.
24
        signal.alarm(0)
212 by drtomc
Gosh, it all looks pretty simple in the end!
25
        self.cmdQ.put({"input":None})
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
26
        ln = self.lineQ.get()
27
        if 'chat' in ln:
28
            # restart the clock:
29
            # Some of our 5 seconds may have elapsed, but never mind.
30
            signal.alarm(5)
31
            return ln['chat']
212 by drtomc
Gosh, it all looks pretty simple in the end!
32
33
class PythonRunner(Thread):
34
    def __init__(self, cmdQ, lineQ):
35
        self.cmdQ = cmdQ
36
        self.lineQ = lineQ
37
        Thread.__init__(self)
38
39
    def run(self):
263 by drtomc
A few little cleanups.
40
        self.init_state()
212 by drtomc
Gosh, it all looks pretty simple in the end!
41
        compiler = codeop.CommandCompiler()
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
42
212 by drtomc
Gosh, it all looks pretty simple in the end!
43
        while True:
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
44
            ln = self.lineQ.get()
45
            if 'chat' in ln:
46
                mode = 
47
                if self.curr_cmd == '':
48
                    self.curr_cmd = ln['chat']
212 by drtomc
Gosh, it all looks pretty simple in the end!
49
                else:
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
50
                    self.curr_cmd = self.curr_cmd + '\n' + ln['chat']
51
                try:
52
                    cmd = compiler(self.curr_cmd)
53
                    if cmd is None:
54
                        # The command was incomplete,
55
                        # so send back a None, so the
56
                        # client can print a '...'
57
                        self.cmdQ.put({"more":None})
58
                    else:
59
                        # The command was complete,
60
                        # so evaluate it!
61
                        sys.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
62
                        self.out = cStringIO.StringIO()
63
                        sys.stdout = out
64
                        sys.stderr = out
65
                        signal.alarm(5)
66
                        res = eval(cmd, globs, locls)
67
                        signal.alarm(0)
68
                        self.cmdQ.put({"okay":(self.out.getvalue(),res)})
69
                        self.curr_cmd = ''
70
                except Exception, exc:
71
                    signal.alarm(0)
72
                    self.cmdQ.put({"exc":(self.out.getvalue(),str(exc))})
73
                    self.curr_cmd = ''
74
            if 'block' in ln:
75
                # throw away a partial command.
76
                self.curr_cmd = ''
77
                try:
78
                    cmd = compile(ln['block'], "<web session>", 'exec');
79
                    
212 by drtomc
Gosh, it all looks pretty simple in the end!
80
                    sys.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
81
                    self.out = cStringIO.StringIO()
212 by drtomc
Gosh, it all looks pretty simple in the end!
82
                    sys.stdout = out
83
                    sys.stderr = out
84
                    signal.alarm(5)
85
                    res = eval(cmd, globs, locls)
86
                    signal.alarm(0)
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
87
                    self.cmdQ.put({"okay":(self.out.getvalue(),res)})
88
                    self.curr_cmd = ''
89
                except Exception, exc:
90
                    signal.alarm(0)
91
                    self.cmdQ.put({"exc":(self.out.getvalue(),str(exc))})
212 by drtomc
Gosh, it all looks pretty simple in the end!
92
263 by drtomc
A few little cleanups.
93
    def init_state(self):
94
        self.globs = {}
95
        self.globs['__builtins__'] = globals()['__builtins__']
96
        self.locls = {}
97
        self.curr_cmd = ''
98
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
99
urls = (
100
    '/',            'index',
126 by drtomc
A basic version of the console going!
101
    '/index.html',  'index',
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
102
    '/(.*\.js)',    'jscript',
103
    '/(.*\.css)',   'style',
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
104
    '/chat',        'chat',
105
    '/block',       'block')
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
106
107
# The global 'magic' is the secret that the client and server share
108
# which is used to create and md5 digest to authenticate requests.
109
# It is assigned a real value at startup.
110
magic = ''
111
112
class index:
113
    def GET(self):
114
        inp = web.input()
115
116
        # Authenticate
117
        digest = md5.new('hello' + magic).digest().encode('hex')
118
        if inp.digest != digest:
119
            web.ctx.status = '401 Unauthorized'
120
            return
121
122
        # Okay, so the authentication succeeded,
123
        # so all we need to do is send back the static
124
        # HTML for the console app.
125
        web.output(file("index.html", "r").read())
126
127
class jscript:
128
    def GET(self, name):
129
        web.output(file(name, "r").read())
130
131
class style:
132
    def GET(self, name):
133
        web.output(file(name, "r").read())
134
135
class chat:
212 by drtomc
Gosh, it all looks pretty simple in the end!
136
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
137
    def POST(self):
138
        inp = web.input()
139
140
        # Authenticate
141
        digest = md5.new(inp.text + magic).digest().encode('hex')
142
        if inp.digest != digest:
275 by mattgiuca
python-console: If unauthorized, prints "401 Unauthorized" instead of nothing
143
            web.output("401 Unauthorized")
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
144
            web.ctx.status = '401 Unauthorized'
145
            return
146
147
        # Okay, so the authentication succeeded,
148
        # so now we have the trivial matter of actually
149
        # executing the python....
340 by drtomc
Mostly fix the block-of-text to the console problem. The tutorial system should call "block" rather than "chat" to send the block of text.
150
        lineQ.put({'chat':inp.text})
151
        r = cmdQ.get()
152
        sys.__stderr__.write(cjson.encode(r) + "\n")
153
        web.output(cjson.encode(r))
154
155
class block:
156
157
    def POST(self):
158
        inp = web.input()
159
160
        # Authenticate
161
        digest = md5.new(inp.text + magic).digest().encode('hex')
162
        if inp.digest != digest:
163
            web.output("401 Unauthorized")
164
            web.ctx.status = '401 Unauthorized'
165
            return
166
167
        # Okay, so the authentication succeeded,
168
        # so now we have the trivial matter of actually
169
        # executing the python....
170
        lineQ.put({'block':inp.text})
212 by drtomc
Gosh, it all looks pretty simple in the end!
171
        r = cmdQ.get()
172
        sys.__stderr__.write(cjson.encode(r) + "\n")
173
        web.output(cjson.encode(r))
174
175
cmdQ = Queue.Queue()
176
lineQ = Queue.Queue()
177
interpThread = PythonRunner(cmdQ, lineQ)
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
178
179
if __name__ == "__main__":
180
    magic = sys.argv[2]
264 by drtomc
Fix the "Aaarrgghh! ^C doesn't work problem". The multiple console process
181
    interpThread.setDaemon(True)
212 by drtomc
Gosh, it all looks pretty simple in the end!
182
    interpThread.start()
95 by mattgiuca
Moved some things out of www into their respective dirs, console and
183
    web.run(urls, globals())