-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
183 lines (162 loc) · 5.76 KB
/
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import socket
import os
import ssl
import select
import sys
import commands
import parsers
import clients
import string
import protocols
import logging
class Server(object):
"""The chat server. It relays communication between client."""
_port = 0
_bind = ""
_parser = None
_server_client = None
_clients = []
_encoders = []
_ssl_configuration = {}
@property
def port(self):
return self._port
@port.setter
def port(self, value):
self._port = int(value)
@property
def bind(self):
return self._bind
@bind.setter
def bind(self, value):
self._bind = value
@property
def parser(self):
return self._parser
@parser.setter
def parser(self, value):
if isinstance(value, parsers.Parser):
self._parser = value
else:
try:
self.parser = parsers.get_parser(value)
except NameError as e:
raise ValueError("parser value '"+str(value)+"' must be an instance of parsers.Parser or a string allowed by parsers.get_parser.")
@property
def server_client(self):
return self._server_client
@server_client.setter
def server_client(self, value):
self._server_client = value
@property
def clients(self):
return self._clients
@property
def encoders(self):
return self._encoders
@encoders.setter
def encoders(self, value):
if not isinstance(value, list):
value = [value]
try:
self._encoders = protocols.get_protocol(value)
except NameError as e:
raise ValueError("Could not parse value.", e)
@property
def ssl_configuration(self):
return self._ssl_configuration
@ssl_configuration.setter
def ssl_configuration(self, value):
if not isinstance(value, dict):
raise ValueError("ssl_configuration must be a dict.")
self._ssl_configuration = value
def __init__(self, port=9999, bind="0.0.0.0", parser="Parser", encoders=[], ssl_configuration={}):
"""
ssl_configuration: this should be a dictionnary of ssl.wrap_socket function parameters.
"""
self.port = port
self.bind = bind
self.parser = parser
self.encoders = encoders
self.ssl_configuration = ssl_configuration
def whisp_client(self, message, client):
cmd = commands.get_command("Whisper",self, self.server_client, [client.name, message])
cmd.execute()
def disconnect_client(self, client):
"""
Disconnect a client and announce it to the world.
"""
self.clients.remove(client)
client.socket.close()
cmd = commands.get_command("Broadcast", self, self.server_client, ["{0} has left the chat!".format(client.name), [client.name]])
cmd.execute()
def kill(self):
"""Close all client connection and stop the server to listen WHITOUT warning the current connected clients."""
for client in self.clients:
self.disconnect_client(client)
self.server_client.socket.close()
def stop(self):
"""Warns the connected client that the server is going down then close all connection"""
logging.info("Server stopped")
cmd = commands.get_command("Broadcast", self, self.server_client, ["I AM GOING DOWN."])
cmd.execute()
self.kill()
def listen(self):
server_socket = socket.socket(socket.AF_INET)
if self.ssl_configuration:
logging.info("SSL mode is on")
server_socket = ssl.wrap_socket(sock=server_socket, server_side=True, **self.ssl_configuration)
self.server_client = clients.Client(ip="", name="[SERVER]", protocol=self.encoders, socket=server_socket, server=self)
self.server_client.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_client.socket.bind((self.bind, self.port))
self.server_client.socket.listen(10)
logging.info( "Listenning started on '" + self.bind + "':'" + str(self.port) + "'")
while True:
inputready, outputready, exceptready = select.select(self.clients + [self.server_client],[],[])
for client in inputready:
if client == self.server_client:
try:
self.__handle_new_connection()
except socket.error as e:
logging.log(logging.ERROR, "Error occured while handling a new connection:'" + str(e) + "'")
else:
self.__handle_request(client)
def __handle_new_connection(self):
"""This is called whenever a new connection is initiated"""
sock, address = self.server_client.socket.accept()
client = clients.Client(ip=address[0], name=address[0], protocol=self.encoders, socket=sock, server=self)
self.clients.append(client)
cmd = commands.get_command("Broadcast", self, self.server_client, ["{0} has joined the chat!".format(client.name), [client.name]])
cmd.execute()
def __handle_request(self, caller):
"""This is called whenever data is received from one of the client."""
try:
data = caller.receive()
logging.debug("Parsing this data: '" + data + "'")
result = self.parser.parse(data)
logging.debug("Result of parsing: '" + result.command_name + "(" + ",".join(result.command_arguments) + ")'")
cmd = commands.get_command(result.command_name, self, caller, result.command_arguments)
cmd.execute()
except commands.ArgumentsValidationError as e:
#Command arguments did not validate.
print(e)
print("asdasdasdasd")
cmd = commands.get_command("Whisper", self, self.server_client, [caller.name, str(e)])
cmd.execute()
except commands.ExecutionFailedError as e:
#Tell the client that the command could not be executed properly.
cmd = commands.get_command("Whisper", self, self.server_client, [caller.name, "Command execution failed"])
cmd.execute()
logging.exception(e)
except clients.SocketError as e:
#Client probably just disconnected.
logging.debug("SocketError while handling request.")
logging.exception(e)
self.disconnect_client(caller)
except clients.ClientIsNotFinishedSendingError as e:
#Client has not finished sending it's data.
pass
except NameError as e:
# The command is not recognized.
cmd = commands.get_command("Whisper", self, self.server_client, [caller.name, "Unrecognized command"])
cmd.execute()