annot-server/websockets.py
author ymh <ymh.work@gmail.com>
Wed, 08 Oct 2014 15:14:58 +0200
changeset 0 e1d4d7a8255a
child 23 16a1925df2df
permissions -rw-r--r--
First shareable version
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
#
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
# See LICENCE for detail
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
# Copyright (c) 2014 IRI
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
#
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
import json
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
from autobahn.twisted.websocket import WebSocketServerFactory, \
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
                                       WebSocketServerProtocol
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
from autobahn.websocket import http
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
from baseserver import BaseProtocol
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
import utils
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
class BroadcastServerProtocol(WebSocketServerProtocol):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
    def onConnect(self, request):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
        if request.params:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
            self.factory.registerFilter(self, request.params)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
    def onOpen(self):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
        self.factory.register(self)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
    def onMessage(self, payload, isBinary):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
        if not isBinary:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
            msg = "{} from {}".format(payload.decode('utf8'), self.peer)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
            self.factory.broadcast(msg)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
    def connectionLost(self, reason):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
        WebSocketServerProtocol.connectionLost(self, reason)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
        self.factory.unregister(self)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
class BroadcastServerFactory(WebSocketServerFactory):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
    """
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
    Simple broadcast server broadcasting any message it receives to all
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
    currently connected clients.
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
    """
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
    def __init__(self, url, debug = False, debugCodePaths = False):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
        WebSocketServerFactory.__init__(self, url, debug = debug, debugCodePaths = debugCodePaths)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
        self.clients = []
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
        self.filters = {}
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
        self.protocol = BroadcastServerProtocol
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
    def registerFilter(self, client, filter):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
        print("registered filter {} for client {}".format(repr(filter),client.peer))
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
        self.filters[client] = filter
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
    def register(self, client):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
        if not client in self.clients:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
             print("registered client {}".format(client.peer))
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
             self.clients.append(client)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
    def unregister(self, client):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
        if client in self.clients:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
            print("unregistered client {}".format(client.peer))
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
            self.clients.remove(client)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
        if client in self.filters:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
            self.filters.pop(client, None)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
    def broadcast(self, msg, filter):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
        print("broadcasting prepared message '{}' ..".format(msg))
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
        #preparedMsg = self.prepareMessage(msg)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
        for c in self.clients:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
            preparedMsg = self.prepareMessage(msg)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
            if all([ (k in filter and filter[k] in v) for k,v in self.filters.get(c, {}).items()]):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
                c.sendPreparedMessage(preparedMsg)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
                print("prepared message sent to {}".format(c.peer))
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
class AnnotationServerProtocol(WebSocketServerProtocol, BaseProtocol):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
    def onConnect(self, request):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
        event_ids = request.params.get('event', [])
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
        if not event_ids or not event_ids[0]:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
            raise http.HttpException(400, "The event parameter is missing")
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
        self.event = event_ids[0]
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
        self._init_props(self.factory.ws_factory, self.factory.conn)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
    #TODO: add error handling
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
    def onMessage(self, payload, isBinary):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
        if isBinary:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
            return
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
        msg = payload.decode('utf8')
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
        params_annot = json.loads(msg)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
        params = {
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
            'event': self.event,
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
            'channel' : utils.ANNOTATION_CHANNEL,
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
            'content' : params_annot
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
        }
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
        def error_callback(failure):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
            raise http.HttpException(500,"Error when processing message : %r" % failure)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
        def annot_callback(res):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
            if 'ts' in res:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
                res['ts'] = res['ts'].isoformat()+'Z'
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
            if 'uuid' in res:
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
                res['uuid'] = str(res['uuid'])
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
            self.sendMessage(json.dumps(res))
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
        defer = self.process_annotation(params)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
        defer.addErrback(error_callback)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
        defer.addCallback(annot_callback)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
class AnotationServerFactory(WebSocketServerFactory):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
    def __init__(self, url, ws_factory, conn, debug = False, debugCodePaths = False):
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
        WebSocketServerFactory.__init__(self, url, debug = debug, debugCodePaths = debugCodePaths)
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
        self.ws_factory = ws_factory
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
        self.conn = conn
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
        self.clients = {}
e1d4d7a8255a First shareable version
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
        self.protocol = AnnotationServerProtocol