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

418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
1
#!/usr/bin/python
2
3
# usage:
603 by mattgiuca
Console now starts up in the user's home directory.
4
#   python-console <port> <magic> [<working-dir>]
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
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
526 by drtomc
python-console: trivial bugfix - missing import.
15
from functools import partial
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
16
432 by drtomc
usrmgt: more work on this. Still some work to go.
17
import common.chat
18
598 by drtomc
console: send output back to the browser progressively.
19
class Interrupt(Exception):
628 by drtomc
console: Add output based interrupt. This allows users to interrupt long
20
    def __init__(self):
21
        Exception.__init__(self, "Interrupted!")
598 by drtomc
console: send output back to the browser progressively.
22
522 by drtomc
Add quite a lot of stuff to get usrmgt happening.
23
class ExpiryTimer(object):
24
    def __init__(self, idle):
25
        self.idle = idle
564 by drtomc
python-console: Fix the timeout code.
26
        signal.signal(signal.SIGALRM, partial(self.timeout))
522 by drtomc
Add quite a lot of stuff to get usrmgt happening.
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
        
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
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})
522 by drtomc
Add quite a lot of stuff to get usrmgt happening.
47
        expiry.ping()
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
48
        ln = self.lineQ.get()
49
        if 'chat' in ln:
50
            return ln['chat']
648 by drtomc
console: fix a trivial bug which caused it to loop if you got a syntax error in your first command.
51
        if 'interrupt' in ln:
52
            raise Interrupt()
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
53
598 by drtomc
console: send output back to the browser progressively.
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):
641 by drtomc
console: slightly more aggressive output buffering - wait till we've at least
61
        # if there's less than 1K, buffer
62
        if len(self.remainder) + len(stuff) < 128:
63
            self.remainder = self.remainder + stuff
64
            return
65
598 by drtomc
console: send output back to the browser progressively.
66
        # Split the content up into lines, and ship all the completed
67
        # lines off to the server.
68
        lines = stuff.split("\n")
69
        lines[0] = self.remainder + lines[0]
70
        self.remainder = lines[-1]
71
        del lines[-1]
72
73
        if len(lines) > 0:
599 by drtomc
console: improve end of line handling.
74
            lines.append('')
75
            text = "\n".join(lines)
76
            self.cmdQ.put({"output":text})
598 by drtomc
console: send output back to the browser progressively.
77
            expiry.ping()
78
            ln = self.lineQ.get()
79
            if 'interrupt' in ln:
80
                raise Interrupt()
81
82
    def flush(self):
599 by drtomc
console: improve end of line handling.
83
        if len(self.remainder) > 0:
84
            self.cmdQ.put({"output":self.remainder})
85
            expiry.ping()
86
            ln = self.lineQ.get()
87
            self.remainder = ''
88
            if 'interrupt' in ln:
89
                raise Interrupt()
598 by drtomc
console: send output back to the browser progressively.
90
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
91
class PythonRunner(Thread):
92
    def __init__(self, cmdQ, lineQ):
93
        self.cmdQ = cmdQ
94
        self.lineQ = lineQ
648 by drtomc
console: fix a trivial bug which caused it to loop if you got a syntax error in your first command.
95
        self.stdout = StdoutToWeb(self.cmdQ, self.lineQ)
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
96
        Thread.__init__(self)
97
98
    def execCmd(self, cmd):
99
        try:
100
            sys.stdin = StdinFromWeb(self.cmdQ, self.lineQ)
599 by drtomc
console: improve end of line handling.
101
            sys.stdout = self.stdout
102
            sys.stderr = self.stdout
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
103
            res = eval(cmd, self.globs, self.locls)
599 by drtomc
console: improve end of line handling.
104
            self.stdout.flush()
105
            self.cmdQ.put({"okay":res})
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
106
            self.curr_cmd = ''
107
        except Exception, exc:
599 by drtomc
console: improve end of line handling.
108
            self.stdout.flush()
109
            self.cmdQ.put({"exc":str(exc)})
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
110
            self.curr_cmd = ''
111
112
    def run(self):
598 by drtomc
console: send output back to the browser progressively.
113
        self.globs = {}
114
        self.globs['__builtins__'] = globals()['__builtins__']
115
        self.locls = {}
116
        self.curr_cmd = ''
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
117
        compiler = codeop.CommandCompiler()
118
119
        while True:
120
            ln = self.lineQ.get()
121
            if 'chat' in ln:
122
                if self.curr_cmd == '':
123
                    self.curr_cmd = ln['chat']
124
                else:
125
                    self.curr_cmd = self.curr_cmd + '\n' + ln['chat']
126
                try:
127
                    cmd = compiler(self.curr_cmd)
128
                    if cmd is None:
129
                        # The command was incomplete,
130
                        # so send back a None, so the
131
                        # client can print a '...'
132
                        self.cmdQ.put({"more":None})
133
                    else:
134
                        self.execCmd(cmd)
135
                except Exception, exc:
599 by drtomc
console: improve end of line handling.
136
                    self.stdout.flush()
137
                    self.cmdQ.put({"exc":str(exc)})
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
138
                    self.curr_cmd = ''
139
            if 'block' in ln:
140
                # throw away a partial command.
141
                try:
142
                    cmd = compile(ln['block'], "<web session>", 'exec');
143
                    self.execCmd(cmd)
144
                except Exception, exc:
599 by drtomc
console: improve end of line handling.
145
                    self.stdout.flush()
146
                    self.cmdQ.put({"exc":str(exc)})
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
147
                    self.curr_cmd = ''
148
149
def daemonize():
150
    if os.fork():   # launch child and...
151
        os._exit(0) # kill off parent
152
    os.setsid()
153
    if os.fork():   # launch child and...
154
        os._exit(0) # kill off parent again.
155
    os.umask(077)
156
157
# The global 'magic' is the secret that the client and server share
158
# which is used to create and md5 digest to authenticate requests.
159
# It is assigned a real value at startup.
160
magic = ''
161
162
cmdQ = Queue.Queue()
163
lineQ = Queue.Queue()
164
interpThread = PythonRunner(cmdQ, lineQ)
165
522 by drtomc
Add quite a lot of stuff to get usrmgt happening.
166
# Default expiry time of 15 minutes
167
expiry = ExpiryTimer(15 * 60)
168
432 by drtomc
usrmgt: more work on this. Still some work to go.
169
def initializer():
170
    interpThread.setDaemon(True)
171
    interpThread.start()
522 by drtomc
Add quite a lot of stuff to get usrmgt happening.
172
    expiry.ping()
432 by drtomc
usrmgt: more work on this. Still some work to go.
173
174
def dispatch_msg(msg):
522 by drtomc
Add quite a lot of stuff to get usrmgt happening.
175
    expiry.ping()
432 by drtomc
usrmgt: more work on this. Still some work to go.
176
    lineQ.put({msg['cmd']:msg['text']})
177
    return cmdQ.get()
178
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
179
if __name__ == "__main__":
180
    port = int(sys.argv[1])
181
    magic = sys.argv[2]
603 by mattgiuca
Console now starts up in the user's home directory.
182
    if len(sys.argv) >= 4:
183
        # working_dir
184
        os.chdir(sys.argv[3])
418 by mattgiuca
Renamed trunk/console to trunk/scripts. We are now able to put more scripts in
185
432 by drtomc
usrmgt: more work on this. Still some work to go.
186
    common.chat.start_server(port, magic, True, dispatch_msg, initializer)