~benji/charms/precise/juju-gui/fix-cache-headers

« back to all changes in this revision

Viewing changes to server/guiserver/clients.py

  • Committer: Benji York
  • Date: 2013-07-31 22:08:34 UTC
  • mfrom: (60.13.9 noncharmers)
  • Revision ID: benji.york@canonical.com-20130731220834-hr78mvsri3ou0x59
mergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This file is part of the Juju GUI, which lets users view and manage Juju
 
2
# environments within a graphical interface (https://launchpad.net/juju-gui).
 
3
# Copyright (C) 2013 Canonical Ltd.
 
4
#
 
5
# This program is free software: you can redistribute it and/or modify it under
 
6
# the terms of the GNU Affero General Public License version 3, as published by
 
7
# the Free Software Foundation.
 
8
#
 
9
# This program is distributed in the hope that it will be useful, but WITHOUT
 
10
# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
 
11
# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
# Affero General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU Affero General Public License
 
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 
 
17
"""Juju GUI server websocket clients."""
 
18
 
 
19
from tornado import (
 
20
    concurrent,
 
21
    httpclient,
 
22
    websocket,
 
23
)
 
24
 
 
25
 
 
26
def websocket_connect(io_loop, url, on_message_callback, headers=None):
 
27
    """WebSocket client connection factory.
 
28
 
 
29
    The client factory receives the following arguments:
 
30
        - io_loop: the Tornado IO loop instance;
 
31
        - url: the WebSocket URL to use for the connection;
 
32
        - on_message_callback: a callback that will be called each time
 
33
          a new message is received by the client;
 
34
        - headers (optional): a dict of additional headers to include in the
 
35
          client handshake.
 
36
 
 
37
    Return a Future whose result is a WebSocketClientConnection.
 
38
    """
 
39
    request = httpclient.HTTPRequest(
 
40
        url, validate_cert=False, request_timeout=100)
 
41
    if headers is not None:
 
42
        request.headers.update(headers)
 
43
    conn = WebSocketClientConnection(io_loop, request, on_message_callback)
 
44
    return conn.connect_future
 
45
 
 
46
 
 
47
class WebSocketClientConnection(websocket.WebSocketClientConnection):
 
48
    """WebSocket client connection supporting secure WebSockets.
 
49
 
 
50
    Use this connection as described in
 
51
    <http://www.tornadoweb.org/en/stable/websocket.html#client-side-support>.
 
52
    """
 
53
 
 
54
    def __init__(self, io_loop, request, on_message_callback):
 
55
        """Client initializer.
 
56
 
 
57
        The WebSocket client receives all the arguments accepted by
 
58
        tornado.websocket.WebSocketClientConnection and a callback that will be
 
59
        called each time a new message is received by the client.
 
60
        """
 
61
        super(WebSocketClientConnection, self).__init__(io_loop, request)
 
62
        self._on_message_callback = on_message_callback
 
63
        self.close_future = concurrent.Future()
 
64
 
 
65
    def on_message(self, message):
 
66
        """Hook called when a new message is received.
 
67
 
 
68
        The on_message_callback is called passing it the message.
 
69
        """
 
70
        super(WebSocketClientConnection, self).on_message(message)
 
71
        self._on_message_callback(message)
 
72
 
 
73
    def close(self):
 
74
        """Close the client connection.
 
75
 
 
76
        Return a Future that is fired when the connection is terminated.
 
77
        """
 
78
        self.stream.close()
 
79
        return self.close_future
 
80
 
 
81
    def _on_close(self):
 
82
        """Fire the close_future and send a None message."""
 
83
        super(WebSocketClientConnection, self)._on_close()
 
84
        # Since this is just a notification the Future result is set to None.
 
85
        self.close_future.set_result(None)