136 lines
6.4 KiB
Python

import json
import signal
import socket
import sys
import threading
from Classes.Game.Player import Player
from Classes.System.GameManager import GameManager
from Classes.System.Network.EventHandler import TCPEventHandler
from Classes.System.World import World
class NetworkManager:
class TCP:
__Addr:str
__Port:str
__BufferSize:int = 1024
__tcpSocket:socket
__eventHandler: dict
__users: dict
__TCPClientThread:threading.Thread
__gameManager:GameManager
def __init__(self, Addr:str, Port:str, gameManager:GameManager):
gameManager.getLogger().info("starting up network manager")
self.running = True
self.__Addr = Addr
self.__Port = int(Port)
self.__gameManager = gameManager
self.__eventHandler = {}
gameManager.getLogger().info("starting up tcp server")
self.__tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__tcpSocket.bind((self.__Addr, self.__Port))
self.__tcpSocket.listen()
gameManager.getLogger().info("starting up thread for client socket accepting")
self.__TCPClientThread = threading.Thread(target=self.accept_connections)
self.__TCPClientThread.daemon = True
self.__TCPClientThread.start()
def accept_connections(self):
while self.running:
try:
client_tcp_socket, client_address = self.__tcpSocket.accept()
self.__gameManager.getLogger().info(f"Connected with {client_address}")
self.__gameManager.getPlayers()[client_address] = client_tcp_socket
self.__eventHandler[client_address] = TCPEventHandler(client_tcp_socket)
client_handler_thread = threading.Thread(
target=self.receive,
args=(client_tcp_socket, client_address)
)
self.__gameManager.getLogger().info(f"starting client handler thread for client at address {client_address}")
client_handler_thread.daemon = True
client_handler_thread.start()
except Exception as e:
self.__gameManager.getLogger().error(f"tcp socket failed to accept connection due to error: {e}")
pass
client_handler_thread.join()
def receive(self, client_socket, client_address):
while self.running:
try:
data = client_socket.recv(self.__BufferSize)
if not data:
self.__gameManager.getLogger().info(f"Connection with {client_address} closed.")
break
try:
message = data.decode()
messageJson = json.loads(message)
self.__gameManager.getLogger().info(f"decoded message {messageJson}")
user = messageJson.get("user")
self.__gameManager.getLogger().info(f"user in message {user}")
except Exception as ex:
self.__gameManager.getLogger().info(f"decoding incoming packet failed due to exception: {ex}")
# creates a user and counts how many currently are connected to the server
# if enough users for a round are connected the server has to start the game
if user not in self.__gameManager.getPlayers():
if messageJson["event"] == "login":
self.__gameManager.getLogger().info("user logging in")
self.__gameManager.getLogger().info("task passed off to gameManager")
user = self.__gameManager.addPlayers(Player(messageJson["username"], messageJson["deck"]), client_socket, client_address, messageJson["deck"])
self.__gameManager.getLogger().info(f"connected users {len(self.__gameManager.getPlayers())}")
self.__gameManager.getLogger().info(f"confirming login for user")
self.__eventHandler[client_address].handleTCPEvents(messageJson, self.__gameManager, client_address)
self.__gameManager.getLogger().info(f"Received message from {client_address}: {message}")
except socket.error as e:
if e.errno == 10054:
self.__gameManager.getLogger().error(f"Connection with {client_address} forcibly closed by remote host.")
break
self.__gameManager.getLogger().error(f"Socket error receiving data from {client_address}: {e}")
except json.JSONDecodeError as e:
self.__gameManager.getLogger().error(f"JSON decoding error receiving data from {client_address}: {e}")
# except Exception as e:
# self.__gameManager.getLogger().error(f"UknownError receiving data from {client_address} due to error: {e}")
def broadcast(self, payload:dict):
for user in self.__gameManager.getPlayers().values():
user["socket"].send(json.dumps(payload).encode())
def send(self, payload: dict, user: str):
players = self.__gameManager.getPlayers()
if user in players and "socket" in players[user]:
players[user]["socket"].send(json.dumps(payload).encode())
else:
self.__gameManager.getLogger().error(f"user '{user}' or socket was not found 'socket' failed to send data.")
def stop(self):
self.__TCPClientThread.join() # Wait for the thread to finish before exiting
tcp: TCP
# udp: UDP
def __init__(self, Addr:str, TCPPort:str, UDPPort:str, gameManager:GameManager):
self.tcp = self.TCP(Addr, TCPPort, gameManager)
signal.signal(signal.SIGINT, self.handle_interrupt) # Register the signal handler
def handle_interrupt(self, signum, frame):
self.__gameManager.getLogger().info("Received keyboard interrupt. Stopping the server.")
self.tcp().stop()
sys.exit(0)