-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiscovery_server.py
115 lines (95 loc) · 4.04 KB
/
discovery_server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import socket
from typing import List
from logger import get_logger
from user import User, CurrentUser
BUFFER_SIZE = 1024
server_hostname = 'vega.ii.uam.es'
server_port = 8000
class RegisterFailed(Exception):
def __init__(self):
super().__init__("Register failed")
class UserUnknown(Exception):
def __init__(self, nick: str):
super().__init__(f"User {nick} was not found")
class BadUser(Exception):
def __init__(self, nick: str):
super().__init__(f"Couldn't parse {nick} information")
def _send(message: bytes, end_char: chr = None) -> str:
"""
Sends a message to the Discovery Server
:param message: message encoded in bytes to be sent
:return: response of the server
"""
return_string = ""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as connection:
connection.connect((socket.gethostbyname(server_hostname), server_port))
connection.send(message)
get_logger().debug(f"Sent {message} to discovery server")
response = connection.recv(BUFFER_SIZE)
return_string += response.decode()
if end_char:
connection.setblocking(False)
while chr(response[-1]) != end_char:
try:
response = connection.recv(BUFFER_SIZE)
return_string += response.decode()
except BlockingIOError:
pass
connection.send("QUIT".encode())
get_logger().debug(f"Received {return_string} from discovery server")
return return_string
def register():
"""
Registers the current user in the system with the specified parameters
:raise RegisterFailed
"""
user = CurrentUser()
string_to_send = f"REGISTER {user.nick} {user.ip} {user.tcp_port} {user.password} {'#'.join(user.protocols)}"
response = _send(string_to_send.encode()).split()
if response[0] == "NOK":
get_logger().warning(f"Error registering user {user.nick}: {response}")
raise RegisterFailed
get_logger().info(f"Successfully registered user {user.nick}")
def get_user(nick: str) -> User:
"""
Gets the IP, port and protocols of the user with the specified nickname
:param nick
:return: User
:raise UserUnknown if user is not found
"""
string_to_send = f"QUERY {nick}"
response = _send(string_to_send.encode()).split()
if response[0] == "NOK":
get_logger().warning(f"Error getting username: {response}")
raise UserUnknown(nick)
else:
try:
user = User(nick, ip=response[3], tcp_port=int(response[4]), protocols=response[5])
get_logger().info(f"Successfully fetched user {nick}")
return user
except Exception:
get_logger().warning(f"Error getting username: {response}")
raise BadUser(nick)
def list_users() -> List[User]:
"""
Gets a list of all the users
:return: list of users.
"""
"""Response contains something like OK USERS_LIST N_USERS user1#... So to get the actual list of users,
we look for N_USERS and start splitting the list from there. Afterwards, we get a list with all the info
of each user in a string (users_str), so we need to split again each user to get a list of the needed values"""
response = _send("LIST_USERS".encode(), end_char='#')
n_users = response.split()[2]
start_index = response.find(n_users) + len(n_users) + 1 # The number itself and the white space
users_str = response[start_index:].split('#')[:-1] # Avoid final empty element
users_splitted = [user.split() for user in users_str]
users = []
for user in users_splitted:
try:
# Protocols is not answered by the server, ts instead. Since we do not use the info, we set it to V0
users.append(User(nick=user[0], ip=user[1], tcp_port=int(float(user[2])), protocols="V0"))
except Exception as e:
get_logger().warning(f"Error parsing user: {e}")
pass
get_logger().info(f"Successfully parsed {len(users)} users out of {n_users}")
return users