diff --git a/projects/server/src/server/rustomer_motors_server.py b/projects/server/src/server/rustomer_motors_server.py deleted file mode 100644 index 09e2624c5..000000000 --- a/projects/server/src/server/rustomer_motors_server.py +++ /dev/null @@ -1,70 +0,0 @@ -import argparse -import tkinter as tk -from socket import socket -from .env_default_action import EnvDefault - - -class RustyMotorsServer(tk.Frame): - def __init__( - self, - master=None, - ): - tk.Frame.__init__(self, master) - self.grid() - tk.Label(self, text="Hello World!").grid(column=0, row=0) - tk.Button(self, text="Quit", command=self.quit).grid(column=1, row=0) - - parser = argparse.ArgumentParser() - parser.add_argument( - "--server-address", - action=EnvDefault, - envvar="SERVER_ADDRESS", - default="localhost", - help="The address to bind the server to. Default: localhost. \ - Can be set with the SERVER_ADDRESS environment variable.", - ) - parser.add_argument( - "--port", - action=EnvDefault, - envvar="PORT", - default=12345, - help="The port to bind the server to. Default: 12345. Can be set with the PORT environment variable.", - ) - parser.add_argument( - "--external-host", - action=EnvDefault, - envvar="EXTERNAL_HOST", - default="localhost", - help="The external host to tell clients to connect to. Default: localhost. \ - Can be set with the EXTERNAL_HOST environment variable.", - ) - args = parser.parse_args() - - self.server_address = str(args.server_address) - self.port = int(args.port) - self.external_host = str(args.external_host) - - self.server_socket = socket() - self.server_socket.bind((self.server_address, self.port)) - - if self.server_socket is not None: - self.server_socket.listen(1) - print(f"Server listening on {self.server_address}:{self.port}") - self.server_socket.setblocking(False) - self.after(1000, self.try_accept, self.server_socket) - else: - print("Unable to start server.") - exit(1) - - def try_accept(self, sock: socket): - try: - client_socket, client_address = sock.accept() - print(f"Connection from {client_address}") - client_socket.sendall(b"Hello World!") - # client_socket.close() - self.after(1000, self.try_accept, sock) - except BlockingIOError: - self.after(1000, self.try_accept, sock) - - def run(self): - self.mainloop() diff --git a/projects/server/src/server/rusty_motors_server.py b/projects/server/src/server/rusty_motors_server.py new file mode 100644 index 000000000..5ef3ad43c --- /dev/null +++ b/projects/server/src/server/rusty_motors_server.py @@ -0,0 +1,119 @@ +import argparse +import tkinter as tk +from .env_default_action import EnvDefault +from select import poll, POLLIN +from socketserver import BaseRequestHandler, ThreadingTCPServer +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + + +class WebRequestHandler(BaseHTTPRequestHandler): + + def do_GET(self): + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(b"Hello World!") + + +class TCPRequestHandler(BaseRequestHandler): + + def handle(self): + print(f"Received connection from {self.client_address}") + data = self.request.recv(1024) + print(f"Received data: {data}") + + +class RustyMotorsServer(tk.Frame): + def __init__( + self, + master=None, + ): + tk.Frame.__init__(self, master) + self.grid() + tk.Label(self, text="Hello World!").grid(column=0, row=0) + tk.Button(self, text="Quit", command=self.shutdown).grid(column=1, row=0) + + self.bindings() + + parser = argparse.ArgumentParser() + parser.add_argument( + "--server-address", + action=EnvDefault, + envvar="SERVER_ADDRESS", + default="localhost", + help="The address to bind the server to. Default: localhost. \ + Can be set with the SERVER_ADDRESS environment variable.", + ) + parser.add_argument( + "--port", + action=EnvDefault, + envvar="PORT", + default=3000, + help="The port to bind the server to. Default: 3000. Can be set with the PORT environment variable.", + ) + parser.add_argument( + "--external-host", + action=EnvDefault, + envvar="EXTERNAL_HOST", + default="localhost", + help="The external host to tell clients to connect to. Default: localhost. \ + Can be set with the EXTERNAL_HOST environment variable.", + ) + args = parser.parse_args() + + # Setup HTTP server + self.http_server = ThreadingHTTPServer( + (args.server_address, args.port), WebRequestHandler + ) + self.http_server.socket.fileno() + + self.login_server = ThreadingTCPServer(("localhost", 8226), TCPRequestHandler) + self.persona_server = ThreadingTCPServer(("localhost", 8228), TCPRequestHandler) + self.lobby_server = ThreadingTCPServer(("localhost", 7003), TCPRequestHandler) + self.mcots_server = ThreadingTCPServer(("localhost", 43300), TCPRequestHandler) + + self.fdMapper: dict[int, ThreadingHTTPServer | TCPRequestHandler] = { + self.http_server.socket.fileno(): self.http_server, + self.login_server.fileno(): self.login_server, + self.persona_server.fileno(): self.persona_server, + self.lobby_server.fileno(): self.lobby_server, + self.mcots_server.fileno(): self.mcots_server, + } + + self.poller = poll() + self.poller.register(self.http_server.socket, POLLIN) + self.poller.register(self.login_server, POLLIN) + self.poller.register(self.persona_server, POLLIN) + self.poller.register(self.lobby_server, POLLIN) + self.poller.register(self.mcots_server, POLLIN) + print("Registered all sockets") + + self.after(1000, self.try_poll) + + def shutdown(self): + print("Shutting down server") + self.quit() + + def try_poll(self): + incoming = self.poller.poll(1) + + if len(incoming) == 0: + self.after(1000, self.try_poll) + return + + for fd, event in incoming: + if event == POLLIN: + self.handle_incoming(fd) + + self.after(1000, self.try_poll) + + def handle_incoming(self, fd): + server = self.fdMapper[fd] + print(f"Handling incoming connection from {server}") + server.handle_request() + + def bindings(self): + self.master.bind("x", lambda event: self.shutdown()) + + def run(self): + self.mainloop() diff --git a/projects/server/src/server/test___init__.py b/projects/server/src/server/test___init__.py deleted file mode 100644 index aa5eabb16..000000000 --- a/projects/server/src/server/test___init__.py +++ /dev/null @@ -1,26 +0,0 @@ -import unittest -from unittest.mock import MagicMock - -from server.rustomer_motors_server import RustyMotorsServer - - -class TestRustyMotorsServer(unittest.TestCase): - def test_init(self): - # Create a mock master object - master = MagicMock() - - # Create an instance of RustyMotorsServer - server = RustyMotorsServer(master) - - # Assert that the server's master attribute is set correctly - self.assertEqual(server.master, master) - - # Assert that the server's server_socket attribute is not None - self.assertIsNotNone(server.server_socket) - - # Assert that the server's server_socket is set to non-blocking mode - self.assertFalse(server.server_socket.getblocking()) - - -if __name__ == "__main__": - unittest.main() diff --git a/projects/server/tests/rusty_motors_server_test.py b/projects/server/tests/rusty_motors_server_test.py new file mode 100644 index 000000000..7a0e9b422 --- /dev/null +++ b/projects/server/tests/rusty_motors_server_test.py @@ -0,0 +1,9 @@ +from unittest.mock import patch +from server.rusty_motors_server import RustyMotorsServer + + +def test_shutdown(): + server = RustyMotorsServer() + with patch.object(server, "quit") as mock_quit: + server.shutdown() + mock_quit.assert_called_once() diff --git a/rm-server.py b/rm-server.py index d622b518c..8542fdd6f 100755 --- a/rm-server.py +++ b/rm-server.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -from server.rustomer_motors_server import RustyMotorsServer +from server.rusty_motors_server import RustyMotorsServer path = "/home/drazisil/Downloads/MCO/mcity.exe"