Completed
Push — master ( 275057...223d4e )
by
unknown
10s
created

ClientWSConnection.open()   A

Complexity

Conditions 4

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.2
cc 4
1
#-*- coding = utf-8 -*-
2
import tornado.web
3
import json
4
from tornado import websocket
5
6
# General modules.
7
import logging
8
9
"""
10
    Django send messages to all the others
11
    A client has a WebSocketConection with this process
12
    This connection has to be authorised -> Token/other : how to check that the user is authorised ? ChatHandler has a list of authorized tokens
13
    Connections only accept messages from Django
14
    
15
    Proccess : 
16
        - User logs in -> Django send token to MainHandler
17
        - User sent message -> Django save it and give it to the MainHandler, which gives it to the appropriated connections -> clients
18
        - User logs out -> Django tell MainHandler to remove the token from the list
19
"""
20
class MainHandler(tornado.web.RequestHandler):
21
22
    def initialize(self, chat_handler):
23
        """Store a reference to the "external" ChatHandler instance"""
24
        self.__ch = chat_handler
25
26
    def _get_current_user(self, param, callback):
27
        """
28
        Check if the message really originates from Django.
29
        """
30
        try:
31
            secret = self.get_query_argument("secret_key")
32
            if(secret == ""):
33
                #add user to the chat he is member of
34
                self._current_user = "Django"
35
                print("Right user.")
36
                print(self.request)
37
                print(self.request.arguments)
38
                print(self.get_argument("message", strip=False))
39
                param = json.loads(self.get_argument("message", strip=False))
40
                print(param)
41
                callback(param)
42
                print("Callback called.")
43
                self.set_status(200, "All right")
44
                print("get current user finished")
45
                return
46
            else:
47
                print("request not from Django")
48
                self._current_user = None
49
                self.set_status(403, "You are not authorised to access this server.")
50
                self.finish()
51
        except tornado.web.MissingArgumentError:
52
            print("request not from Django")
53
            self._current_user = None
54
            self.set_status(403, "You are not authorised to access this server.")
55
            self.finish()
56
57
    def get(self, token=None):
58
        """
59
            Add a client to the list of authorized ones
60
        """
61
        if not token:
62
            self.set_status(403, "You are not authorised to access this server.")
63
        # Get the current user.
64
        self._get_current_user(param=token, callback=self.__ch.add_potential_client)
65
        print("get finish.")
66
67
    def post(self, message=None):
68
        """
69
            Post a message from Django
70
        """
71
        print("Get method called")
72
        if not message:
73
            self.set_status(400, "Bad Request.")
74
            self.finish()
75
        print("Get Method successfully called")
76
        # Get the current user.
77
        self._get_current_user(param=message, callback=self.__ch.add_message)
78
        print("post finish.")
79
        self.set_status(200, "All right")
80
        print("post not finished yet")
81
        return
82
83
    def delete(self, token=None):
84
        """
85
            Remove a client from the list of authorized ones
86
        """
87
        if not token:
88
            self.set_status(403, "You are not authorised to access this server.")
89
            self.finish()
90
        # Get the current user.
91
        self._get_current_user(param=token, callback=self.__ch.remove_potential_client)
92
        self.finish()
93
94
95
class ClientWSConnection(websocket.WebSocketHandler):
96
 
97
    def initialize(self, chat_handler):
98
        """Store a reference to the "external" ChatHandler instance"""
99
        self.__ch = chat_handler
100
 
101
    def open(self, token):
102
        for user in self.__ch.authorized_tokens:
103
            if user.token == token.token and user.user.id == token.user_id:
104
                self.__ch.add_client_wsconn(user, self)
105
                print("WebSocket opened. ClientID = %s" % self.__token.user_id)
106
                break
107
        self.close(reason="You are not allowed to establish a connection with this server.", code=403)
108
 
109
    def on_message(self, message):
110
        print("Try to send a message the wrong way.")
111
 
112
    def on_close(self):
113
        print("WebSocket closed")
114
        self.__ch.remove_client(self.__token.user_id)
115
116
"""
117
    Needs:
118
        - authorized_tokens = [{'token': token, 'user': user}]
119
        - add_potential_client({'token': token, 'user': user})
120
        - add_client_wsconn(user, ClientWSConnection)
121
        - remove_client(user_id)
122
        - remove_potential_client({'token': token, 'user': user})
123
        - add_message(message)
124
        - chatemate_cwsconns(user_id)
125
        - send_is_connected_msg(user_id)
126
        - send_is_disconnected_msg(user_id)
127
"""
128
class ChatHandler(object):
129
    """Store data about connections, chats, which users are in which chats, etc."""
130
 
131
    def __init__(self):
132
        self.authorized_tokens = []  # store the list of {'token': token, 'user': user}
133
        self.user_connections = {} # dict  to store 'user_id': {'wsconn": wsconn, 'chats': [chat_id1, chat_id2]}
134
        self.chatmates = {}  # store a set for each chat, each contains the id of the clients in the room.
135
 
136
    def add_potential_client(self, token):
137
        """Add potential client to chat."""
138
        self.authorized_tokens.append(token)
139
 
140
    def add_client_wsconn(self, user, conn):
141
        """Store the websocket connection corresponding to an authorized client."""
142
        self.user_connections[user.id]['wsconn'] = conn
143
        self.user_connections[user.id]['chats'] = []
144
 
145
        # for each chat this user is member of, add the user to the chatmates of the chat
146
        for chatmember in user.user_chatmember:
147
            self.chatmates[chatmember.chat.id].add(user.id)
148
            self.user_connections[user.id]['chats'].append(chatmember.chat.id)
149
150
        # send "is_connected" messages
151
        self.send_is_connected_msg(user.id)
152
 
153
    def remove_client(self, user_id):
154
        """Remove all client information from the chat handler."""
155
        # first, remove the client connection from the corresponding chat in self.chatmates
156
        chats = self.user_connections[user_id]
157
        self.send_is_disconnected_msg(user_id)
158
        for chat_id in chats:
159
            self.chatmates[chat_id].discard(user_id)
160
        del self.user_connections[user_id]
161
 
162
    def remove_potential_client(self, token):
163
        """Remove potential client from chat."""
164
        del self.authorized_tokens[token]
165
        remove_client(token.user.id)
166
167
    def add_message(self, message):
168
        print('begin of the add_message method')
169
        print(message)
170
        print(message['chat'])
171
        print(message['chat']['id'])
172
        rconns = self.chatmate_cwsconns(message['chat']['id'])
173
        print(rconns)
174
        for conn in rconns:
175
            conn.write_message(message)
176
            print("Message sent")
177
        print("end of the sent messages");
178
 
179
    def chatmate_cwsconns(self, chat_id):
180
        """Return a list with the connections of the users currently connected to the specified chat."""
181
        print('begin of the chatmate_cwsconns method.')
182
        print(self.chatmates)
183
        if chat_id in self.chatmates:
184
            print("found")
185
            return self.chatmates[chat_id]
186
        else:
187
            print('not found')
188
            return []
189
 
190
    def send_is_connected_msg(self, user_id):
191
        """Send a message of type 'is_connected' to all users connected to the chat where user_id is connected."""
192
        r = set()
193
        #for every chat the user is part of
194
        for chat in self.user_connections[user_id]['chats']:
195
            #add the other members of the chat to the list of receivers
196
            r.update(self.chatmate_cwsconns(chat))
197
        msg = {"msgtype": "is_connected", "username": user_id}
198
        pmessage = json.dumps(msg)
199
        for conn in r_cwsconns:
200
            conn.write_message(pmessage)
201
 
202
    def send_is_disconnected_msg(self, user_id):
203
        """Send a message of type 'is_disconnected' to all users connected to the chat where user_id is disconnected."""
204
        r = set()
205
        #for every chat the user is part of
206
        for chat in self.user_connections[user_id]['chats']:
207
            #add the other members of the chat to the list of receivers
208
            r.update(self.chatmate_cwsconns(chat))
209
        msg = {"msgtype": "is_disconnected", "username": user_id}
210
        pmessage = json.dumps(msg)
211
        for conn in r_cwsconns:
212
            conn.write_message(pmessage)
213