136 lines
6.4 KiB
Python
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) |