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

« back to all changes in this revision

Viewing changes to ivle/chat.py

  • Committer: mattgiuca
  • Date: 2008-01-31 01:44:30 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:345
Global CSS change: ivlebody no longer has 1em of padding (it has none).
This is because most apps were disabling it (and it had to change anyway for
other reasons -- see below).

Hence, all apps which WERE disabling the padding have had that removed, and
just work by default. (console, browser, tutorial)
All apps which WEREN'T disabling the padding (very few) now have to manually
include an extra div. This has been done on all such apps, and has been
heavily documented (both in the CSS file and doc/app_howto). (help, dummy,
debuginfo).

media/common/ivle.css: 
    The real change here (which isn't yet being used) is that ivlebody is now
    positioned absolutely and takes up all the space on the canvas. This is
    to be used for full-page layouts in console and browser.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# IVLE - Informatics Virtual Learning Environment
2
 
# Copyright (C) 2007-2008 The University of Melbourne
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
 
 
18
 
# Module: Chat
19
 
# Author: Thomas Conway
20
 
# Date:   5/2/2008
21
 
 
22
 
import cjson
23
 
import cStringIO
24
 
import hashlib
25
 
import sys
26
 
import os
27
 
import socket
28
 
import traceback
29
 
 
30
 
SOCKETTIMEOUT = 60
31
 
BLOCKSIZE = 1024
32
 
 
33
 
class Terminate(Exception):
34
 
    """Exception thrown when server is to be shut down. It will attempt to
35
 
    send the final_response to the client and then exits"""
36
 
    def __init__(self, final_response=None):
37
 
        self.final_response = final_response
38
 
 
39
 
    def __str__(self):
40
 
        return repr(self.final_response)
41
 
 
42
 
class ProtocolError(Exception):
43
 
    """Exception thrown when client violates the the chat protocol"""
44
 
    pass
45
 
 
46
 
def start_server(port, magic, daemon_mode, handler, initializer = None):
47
 
    # Attempt to open the socket.
48
 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
49
 
    s.bind(('', port))
50
 
    s.listen(1)
51
 
 
52
 
    # Excellent! It worked. Let's turn ourself into a daemon,
53
 
    # then get on with the job of being a python interpreter.
54
 
    if daemon_mode:
55
 
        if os.fork():   # launch child and...
56
 
            os._exit(0) # kill off parent
57
 
        os.setsid()
58
 
        if os.fork():   # launch child and...
59
 
            os._exit(0) # kill off parent again.
60
 
        os.umask(077)
61
 
 
62
 
        try:
63
 
            MAXFD = os.sysconf("SC_OPEN_MAX")
64
 
        except:
65
 
            MAXFD = 256
66
 
 
67
 
        # Close all file descriptors, except the socket.
68
 
        for i in xrange(MAXFD):
69
 
            if i == s.fileno():
70
 
                continue
71
 
            try:
72
 
                os.close(i)
73
 
            except OSError:
74
 
                pass
75
 
 
76
 
        si = os.open(os.devnull, os.O_RDONLY)
77
 
        os.dup2(si, sys.stdin.fileno())
78
 
 
79
 
        so = os.open(os.devnull, os.O_WRONLY)
80
 
        os.dup2(so, sys.stdout.fileno())
81
 
 
82
 
        se = os.open(os.devnull, os.O_WRONLY)
83
 
        os.dup2(se, sys.stderr.fileno())
84
 
 
85
 
    if initializer:
86
 
        initializer()
87
 
 
88
 
    while True:
89
 
        (conn, addr) = s.accept()
90
 
        conn.settimeout(SOCKETTIMEOUT)
91
 
        try:
92
 
            # Grab the input and try to decode
93
 
            inp = recv_netstring(conn)
94
 
            try:
95
 
                content = decode(inp, magic)
96
 
            except ProtocolError:
97
 
                conn.close()
98
 
                continue
99
 
 
100
 
            response = handler(content)
101
 
 
102
 
            send_netstring(conn, cjson.encode(response))
103
 
 
104
 
            conn.close()
105
 
 
106
 
        except Terminate, t:
107
 
            # Try and send final response and then terminate
108
 
            if t.final_response:
109
 
                send_netstring(conn, cjson.encode(t.final_response))
110
 
            conn.close()
111
 
            sys.exit(0)
112
 
        except Exception:
113
 
            # Make a JSON object full of exceptional goodness
114
 
            tb_dump = cStringIO.StringIO()
115
 
            e_type, e_val, e_tb = sys.exc_info()
116
 
            traceback.print_tb(e_tb, file=tb_dump)
117
 
            json_exc = {
118
 
                "type": e_type.__name__,
119
 
                "value": str(e_val),
120
 
                "traceback": tb_dump.getvalue()
121
 
            }
122
 
            send_netstring(conn, cjson.encode(json_exc))
123
 
            conn.close()
124
 
 
125
 
 
126
 
def chat(host, port, msg, magic, decode = True):
127
 
    sok = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
128
 
    sok.connect((host, port))
129
 
    sok.settimeout(SOCKETTIMEOUT)
130
 
 
131
 
    json = encode(msg, magic)
132
 
 
133
 
    send_netstring(sok, json)
134
 
    inp = recv_netstring(sok)
135
 
 
136
 
    sok.close()
137
 
 
138
 
    if decode:
139
 
        return cjson.decode(inp)
140
 
    else:
141
 
        return inp
142
 
 
143
 
def encode(message, magic):
144
 
    """Converts a message into a JSON serialisation and uses a magic
145
 
    string to attach a HMAC digest.
146
 
    """
147
 
    # XXX: Any reason that we double encode?
148
 
    content = cjson.encode(message)
149
 
 
150
 
    digest = hashlib.md5(content + magic).hexdigest()
151
 
    env = {'digest':digest,'content':content}
152
 
    json = cjson.encode(env)
153
 
 
154
 
    return json
155
 
 
156
 
 
157
 
def decode(message, magic):
158
 
    """Takes a message with an attached HMAC digest and validates the message.
159
 
    """
160
 
    msg = cjson.decode(message)
161
 
 
162
 
    # Check that the message is valid
163
 
    digest = hashlib.md5(msg['content'] + magic).hexdigest()
164
 
    if msg['digest'] != digest:
165
 
        raise ProtocolError("HMAC digest is invalid")
166
 
    content = cjson.decode(msg['content'])
167
 
 
168
 
    return content
169
 
 
170
 
 
171
 
def send_netstring(sok, data):
172
 
    """ Sends a netstring to a socket
173
 
    """
174
 
    netstring = "%d:%s,"%(len(data),data)
175
 
    sok.sendall(netstring)
176
 
 
177
 
 
178
 
def recv_netstring(sok):
179
 
    """ Attempts to recieve a Netstring from a socket.
180
 
    Throws a ProtocolError if the received data violates the Netstring 
181
 
    protocol.
182
 
    """
183
 
    # Decode netstring
184
 
    size_buffer = []
185
 
    c = sok.recv(1)
186
 
    while c != ':':
187
 
        # Limit the Netstring to less than 10^10 bytes (~1GB).
188
 
        if len(size_buffer) >= 10:
189
 
            raise ProtocolError(
190
 
                    "Could not read Netstring size in first 9 bytes: '%s'"%(
191
 
                    ''.join(size_buffer)))
192
 
        size_buffer.append(c)
193
 
        c = sok.recv(1)
194
 
    try:
195
 
        # Message should be length plus ',' terminator
196
 
        recv_expected = int(''.join(size_buffer)) + 1
197
 
    except ValueError, e:
198
 
        raise ProtocolError("Could not decode Netstring size as int: '%s'"%(
199
 
                ''.join(size_buffer)))
200
 
 
201
 
    # Read data
202
 
    buf = []
203
 
    recv_data = sok.recv(min(recv_expected, BLOCKSIZE))
204
 
    recv_size = len(recv_data)
205
 
    while recv_size < recv_expected:
206
 
        buf.append(recv_data)
207
 
        recv_data = sok.recv(min(recv_expected-recv_size, 1024))
208
 
        recv_size = recv_size + len(recv_data)
209
 
    assert(recv_size == recv_expected)
210
 
 
211
 
    # Did we receive the correct amount?
212
 
    if recv_data[-1] != ',':
213
 
        raise ProtocolError("Netstring did not end with ','")
214
 
    buf.append(recv_data[:-1])
215
 
 
216
 
    return ''.join(buf)