diff --git a/components/web_client_tcp.gd b/components/web_client_tcp.gd index eb87841..f5efbe3 100644 --- a/components/web_client_tcp.gd +++ b/components/web_client_tcp.gd @@ -1,9 +1,10 @@ class_name WebClientTCP extends Node -var _tcp := StreamPeerTCP.new() +#var _tcp := StreamPeerTCP.new() +var _socket := WebSocketPeer.new() -var _new_status: int = -1 +var _new_status: int = WebSocketPeer.STATE_CLOSED var _processed_status: int = -1 var _lobby_id: String @@ -39,42 +40,66 @@ enum ConnectionStatus { } func _process(_delta: float) -> void: - _tcp.poll() - _new_status = _tcp.get_status() - # Ensure status change is only processed once + _socket.poll() + _new_status = _socket.get_ready_state() if not _processed_status == _new_status: match _new_status: - StreamPeerTCP.Status.STATUS_NONE: - _clean_up_thread() - connection_status_changed.emit(ConnectionStatus.DISCONNECTED) - StreamPeerTCP.Status.STATUS_CONNECTING: - connection_status_changed.emit(ConnectionStatus.ATTEMPTING_CONNECTION) - StreamPeerTCP.Status.STATUS_CONNECTED: + WebSocketPeer.STATE_OPEN: + print("open") _stop_thread = false _thread = Thread.new() _thread.start(_listen_for_data) connected_to_server.emit() connection_status_changed.emit(ConnectionStatus.LOBBYLESS) - StreamPeerTCP.Status.STATUS_ERROR: - connection_error_occurred.emit() + WebSocketPeer.STATE_CONNECTING: + print("connecting") + connection_status_changed.emit(ConnectionStatus.ATTEMPTING_CONNECTION) + WebSocketPeer.STATE_CLOSING: + print("closing") + pass + WebSocketPeer.STATE_CLOSED: + print("closed") + _clean_up_thread() connection_status_changed.emit(ConnectionStatus.DISCONNECTED) - + _processed_status = _new_status + #_new_status = _tcp.get_status() + ## Ensure status change is only processed once + #if not _processed_status == _new_status: + #match _new_status: + #StreamPeerTCP.Status.STATUS_NONE: + #_clean_up_thread() + #connection_status_changed.emit(ConnectionStatus.DISCONNECTED) + #StreamPeerTCP.Status.STATUS_CONNECTING: + #connection_status_changed.emit(ConnectionStatus.ATTEMPTING_CONNECTION) + #StreamPeerTCP.Status.STATUS_CONNECTED: + #_stop_thread = false + #_thread = Thread.new() + #_thread.start(_listen_for_data) + #connected_to_server.emit() + #connection_status_changed.emit(ConnectionStatus.LOBBYLESS) + #StreamPeerTCP.Status.STATUS_ERROR: + #connection_error_occurred.emit() + #connection_status_changed.emit(ConnectionStatus.DISCONNECTED) + # + #_processed_status = _new_status func _listen_for_data() -> void: - while not _stop_thread: - received_data = _tcp.get_data(1) + while true: + #received_data = _tcp.get_data(1) # Error (e.g. abrupt disconnect), stop listening - if not received_data[0] == OK: - disconnected_from_server.emit.call_deferred() - return - - cached_response += (received_data[1] as PackedByteArray).get_string_from_utf8() - if cached_response.ends_with("}"): + #if not received_data[0] == OK: + #disconnected_from_server.emit.call_deferred() + #return + if _socket.get_available_packet_count(): + cached_response = _socket.get_packet().get_string_from_utf8() print(cached_response) - _handle_response(cached_response) - cached_response = "" + #cached_response += (received_data[1] as PackedByteArray).get_string_from_utf8() + if cached_response.ends_with("}"): + #print(cached_response) + _handle_response(cached_response) + cached_response = "" func _handle_response(response: String) -> void: var data = JSON.parse_string(response) @@ -106,11 +131,15 @@ func _exit_tree() -> void: disconnect_from_server() func connect_to_server() -> void: - _tcp.connect_to_host("127.0.0.1", 9974) - _tcp.set_no_delay(true) + #_tcp.connect_to_host("168.119.97.227", 9974) + #_tcp.set_no_delay(true) + var err = _socket.connect_to_url("127.0.0.1:9974") + if err != OK: + print("didn't work!") func disconnect_from_server() -> void: - _tcp.disconnect_from_host() + #_tcp.disconnect_from_host() + _socket.close() _clean_up_thread() disconnected_from_server.emit() connection_status_changed.emit(ConnectionStatus.DISCONNECTED) @@ -146,4 +175,5 @@ func send_chat_message(message: String) -> void: _send_message(TCPMessages.send_chat_message(_lobby_id, _client_id, message)) func _send_message(message: String) -> void: - _tcp.put_data(message.to_utf8_buffer()) + #_tcp.put_data(message.to_utf8_buffer()) + _socket.send_text(message) diff --git a/export_presets.cfg b/export_presets.cfg index 11173a0..bf96a06 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -39,3 +39,47 @@ unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") rm -rf \"{temp_dir}\"" + +[preset.1] + +name="Web" +platform="Web" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="../00 Exports/magician/20250704/magician_server.html" +patches=PackedStringArray() +encryption_include_filters="" +encryption_exclude_filters="" +seed=0 +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.1.options] + +custom_template/debug="" +custom_template/release="" +variant/extensions_support=false +variant/thread_support=false +vram_texture_compression/for_desktop=true +vram_texture_compression/for_mobile=false +html/export_icon=true +html/custom_html_shell="" +html/head_include="" +html/canvas_resize_policy=2 +html/focus_canvas_on_start=true +html/experimental_virtual_keyboard=false +progressive_web_app/enabled=false +progressive_web_app/ensure_cross_origin_isolation_headers=true +progressive_web_app/offline_page="" +progressive_web_app/display=1 +progressive_web_app/orientation=0 +progressive_web_app/icon_144x144="" +progressive_web_app/icon_180x180="" +progressive_web_app/icon_512x512="" +progressive_web_app/background_color=Color(0, 0, 0, 1) diff --git a/server.py b/server.py index 471c0bf..b565e0f 100644 --- a/server.py +++ b/server.py @@ -1,187 +1,251 @@ -from twisted.internet.protocol import DatagramProtocol -from twisted.internet import reactor -from time import sleep - +import json +import random +import socket import sys +import threading -def address_to_string(address): - ip, port = address - return ':'.join([ip, str(port)]) +import asyncio +from websockets.asyncio.server import serve -class ServerProtocol(DatagramProtocol): +def generate_code() -> str: + result = "" + for i in range(6): + result += chr(random.randint(0, 25) + 65) + return result - def __init__(self): - self.active_sessions: dict[Session] = {} - self.registered_clients: dict[Client] = {} - # Checks whether a client with the given client_id is already registered. - def is_client_registered(self, client_id): - return client_id in self.registered_clients - - # Checks if a session has already been registered with the given session_id. - def session_exists(self, session_id) -> bool: - return session_id in self.active_sessions - - # Creates a new session for players to join. - def create_session(self, session_id, host_client_id) -> int: - if self.session_exists(session_id): - # Tried to create existing session - return 1 - - self.active_sessions[session_id] = Session(session_id, host_client_id, self) - return 0 - - # Closes an existing session. Must disconnect all clients manually before calling this! - def close_session(self, s_id): - try: - del self.active_sessions[s_id] - except KeyError: - print("Tried to terminate non-existing session") - - # Registers a client and connects them to a given session. - def register_client(self, session_id, client_id, client_name, client_ip, client_port) -> int: - if self.is_client_registered(client_id): - print("Client %s is already registered." % [client_id]) - return 1 - - if not self.session_exists(session_id): - print("Client registered for non-existing session") - return 2 - - if len(self.active_sessions[session_id].registered_clients) >= 2: - print("Trying to join full session") - return 3 - - new_client = Client(session_id, client_id, client_name, client_ip, client_port) - self.registered_clients[client_id] = new_client - self.active_sessions[session_id].register_client(new_client) - - return 0 - - # Disconnects a client and removes them from the registered_clients. - def disconnect_client(self, session_id, client_id): - try: - del self.registered_clients[client_id] - self.active_sessions[session_id].remove_client(client_id) - except KeyError: - print("Tried to disconnect unregistered client %s." % [client_id]) - - # Checks whether the given client owns any session. Returns the session ID if true. - # Returns an empty string otherwise. - def owns_session(self, client_id) -> str: - for session_id in self.active_sessions: - if self.active_sessions[session_id].host_client_id == client_id: - return session_id - return "" - - # Sends a message to a client specified by their address. - def send_message(self, msg, address): - self.transport.write(bytes(msg, "utf-8"), address) - - # Executed when data is received from a client. - def datagramReceived(self, datagram, address): - """Handle incoming datagram messages.""" - print(datagram) - data_string = datagram.decode("utf-8") - msg_type = data_string[:2] - - print(address) - - client_ip, client_port = address - split_data = data_string.split(":") - - if msg_type == "cr": - # create lobby - error = self.create_session(split_data[1], split_data[2]) - - if error == 1: - # tried to create existing session - print("Could not create session; already exists") - self.transport.write(bytes('c1', "utf-8"), address) - return - - # TODO no error handling for register_client here yet - print(self.register_client(split_data[1], split_data[2], split_data[3], client_ip, client_port)) - print(client_port) - print("CLIENT PORT") - print("successfully created session and registered client") - self.transport.write(bytes('c0', "utf-8"), address) - - - elif msg_type == "jn": - # join lobby - error = self.register_client(split_data[1], split_data[2], split_data[3], client_ip, client_port) - print(client_port) - print("CLIENT PORT") - - if error == 1: - # client already registered - self.send_message('j1', address) - return - elif error == 2: - # session does not exist - self.send_message('j2', address) - return - elif error == 3: - # session full - self.send_message('j3', address) - return - - self.send_message('j0', address) - print("joined successfully") - - elif msg_type == "lv": - session_id = split_data[1] - leaving_client_id = split_data[2] - owned_session = self.owns_session(leaving_client_id) - if owned_session == "": - # client is only connected to a session - self.disconnect_client(session_id, leaving_client_id) - print("disconnected client from session") - else: - # client owns a session - # disconnect all clients - clients_to_delete = self.active_sessions[session_id].registered_clients.copy() - for client in clients_to_delete: - print(clients_to_delete) - print(client) - client_address = (client.client_ip, client.client_port) - print(client_address) - self.send_message('ex', client_address) - self.disconnect_client(client.session_id, client.client_id) - - self.close_session(session_id) - print("host gone; disconnected clients and closed session") - -class Session: - - def __init__(self, session_id, host_client_id, server): - self.id = session_id - self.host_client_id = host_client_id - self.server = server - self.registered_clients: list[Client] = [] - - # Registers a client in the session. - def register_client(self, client): - if client in self.registered_clients: - # Client is already registered - return - - self.registered_clients.append(client) +class Lobby: - def remove_client(self, client_id): - for client in self.registered_clients: - if client.client_id == client_id: - self.registered_clients.remove(client) + def __init__(self, lobby_id, host_client_id): + self.lobby_id = lobby_id + self.host_client_id = host_client_id + self.connected_clients = {} class Client: - def __init__(self, session_id, client_id, client_name, client_ip, client_port): - self.session_id = session_id + def __init__(self, client_id, client_name, websocket): self.client_id = client_id self.client_name = client_name - self.client_ip = client_ip - self.client_port = client_port + self.websocket = websocket + +class LobbyManager: + + def __init__(self): + self.active_lobbies = {} + + def get_lobby(self, lobby_id) -> Lobby: + return self.active_lobbies[lobby_id] + + def lobby_id_exists(self, lobby_id) -> bool: + return lobby_id in self.active_lobbies + + def client_id_exists_in_lobby(self, lobby_id, client_id) -> bool: + if not self.lobby_id_exists(lobby_id): + return False + return client_id in self.active_lobbies[lobby_id].connected_clients + + def get_unique_lobby_id(self) -> str: + id = generate_code() + if self.lobby_id_exists(id): + return self.get_unique_lobby_id() + return id + + def get_unique_client_id(self, lobby_id) -> str: + id = generate_code() + if self.client_id_exists_in_lobby(lobby_id, id): + return self.get_unique_client_id(lobby_id) + return id + + def create_lobby(self, lobby_id, host_client_id) -> None: + self.active_lobbies[lobby_id] = Lobby(lobby_id, host_client_id) + print(f"Created lobby {lobby_id}") + + def delete_lobby(self, lobby_id) -> None: + try: + del self.active_lobbies[lobby_id] + print(f"Deleted lobby {lobby_id}") + except KeyError: + print(f"Lobby with ID {lobby_id} not found, could not be deleted") + + async def join_lobby(self, lobby_id, client_id, client_name, websocket) -> None: + self.active_lobbies[lobby_id].connected_clients[client_id] = Client( + client_id, + client_name, + websocket, + ) + print(f"Client {client_id} joined lobby {lobby_id}") + + await self.broadcast_message( + lobby_id, + json.dumps({ + "response": "client_joined_lobby", + "new_client_id": client_id, + "new_client_name": client_name, + }) + ) + + async def leave_lobby(self, lobby_id, client_id) -> None: + try: + # get client name BEFORE deleting the client... + client_name = self.get_client_name(lobby_id, client_id) + del self.active_lobbies[lobby_id].connected_clients[client_id] + await self.broadcast_message( + lobby_id, + json.dumps({ + "response": "client_left_lobby", + "status": "ok", + "client_name": client_name, + }), + ) + print(f"Deleted client {client_id} from lobby {lobby_id}") + except KeyError: + print(f"Client with ID {client_id} in lobby {lobby_id} not found, could not be deleted") + + def get_lobby_player_count(self, lobby_id) -> int: + return len(self.active_lobbies[lobby_id].connected_clients) + + def get_client_name(self, lobby_id, client_id) -> str: + return self.active_lobbies[lobby_id].connected_clients[client_id].client_name + + def get_lobby_host_client_id(self, lobby_id) -> str: + return self.active_lobbies[lobby_id].host_client_id + + async def send_message(self, lobby_id, client_id, message) -> None: + await self.active_lobbies[lobby_id].connected_clients[client_id].websocket.send(message) + + async def broadcast_message(self, lobby_id, message) -> None: + connected_clients = self.active_lobbies[lobby_id].connected_clients + for client_id in connected_clients: + await connected_clients[client_id].websocket.send(message) + +# class ClientConnection: + +# def __init__(self, connection, address, lobby_manager): +# self.connection = connection +# self.address = address +# self.lobby_manager = lobby_manager + +# self.listen_client() + +# # Listens to a connected TCP client. +# def listen_client(self) -> None: +# try: +# print(f"Connected to {self.address[0]}:{self.address[1]}") + +# received_data = "" +# while True: +# data = self.connection.recv(1) +# received_data += data.decode("utf-8") +# if received_data[-1] == "}": +# print(received_data) +# self.process_input(received_data) +# received_data = "" + +# if not data: +# break +# except IndexError: +# print("Client force-disconnected") +# except ConnectionResetError: +# print("Client force-disconnected") +# finally: +# self.connection.close() +# print(f"Closing connection to {self.address[0]}:{self.address[1]}") + + + +lobby_manager = LobbyManager() + +async def listen_websocket() -> None: + async with serve(start_listen_client_websocket, "localhost", 9974) as server: + await server.serve_forever() + +async def start_listen_client_websocket(websocket) -> None: + async for message in websocket: + # await + await process_input(message, websocket) + +async def process_input(message: str, websocket) -> None: + data_object = json.loads(message) + + if data_object["response"] == "create_lobby": + new_lobby_id = lobby_manager.get_unique_lobby_id() + new_client_id = lobby_manager.get_unique_client_id(new_lobby_id) + print(new_client_id + " is creating lobby " + new_lobby_id) + + lobby_manager.create_lobby( + new_lobby_id, + new_client_id, + ) + await lobby_manager.join_lobby( + new_lobby_id, + new_client_id, + data_object["client_name"], + websocket, + ) + await lobby_manager.send_message( + new_lobby_id, + new_client_id, + json.dumps({ + "response": "create_lobby", + "status": "ok", + "lobby_id": new_lobby_id, + "client_id": new_client_id, + }), + ) + + elif data_object["response"] == "join_lobby": + print("joining lobby") + lobby_id = data_object["lobby_id"] + new_client_id = lobby_manager.get_unique_client_id(lobby_id) + + await lobby_manager.join_lobby( + lobby_id, + new_client_id, + data_object["client_name"], + websocket, + ) + await lobby_manager.send_message( + lobby_id, + new_client_id, + json.dumps({ + "response": "join_lobby", + "status": "ok", + "client_id": new_client_id, + }), + ) + + # send message to all connected clients + + elif data_object["response"] == "leave_lobby": + print("leaving lobby") + lobby_id = data_object["lobby_id"] + host_client_id = lobby_manager.get_lobby_host_client_id(lobby_id) + + if host_client_id == data_object["client_id"]: + # client is host; close lobby + await lobby_manager.leave_lobby(lobby_id, data_object["client_id"]) + await lobby_manager.broadcast_message( + lobby_id, + json.dumps({ + "response": "leave_lobby_request", + }) + ) + if lobby_manager.get_lobby_player_count(lobby_id) == 0: + lobby_manager.delete_lobby(lobby_id) + else: + # client is not host; client leaves only + await lobby_manager.leave_lobby(lobby_id, data_object["client_id"]) + + elif data_object["response"] == "send_chat_message": + print("relaying chat message") + await lobby_manager.broadcast_message( + data_object["lobby_id"], + json.dumps({ + "response": "receive_chat_message", + "message": data_object["message"], + "client_name": lobby_manager.get_client_name(data_object["lobby_id"], data_object["client_id"]), + }) + ) if __name__ == '__main__': if len(sys.argv) < 2: @@ -189,6 +253,13 @@ if __name__ == '__main__': sys.exit(1) port = int(sys.argv[1]) - reactor.listenUDP(port, ServerProtocol()) + # tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # server_address = ('168.119.97.227', port) + # tcp_socket.bind(server_address) + # tcp_socket.listen(1) + # tcp_socket.settimeout(0.5) + print('Listening on *:%d' % (port)) - reactor.run() + + # listen() + asyncio.run(listen_websocket()) \ No newline at end of file diff --git a/server_tcp.py b/server_tcp.py deleted file mode 100644 index 45c017f..0000000 --- a/server_tcp.py +++ /dev/null @@ -1,271 +0,0 @@ -import json -import random -import socket -import sys -import threading - -# Establishes connections to TCP clients. -def listen() -> None: - print(generate_code()) - lobby_manager = LobbyManager() - threads = [] - while True: - try: - connection, address = tcp_socket.accept() - new_thread = threading.Thread(target=start_listen_client, args=(connection, address, lobby_manager)) - new_thread.start() - threads.append(new_thread) - except socket.timeout: - pass - except KeyboardInterrupt: - tcp_socket.close() - -def start_listen_client(connection, address, lobby_manager): - ClientConnection(connection, address, lobby_manager) - -def generate_code() -> str: - result = "" - for i in range(6): - result += chr(random.randint(0, 25) + 65) - return result - - -class Lobby: - - def __init__(self, lobby_id, host_client_id): - self.lobby_id = lobby_id - self.host_client_id = host_client_id - self.connected_clients = {} - -class Client: - - def __init__(self, client_id, client_name, address, connection): - self.client_id = client_id - self.client_name = client_name - self.address = address - self.connection = connection - -class LobbyManager: - - def __init__(self): - self.active_lobbies = {} - - def get_lobby(self, lobby_id) -> Lobby: - return self.active_lobbies[lobby_id] - - def lobby_id_exists(self, lobby_id) -> bool: - return lobby_id in self.active_lobbies - - def client_id_exists_in_lobby(self, lobby_id, client_id) -> bool: - if not self.lobby_id_exists(lobby_id): - return False - return client_id in self.active_lobbies[lobby_id].connected_clients - - def get_unique_lobby_id(self) -> str: - id = generate_code() - if self.lobby_id_exists(id): - return self.get_unique_lobby_id() - return id - - def get_unique_client_id(self, lobby_id) -> str: - id = generate_code() - if self.client_id_exists_in_lobby(lobby_id, id): - return self.get_unique_client_id(lobby_id) - return id - - def create_lobby(self, lobby_id, host_client_id) -> None: - self.active_lobbies[lobby_id] = Lobby(lobby_id, host_client_id) - print(f"Created lobby {lobby_id}") - - def delete_lobby(self, lobby_id) -> None: - try: - del self.active_lobbies[lobby_id] - print(f"Deleted lobby {lobby_id}") - except KeyError: - print(f"Lobby with ID {lobby_id} not found, could not be deleted") - - def join_lobby(self, lobby_id, client_id, client_name, address, connection) -> None: - self.active_lobbies[lobby_id].connected_clients[client_id] = Client( - client_id, - client_name, - address, - connection, - ) - print(f"Client {client_id} joined lobby {lobby_id}") - - self.broadcast_message( - lobby_id, - json.dumps({ - "response": "client_joined_lobby", - "new_client_id": client_id, - "new_client_name": client_name, - }) - ) - - def leave_lobby(self, lobby_id, client_id) -> None: - try: - # get client name BEFORE deleting the client... - client_name = self.get_client_name(lobby_id, client_id) - del self.active_lobbies[lobby_id].connected_clients[client_id] - self.broadcast_message( - lobby_id, - json.dumps({ - "response": "client_left_lobby", - "status": "ok", - "client_name": client_name, - }), - ) - print(f"Deleted client {client_id} from lobby {lobby_id}") - except KeyError: - print(f"Client with ID {client_id} in lobby {lobby_id} not found, could not be deleted") - - def get_lobby_player_count(self, lobby_id) -> int: - return len(self.active_lobbies[lobby_id].connected_clients) - - def get_client_name(self, lobby_id, client_id) -> str: - return self.active_lobbies[lobby_id].connected_clients[client_id].client_name - - def get_lobby_host_client_id(self, lobby_id) -> str: - return self.active_lobbies[lobby_id].host_client_id - - def send_message(self, lobby_id, client_id, message) -> None: - self.active_lobbies[lobby_id].connected_clients[client_id].connection.sendall(str.encode(message)) - - def broadcast_message(self, lobby_id, message) -> None: - connected_clients = self.active_lobbies[lobby_id].connected_clients - for client_id in connected_clients: - connected_clients[client_id].connection.sendall(str.encode(message)) - -class ClientConnection: - - def __init__(self, connection, address, lobby_manager): - self.connection = connection - self.address = address - self.lobby_manager = lobby_manager - - self.listen_client() - - # Listens to a connected TCP client. - def listen_client(self) -> None: - try: - print(f"Connected to {self.address[0]}:{self.address[1]}") - - received_data = "" - while True: - data = self.connection.recv(1) - received_data += data.decode("utf-8") - if received_data[-1] == "}": - print(received_data) - self.process_input(received_data) - received_data = "" - - if not data: - break - except IndexError: - print("Client force-disconnected") - except ConnectionResetError: - print("Client force-disconnected") - finally: - self.connection.close() - print(f"Closing connection to {self.address[0]}:{self.address[1]}") - - def process_input(self, data: str) -> None: - data_object = json.loads(data) - - if data_object["response"] == "create_lobby": - new_lobby_id = self.lobby_manager.get_unique_lobby_id() - new_client_id = self.lobby_manager.get_unique_client_id(new_lobby_id) - print(new_client_id + " is creating lobby " + new_lobby_id) - - self.lobby_manager.create_lobby( - new_lobby_id, - new_client_id, - ) - self.lobby_manager.join_lobby( - new_lobby_id, - new_client_id, - data_object["client_name"], - self.address, - self.connection, - ) - self.lobby_manager.send_message( - new_lobby_id, - new_client_id, - json.dumps({ - "response": "create_lobby", - "status": "ok", - "lobby_id": new_lobby_id, - "client_id": new_client_id, - }), - ) - - elif data_object["response"] == "join_lobby": - print("joining lobby") - lobby_id = data_object["lobby_id"] - new_client_id = self.lobby_manager.get_unique_client_id(lobby_id) - - self.lobby_manager.join_lobby( - lobby_id, - new_client_id, - data_object["client_name"], - self.address, - self.connection, - ) - self.lobby_manager.send_message( - lobby_id, - new_client_id, - json.dumps({ - "response": "join_lobby", - "status": "ok", - "client_id": new_client_id, - }), - ) - - # send message to all connected clients - - elif data_object["response"] == "leave_lobby": - print("leaving lobby") - lobby_id = data_object["lobby_id"] - host_client_id = self.lobby_manager.get_lobby_host_client_id(lobby_id) - - if host_client_id == data_object["client_id"]: - # client is host; close lobby - self.lobby_manager.leave_lobby(lobby_id, data_object["client_id"]) - self.lobby_manager.broadcast_message( - lobby_id, - json.dumps({ - "response": "leave_lobby_request", - }) - ) - if self.lobby_manager.get_lobby_player_count(lobby_id) == 0: - self.lobby_manager.delete_lobby(lobby_id) - else: - # client is not host; client leaves only - self.lobby_manager.leave_lobby(lobby_id, data_object["client_id"]) - - elif data_object["response"] == "send_chat_message": - print("relaying chat message") - self.lobby_manager.broadcast_message( - data_object["lobby_id"], - json.dumps({ - "response": "receive_chat_message", - "message": data_object["message"], - "client_name": self.lobby_manager.get_client_name(data_object["lobby_id"], data_object["client_id"]), - }) - ) - -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Usage: ./server.py PORT") - sys.exit(1) - - port = int(sys.argv[1]) - tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = ('localhost', port) - tcp_socket.bind(server_address) - tcp_socket.listen(1) - tcp_socket.settimeout(0.5) - - print('Listening on *:%d' % (port)) - - listen() \ No newline at end of file