-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.py
70 lines (60 loc) · 2.92 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
import socketserver
from logging import Logger
from command_parse import MCLiteCommand, NonExistentCommandException, CommandParseException, QuitCommand, \
StorageCommand, RetrievalCommand, DeleteCommand
from server_logging import init_logger, ConnectionLogAdapter
from response_parse import ErrorResponse
from server_config import SERVER_HOST, SERVER_PORT
from storage import FileStorage
class MCLiteTCPHandler(socketserver.StreamRequestHandler):
storage = FileStorage()
@classmethod
def set_logger(cls, logger: Logger):
cls.logger = logger
def handle(self):
log_adapter = ConnectionLogAdapter(self.logger, {
"client_host": self.client_address[0],
"client_port": self.client_address[1],
})
log_adapter.info("New client connected.")
try:
while True:
text_line = self.rfile.readline()
try:
comm_abs_synt = MCLiteCommand.parse(text_line, self.rfile)
request_repr = str(comm_abs_synt)
log_adapter.debug(f"Request: {request_repr}")
command = comm_abs_synt.command
response = b""
if isinstance(command, QuitCommand):
break
elif isinstance(command, StorageCommand):
response = self.storage.set(command.key, command.value, command.value_size_bytes)
elif isinstance(command, RetrievalCommand):
response = self.storage.get(command.keys)
elif isinstance(command, DeleteCommand):
response = self.storage.delete(command.key)
log_adapter.debug(f"Response: {response}")
self.wfile.write(response.to_concrete_syntax())
except NonExistentCommandException as e:
log_adapter.debug(str(e))
response = ErrorResponse("ERROR", None)
self.wfile.write(response.to_concrete_syntax())
except CommandParseException as e:
log_adapter.debug(str(e))
response = ErrorResponse("CLIENT_ERROR", str(e))
self.wfile.write(response.to_concrete_syntax())
except BrokenPipeError as e:
log_adapter.warning("Broken pipe error. Disconnecting now...")
except Exception as e:
log_adapter.error("Unexpected error. Disconnecting now...")
finally:
log_adapter.info("Client disconnected")
if __name__ == "__main__":
logger = init_logger()
# Create the server, binding to HOST on PORT
with socketserver.ForkingTCPServer((SERVER_HOST, SERVER_PORT), MCLiteTCPHandler) as server:
MCLiteTCPHandler.set_logger(logger)
logger.info(f"Begin listening on {SERVER_HOST}:{SERVER_PORT}...")
server.serve_forever()
logger.info("Shutting down.")