mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Update proxy server
This commit is contained in:
parent
f83e4f4ce4
commit
45129c5cda
447
proxyServer.py
447
proxyServer.py
@ -11,14 +11,7 @@ PROTOCOL_VERSION_MAX = 1
|
|||||||
SERVER_HOST = "0.0.0.0"
|
SERVER_HOST = "0.0.0.0"
|
||||||
SERVER_PORT = 5002 # port we want to use
|
SERVER_PORT = 5002 # port we want to use
|
||||||
|
|
||||||
def send_msg(sock, msg, doPack):
|
def receive_packed(sock):
|
||||||
# For 1 byte (bool) send just that
|
|
||||||
# Prefix each message with a 4-byte length (network byte order)
|
|
||||||
if doPack and len(msg) > 1:
|
|
||||||
msg = struct.pack('<I', len(msg)) + msg
|
|
||||||
sock.sendall(msg)
|
|
||||||
|
|
||||||
def recv_msg(sock):
|
|
||||||
# Read message length and unpack it into an integer
|
# Read message length and unpack it into an integer
|
||||||
raw_msglen = recvall(sock, 4)
|
raw_msglen = recvall(sock, 4)
|
||||||
if not raw_msglen:
|
if not raw_msglen:
|
||||||
@ -37,9 +30,6 @@ def recvall(sock, n):
|
|||||||
data.extend(packet)
|
data.extend(packet)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# initialize list/set of all connected client's sockets
|
|
||||||
client_sockets = dict()
|
|
||||||
|
|
||||||
|
|
||||||
class GameConnection:
|
class GameConnection:
|
||||||
server: socket # socket to vcmiserver
|
server: socket # socket to vcmiserver
|
||||||
@ -52,17 +42,16 @@ class GameConnection:
|
|||||||
self.client = None
|
self.client = None
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Session:
|
|
||||||
|
class Room:
|
||||||
total = 1 # total amount of players
|
total = 1 # total amount of players
|
||||||
joined = 0 # amount of players joined to the session
|
joined = 0 # amount of players joined to the session
|
||||||
password = "" # password to connect
|
password = "" # password to connect
|
||||||
protected = False # if True, password is required to join to the session
|
protected = False # if True, password is required to join to the session
|
||||||
name: str # name of session
|
name: str # name of session
|
||||||
host: socket # player socket who created the session (lobby mode)
|
host: socket # player socket who created the room
|
||||||
token: str # uuid of vcmiserver for hosting player
|
|
||||||
players = [] # list of sockets of players, joined to the session
|
players = [] # list of sockets of players, joined to the session
|
||||||
connections = [] # list of GameConnections for vcmiclient (game mode)
|
started = False
|
||||||
started = False # True - game mode, False - lobby mode
|
|
||||||
|
|
||||||
def __init__(self, host: socket, name: str) -> None:
|
def __init__(self, host: socket, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -85,6 +74,22 @@ class Session:
|
|||||||
self.players.remove(player)
|
self.players.remove(player)
|
||||||
self.joined -= 1
|
self.joined -= 1
|
||||||
|
|
||||||
|
|
||||||
|
class Session:
|
||||||
|
name: str # name of session
|
||||||
|
host_uuid: str # uuid of vcmiserver for hosting player
|
||||||
|
clients_uuid: list # list od vcmiclients uuid
|
||||||
|
players: list # list of sockets of players, joined to the session
|
||||||
|
connections: list # list of GameConnections for vcmiclient/vcmiserver (game mode)
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.name = ""
|
||||||
|
self.host_uuid = ""
|
||||||
|
self.clients_uuid = []
|
||||||
|
self.players = []
|
||||||
|
self.connections = []
|
||||||
|
pass
|
||||||
|
|
||||||
def addConnection(self, conn: socket, isServer: bool):
|
def addConnection(self, conn: socket, isServer: bool):
|
||||||
#find uninitialized server connection
|
#find uninitialized server connection
|
||||||
for gc in self.connections:
|
for gc in self.connections:
|
||||||
@ -119,6 +124,62 @@ class Session:
|
|||||||
return gc.server
|
return gc.server
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
auth: bool
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.auth = False
|
||||||
|
|
||||||
|
|
||||||
|
class ClientLobby(Client):
|
||||||
|
joined: bool
|
||||||
|
username: str
|
||||||
|
room: Room
|
||||||
|
protocolVersion: int
|
||||||
|
encoding: str
|
||||||
|
ready: bool
|
||||||
|
vcmiversion: str #TODO: check version compatibility
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.room = None
|
||||||
|
self.joined = False
|
||||||
|
self.username = ""
|
||||||
|
self.protocolVersion = 0
|
||||||
|
self.encoding = 'utf8'
|
||||||
|
self.ready = False
|
||||||
|
self.vcmiversion = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ClientPipe(Client):
|
||||||
|
apptype: str #client/server
|
||||||
|
prevmessages: list
|
||||||
|
session: Session
|
||||||
|
uuid: str
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.prevmessages = []
|
||||||
|
self.session = None
|
||||||
|
self.apptype = ""
|
||||||
|
self.uuid = ""
|
||||||
|
|
||||||
|
|
||||||
|
class Sender:
|
||||||
|
address: str #full client address
|
||||||
|
client: Client
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.client = None
|
||||||
|
pass
|
||||||
|
|
||||||
|
def isLobby(self) -> bool:
|
||||||
|
return isinstance(self.client, ClientLobby)
|
||||||
|
|
||||||
|
def isPipe(self) -> bool:
|
||||||
|
return isinstance(self.client, ClientPipe)
|
||||||
|
|
||||||
|
|
||||||
# create a TCP socket
|
# create a TCP socket
|
||||||
s = socket.socket()
|
s = socket.socket()
|
||||||
# make the port as reusable port
|
# make the port as reusable port
|
||||||
@ -129,45 +190,57 @@ s.bind((SERVER_HOST, SERVER_PORT))
|
|||||||
s.listen(10)
|
s.listen(10)
|
||||||
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
|
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
|
||||||
|
|
||||||
|
# active rooms
|
||||||
|
rooms = {}
|
||||||
|
|
||||||
# list of active sessions
|
# list of active sessions
|
||||||
sessions = dict()
|
sessions = []
|
||||||
|
|
||||||
|
# initialize list/set of all connected client's sockets
|
||||||
|
client_sockets = {}
|
||||||
|
|
||||||
|
|
||||||
def handleDisconnection(client: socket):
|
def handleDisconnection(client: socket):
|
||||||
|
if not client in client_sockets:
|
||||||
|
return
|
||||||
|
|
||||||
sender = client_sockets[client]
|
sender = client_sockets[client]
|
||||||
if sender["joined"]:
|
if sender.isLobby() and sender.client.joined:
|
||||||
if not sender["session"].started:
|
if not sender.client.room.started:
|
||||||
if sender["session"].host == client:
|
if sender.client.room.host == client:
|
||||||
#destroy the session, sending messages inside the function
|
#destroy the session, sending messages inside the function
|
||||||
deleteSession(sender["session"])
|
deleteRoom(sender.client.room)
|
||||||
else:
|
else:
|
||||||
sender["session"].leave(client)
|
sender.client.room.leave(client)
|
||||||
sender["joined"] = False
|
sender.client.joined = False
|
||||||
message = f":>>KICK:{sender['session'].name}:{sender['username']}"
|
message = f":>>KICK:{sender.client.room.name}:{sender.client.username}"
|
||||||
for client_socket in sender["session"].players:
|
broadcast(sender.client.room.players, message.encode())
|
||||||
client_socket.send(message.encode())
|
updateStatus(sender.client.room)
|
||||||
updateStatus(sender["session"])
|
updateRooms()
|
||||||
updateSessions()
|
|
||||||
|
if sender.isPipe():
|
||||||
|
pass
|
||||||
|
|
||||||
client.close()
|
client.close()
|
||||||
sender["valid"] = False
|
client_sockets.pop(client)
|
||||||
|
|
||||||
|
|
||||||
def send(client: socket, message: str):
|
def send(client: socket, message: str):
|
||||||
|
if client in client_sockets.keys():
|
||||||
sender = client_sockets[client]
|
sender = client_sockets[client]
|
||||||
if "valid" not in sender or sender["valid"]:
|
|
||||||
client.send(message.encode(errors='replace'))
|
client.send(message.encode(errors='replace'))
|
||||||
|
|
||||||
|
|
||||||
def broadcast(clients: list, message: str):
|
def broadcast(clients: list, message: str):
|
||||||
for c in clients:
|
for c in clients:
|
||||||
|
if client_sockets[c].isLobby() and client_sockets[c].client.auth:
|
||||||
send(c, message)
|
send(c, message)
|
||||||
|
|
||||||
|
|
||||||
def sendSessions(client: socket):
|
def sendRooms(client: socket):
|
||||||
msg2 = ""
|
msg2 = ""
|
||||||
counter = 0
|
counter = 0
|
||||||
for s in sessions.values():
|
for s in rooms.values():
|
||||||
if not s.started:
|
if not s.started:
|
||||||
msg2 += f":{s.name}:{s.joined}:{s.total}:{s.protected}"
|
msg2 += f":{s.name}:{s.joined}:{s.total}:{s.protected}"
|
||||||
counter += 1
|
counter += 1
|
||||||
@ -176,158 +249,166 @@ def sendSessions(client: socket):
|
|||||||
send(client, msg)
|
send(client, msg)
|
||||||
|
|
||||||
|
|
||||||
def updateSessions():
|
def updateRooms():
|
||||||
for s in client_sockets.keys():
|
for s in client_sockets.keys():
|
||||||
sendSessions(s)
|
sendRooms(s)
|
||||||
|
|
||||||
|
|
||||||
def deleteSession(session: Session):
|
def deleteRoom(room: Room):
|
||||||
msg = f":>>KICK:{session.name}"
|
msg = f":>>KICK:{room.name}"
|
||||||
for player in session.players:
|
for player in room.players:
|
||||||
client_sockets[player]["joined"] = False
|
client_sockets[player].client.joined = False
|
||||||
msg2 = msg + f":{client_sockets[player]['username']}"
|
msg2 = msg + f":{client_sockets[player].client.username}"
|
||||||
send(player, msg2)
|
send(player, msg2)
|
||||||
|
|
||||||
sessions.pop(session.name)
|
rooms.pop(room.name)
|
||||||
|
|
||||||
|
|
||||||
def updateStatus(session: Session):
|
def updateStatus(room: Room):
|
||||||
msg = f":>>STATUS:{session.joined}"
|
msg = f":>>STATUS:{room.joined}"
|
||||||
for player in session.players:
|
for player in room.players:
|
||||||
msg += f":{client_sockets[player]['username']}:{client_sockets[player]['ready']}"
|
msg += f":{client_sockets[player].client.username}:{client_sockets[player].client.ready}"
|
||||||
broadcast(session.players, msg)
|
broadcast(room.players, msg)
|
||||||
|
|
||||||
|
|
||||||
def startSession(session: Session):
|
def startRoom(room: Room):
|
||||||
session.started = True
|
room.started = True
|
||||||
|
session = Session()
|
||||||
|
session.name = room.name
|
||||||
|
sessions.append(session)
|
||||||
session.host_uuid = str(uuid.uuid4())
|
session.host_uuid = str(uuid.uuid4())
|
||||||
hostMessage = f":>>HOST:{session.host_uuid}:{session.joined - 1}" #one client will be connected locally
|
hostMessage = f":>>HOST:{session.host_uuid}:{room.joined - 1}" #one client will be connected locally
|
||||||
#host message must be before start message
|
#host message must be before start message
|
||||||
send(session.host, hostMessage)
|
send(room.host, hostMessage)
|
||||||
|
|
||||||
for player in session.players:
|
for player in room.players:
|
||||||
client_sockets[player]['uuid'] = str(uuid.uuid4())
|
_uuid = str(uuid.uuid4())
|
||||||
msg = f":>>START:{client_sockets[player]['uuid']}"
|
session.clients_uuid.append(_uuid)
|
||||||
|
msg = f":>>START:{_uuid}"
|
||||||
send(player, msg)
|
send(player, msg)
|
||||||
|
#remove this connection
|
||||||
|
player.close
|
||||||
|
client_sockets.pop(player)
|
||||||
|
|
||||||
|
#this room shall not exist anymore
|
||||||
|
rooms.pop(room.name)
|
||||||
|
|
||||||
|
|
||||||
def dispatch(client: socket, sender: dict, arr: bytes):
|
def dispatch(cs: socket, sender: Sender, arr: bytes):
|
||||||
|
|
||||||
if arr == None or len(arr) == 0:
|
if arr == None or len(arr) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
print(f"[{sender['address']}] dispatching message")
|
|
||||||
|
|
||||||
#check for game mode connection
|
#check for game mode connection
|
||||||
msg = str(arr)
|
msg = str(arr)
|
||||||
if msg.find("Aiya!") != -1:
|
if msg.find("Aiya!") != -1:
|
||||||
sender["pipe"] = True #switch to pipe mode
|
sender.client = ClientPipe()
|
||||||
print(" vcmi recognized")
|
print(" vcmi recognized")
|
||||||
|
|
||||||
if sender["pipe"]:
|
if sender.isPipe():
|
||||||
if sender["game"]: #if already playing - sending raw bytes as is
|
if sender.client.auth: #if already playing - sending raw bytes as is
|
||||||
sender["prevmessages"].append(arr)
|
sender.client.prevmessages.append(arr)
|
||||||
print(" storing message")
|
print(" storing message")
|
||||||
else:
|
else:
|
||||||
sender["prevmessages"].append(struct.pack('<I', len(arr)) + arr) #pack message
|
sender.client.prevmessages.append(struct.pack('<I', len(arr)) + arr) #pack message
|
||||||
print(" packing message")
|
print(" packing message")
|
||||||
#search fo application type in the message
|
#search fo application type in the message
|
||||||
match = re.search(r"\((\w+)\)", msg)
|
match = re.search(r"\((\w+)\)", msg)
|
||||||
_appType = ''
|
_appType = ''
|
||||||
if match != None:
|
if match != None:
|
||||||
_appType = match.group(1)
|
_appType = match.group(1)
|
||||||
sender["apptype"] = _appType
|
sender.client.apptype = _appType
|
||||||
|
|
||||||
#extract uuid from message
|
#extract uuid from message
|
||||||
_uuid = arr.decode()
|
_uuid = arr.decode()
|
||||||
print(f" decoding {_uuid}")
|
print(f" decoding {_uuid}")
|
||||||
if not _uuid == '' and not sender["apptype"] == '':
|
if not _uuid == '' and not sender.client.apptype == '':
|
||||||
#search for uuid
|
#search for uuid
|
||||||
for session in sessions.values():
|
for session in sessions:
|
||||||
if session.started:
|
|
||||||
#verify uuid of connected application
|
#verify uuid of connected application
|
||||||
if _uuid.find(session.host_uuid) != -1 and sender["apptype"] == "server":
|
if _uuid.find(session.host_uuid) != -1 and sender.client.apptype == "server":
|
||||||
print(f" apptype {sender['apptype']} uuid {_uuid}")
|
print(f" apptype {sender.client.apptype} uuid {_uuid}")
|
||||||
session.addConnection(client, True)
|
session.addConnection(cs, True)
|
||||||
sender["session"] = session
|
sender.client.session = session
|
||||||
sender["game"] = True
|
sender.client.auth = True
|
||||||
#read boolean flag for the endian
|
#read boolean flag for the endian
|
||||||
# this is workaround to send only one remaining byte
|
# this is workaround to send only one remaining byte
|
||||||
# WARNING: reversed byte order is not supported
|
# WARNING: reversed byte order is not supported
|
||||||
sender["prevmessages"].append(client.recv(1))
|
sender.client.prevmessages.append(cs.recv(1))
|
||||||
print(f" binding server connection to session {session.name}")
|
print(f" binding server connection to session {session.name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
if sender["apptype"] == "client":
|
if sender.client.apptype == "client":
|
||||||
for p in session.players:
|
for p in session.clients_uuid:
|
||||||
if _uuid.find(client_sockets[p]["uuid"]) != -1:
|
if _uuid.find(p) != -1:
|
||||||
print(f" apptype {sender['apptype']} uuid {_uuid}")
|
print(f" apptype {sender.client.apptype} uuid {_uuid}")
|
||||||
#client connection
|
#client connection
|
||||||
session.addConnection(client, False)
|
session.addConnection(cs, False)
|
||||||
sender["session"] = session
|
sender.client.session = session
|
||||||
sender["game"] = True
|
sender.client.auth = True
|
||||||
#read boolean flag for the endian
|
#read boolean flag for the endian
|
||||||
# this is workaround to send only one remaining byte
|
# this is workaround to send only one remaining byte
|
||||||
# WARNING: reversed byte order is not supported
|
# WARNING: reversed byte order is not supported
|
||||||
sender["prevmessages"].append(client.recv(1))
|
sender.client.prevmessages.append(cs.recv(1))
|
||||||
print(f" binding client connection to session {session.name}")
|
print(f" binding client connection to session {session.name}")
|
||||||
break
|
break
|
||||||
|
|
||||||
#game mode
|
#game mode
|
||||||
if sender["pipe"] and sender["game"] and sender["session"].validPipe(client):
|
if sender.isPipe() and sender.client.auth and sender.client.session.validPipe(cs):
|
||||||
print(f" pipe for {sender['session'].name}")
|
|
||||||
#send messages from queue
|
#send messages from queue
|
||||||
opposite = sender["session"].getPipe(client)
|
opposite = sender.client.session.getPipe(cs)
|
||||||
for x in client_sockets[opposite]["prevmessages"]:
|
for x in client_sockets[opposite].client.prevmessages:
|
||||||
client.sendall(x)
|
cs.sendall(x)
|
||||||
client_sockets[opposite]["prevmessages"].clear()
|
client_sockets[opposite].client.prevmessages.clear()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for x in sender["prevmessages"]:
|
for x in sender.client.prevmessages:
|
||||||
opposite.sendall(x)
|
opposite.sendall(x)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[!] Error: {e}")
|
print(f"[!] Error: {e}")
|
||||||
#TODO: handle disconnection
|
#TODO: handle disconnection
|
||||||
|
|
||||||
sender["prevmessages"].clear()
|
sender.client.prevmessages.clear()
|
||||||
return
|
return
|
||||||
|
|
||||||
#we are in pipe mode but game still not started - waiting other clients to connect
|
#we are in pipe mode but game still not started - waiting other clients to connect
|
||||||
if sender["pipe"]:
|
if sender.isPipe():
|
||||||
print(f" waiting other clients")
|
print(f" waiting other clients")
|
||||||
return
|
return
|
||||||
|
|
||||||
#lobby mode
|
#intialize lobby mode
|
||||||
if not sender["auth"]:
|
if not sender.isLobby():
|
||||||
if len(arr) < 2:
|
if len(arr) < 2:
|
||||||
print("[!] Error: unknown client tries to connect")
|
print("[!] Error: unknown client tries to connect")
|
||||||
#TODO: block address? close the socket?
|
#TODO: block address? close the socket?
|
||||||
return
|
return
|
||||||
|
|
||||||
|
sender.client = ClientLobby()
|
||||||
|
|
||||||
# first byte is protocol version
|
# first byte is protocol version
|
||||||
sender["protocol_version"] = arr[0]
|
sender.client.protocolVersion = arr[0]
|
||||||
if arr[0] < PROTOCOL_VERSION_MIN or arr[0] > PROTOCOL_VERSION_MAX:
|
if arr[0] < PROTOCOL_VERSION_MIN or arr[0] > PROTOCOL_VERSION_MAX:
|
||||||
print(f"[!] Error: client has incompatbile protocol version {arr[0]}")
|
print(f"[!] Error: client has incompatbile protocol version {arr[0]}")
|
||||||
send(client, ":>>ERROR:Cannot connect to remote server due to protocol incompatibility")
|
send(cs, ":>>ERROR:Cannot connect to remote server due to protocol incompatibility")
|
||||||
return
|
return
|
||||||
|
|
||||||
# second byte is a encoding str size
|
# second byte is an encoding str size
|
||||||
if arr[1] == 0:
|
if arr[1] == 0:
|
||||||
sender["encoding"] = "utf8"
|
sender.client.encoding = "utf8"
|
||||||
else:
|
else:
|
||||||
if len(arr) < arr[1] + 2:
|
if len(arr) < arr[1] + 2:
|
||||||
send(client, ":>>ERROR:Protocol error")
|
send(cs, ":>>ERROR:Protocol error")
|
||||||
return
|
return
|
||||||
|
# read encoding string
|
||||||
sender["encoding"] = arr[2:(arr[1] + 2)].decode(errors='ignore')
|
sender.client.encoding = arr[2:(arr[1] + 2)].decode(errors='ignore')
|
||||||
arr = arr[(arr[1] + 2):]
|
arr = arr[(arr[1] + 2):]
|
||||||
msg = str(arr)
|
msg = str(arr)
|
||||||
|
|
||||||
msg = arr.decode(encoding=sender["encoding"], errors='replace')
|
msg = arr.decode(encoding=sender.client.encoding, errors='replace')
|
||||||
_open = msg.partition('<')
|
_open = msg.partition('<')
|
||||||
_close = _open[2].partition('>')
|
_close = _open[2].partition('>')
|
||||||
if _open[0] != '' or _open[1] == '' or _open[2] == '' or _close[0] == '' or _close[1] == '':
|
if _open[0] != '' or _open[1] == '' or _open[2] == '' or _close[0] == '' or _close[1] == '':
|
||||||
print(f"[!] Incorrect message from {sender['address']}: {msg}")
|
print(f"[!] Incorrect message from {sender.address}: {msg}")
|
||||||
return
|
return
|
||||||
|
|
||||||
_nextTag = _close[2].partition('<')
|
_nextTag = _close[2].partition('<')
|
||||||
@ -336,127 +417,128 @@ def dispatch(client: socket, sender: dict, arr: bytes):
|
|||||||
|
|
||||||
#greetings to the server
|
#greetings to the server
|
||||||
if tag == "GREETINGS":
|
if tag == "GREETINGS":
|
||||||
if sender["auth"]:
|
if sender.client.auth:
|
||||||
print(f"[!] Greetings from authorized user {sender['username']} {sender['address']}")
|
print(f"[!] Greetings from authorized user {sender.client.username} {sender.address}")
|
||||||
send(client, ":>>ERROR:User already authorized")
|
send(cs, ":>>ERROR:User already authorized")
|
||||||
return
|
return
|
||||||
|
|
||||||
if len(tag_value) < 3:
|
if len(tag_value) < 3:
|
||||||
send(client, f":>>ERROR:Too short username {tag_value}")
|
send(cs, f":>>ERROR:Too short username {tag_value}")
|
||||||
return
|
return
|
||||||
|
|
||||||
for user in client_sockets.values():
|
for user in client_sockets.values():
|
||||||
if user['username'] == tag_value:
|
if user.isLobby() and user.client.username == tag_value:
|
||||||
send(client, f":>>ERROR:Can't connect with the name {tag_value}. This login is already occpupied")
|
send(cs, f":>>ERROR:Can't connect with the name {tag_value}. This login is already occpupied")
|
||||||
return
|
return
|
||||||
|
|
||||||
print(f"[*] User {sender['address']} autorized as {tag_value}")
|
print(f"[*] {sender.address} autorized as {tag_value}")
|
||||||
sender["username"] = tag_value
|
sender.client.username = tag_value
|
||||||
sender["auth"] = True
|
sender.client.auth = True
|
||||||
sender["joined"] = False
|
sendRooms(cs)
|
||||||
sendSessions(client)
|
|
||||||
|
|
||||||
#VCMI version received
|
#VCMI version received
|
||||||
if tag == "VER" and sender["auth"]:
|
if tag == "VER" and sender.client.auth:
|
||||||
print(f"[*] User {sender['username']} has version {tag_value}")
|
print(f"[*] User {sender.client.username} has version {tag_value}")
|
||||||
|
sender.client.vcmiversion = tag_value
|
||||||
|
|
||||||
#message received
|
#message received
|
||||||
if tag == "MSG" and sender["auth"]:
|
if tag == "MSG" and sender.client.auth:
|
||||||
message = f":>>MSG:{sender['username']}:{tag_value}"
|
message = f":>>MSG:{sender.client.username}:{tag_value}"
|
||||||
if sender["joined"]:
|
if sender.client.joined:
|
||||||
broadcast(sender["session"].players, message)
|
broadcast(sender.client.room.players, message) #send message only to players in the room
|
||||||
else:
|
else:
|
||||||
broadcast(client_sockets.keys(), message)
|
targetClients = [i for i in client_sockets.keys() if not client_sockets[i].client.joined]
|
||||||
|
broadcast(targetClients, message)
|
||||||
|
|
||||||
#new session
|
#new room
|
||||||
if tag == "NEW" and sender["auth"] and not sender["joined"]:
|
if tag == "NEW" and sender.client.auth and not sender.client.joined:
|
||||||
if tag_value in sessions:
|
if tag_value in rooms:
|
||||||
#refuse creating game
|
#refuse creating game
|
||||||
message = f":>>ERROR:Cannot create session with name {tag_value}, session with this name already exists"
|
message = f":>>ERROR:Cannot create session with name {tag_value}, session with this name already exists"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
return
|
return
|
||||||
|
|
||||||
sessions[tag_value] = Session(client, tag_value)
|
rooms[tag_value] = Room(cs, tag_value)
|
||||||
sender["joined"] = True
|
sender.client.joined = True
|
||||||
sender["ready"] = False
|
sender.client.ready = False
|
||||||
sender["session"] = sessions[tag_value]
|
sender.client.room = rooms[tag_value]
|
||||||
|
|
||||||
#set password for the session
|
#set password for the session
|
||||||
if tag == "PSWD" and sender["auth"] and sender["joined"] and sender["session"].host == client:
|
if tag == "PSWD" and sender.client.auth and sender.client.joined and sender.client.room.host == cs:
|
||||||
sender["session"].password = tag_value
|
sender.client.room.password = tag_value
|
||||||
sender["session"].protected = tag_value != ""
|
sender.client.room.protected = bool(tag_value != "")
|
||||||
|
|
||||||
#set amount of players to the new session
|
#set amount of players to the new room
|
||||||
if tag == "COUNT" and sender["auth"] and sender["joined"] and sender["session"].host == client:
|
if tag == "COUNT" and sender.client.auth and sender.client.joined and sender.client.room.host == cs:
|
||||||
if sender["session"].total != 1:
|
if sender.client.room.total != 1:
|
||||||
#refuse changing amount of players
|
#refuse changing amount of players
|
||||||
message = f":>>ERROR:Changing amount of players is not possible for existing session"
|
message = f":>>ERROR:Changing amount of players is not possible for existing session"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
return
|
return
|
||||||
|
|
||||||
sender["session"].total = int(tag_value)
|
sender.client.room.total = int(tag_value)
|
||||||
message = f":>>CREATED:{sender['session'].name}"
|
message = f":>>CREATED:{sender.client.room.name}"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
#now session is ready to be broadcasted
|
#now room is ready to be broadcasted
|
||||||
message = f":>>JOIN:{sender['session'].name}:{sender['username']}"
|
message = f":>>JOIN:{sender.client.room.name}:{sender.client.username}"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
updateStatus(sender["session"])
|
updateStatus(sender.client.room)
|
||||||
updateSessions()
|
updateRooms()
|
||||||
|
|
||||||
#join session
|
#join session
|
||||||
if tag == "JOIN" and sender["auth"] and not sender["joined"]:
|
if tag == "JOIN" and sender.client.auth and not sender.client.joined:
|
||||||
if tag_value not in sessions:
|
if tag_value not in rooms:
|
||||||
message = f":>>ERROR:Session with name {tag_value} doesn't exist"
|
message = f":>>ERROR:Room with name {tag_value} doesn't exist"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
return
|
return
|
||||||
|
|
||||||
if sessions[tag_value].joined >= sessions[tag_value].total:
|
if rooms[tag_value].joined >= rooms[tag_value].total:
|
||||||
message = f":>>ERROR:Session {tag_value} is full"
|
message = f":>>ERROR:Room {tag_value} is full"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
return
|
return
|
||||||
|
|
||||||
if sessions[tag_value].started:
|
if rooms[tag_value].started:
|
||||||
message = f":>>ERROR:Session {tag_value} is started"
|
message = f":>>ERROR:Session {tag_value} is started"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
return
|
return
|
||||||
|
|
||||||
sender["joined"] = True
|
sender.client.joined = True
|
||||||
sender["ready"] = False
|
sender.client.ready = False
|
||||||
sender["session"] = sessions[tag_value]
|
sender.client.room = rooms[tag_value]
|
||||||
|
|
||||||
if tag == "PSWD" and sender["auth"] and sender["joined"] and sender["session"].host != client:
|
if tag == "PSWD" and sender.client.auth and sender.client.joined and sender.client.room.host != cs:
|
||||||
if not sender["session"].protected or sender["session"].password == tag_value:
|
if not sender.client.room.protected or sender.client.room.password == tag_value:
|
||||||
sender["session"].join(client)
|
sender.client.room.join(cs)
|
||||||
message = f":>>JOIN:{sender['session'].name}:{sender['username']}"
|
message = f":>>JOIN:{sender.client.room.name}:{sender.client.username}"
|
||||||
broadcast(sender["session"].players, message)
|
broadcast(sender.client.room.players, message)
|
||||||
updateStatus(sender["session"])
|
updateStatus(sender.client.room)
|
||||||
updateSessions()
|
updateRooms()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
sender["joined"] = False
|
sender.client.joined = False
|
||||||
message = f":>>ERROR:Incorrect password"
|
message = f":>>ERROR:Incorrect password"
|
||||||
send(client, message)
|
send(cs, message)
|
||||||
return
|
return
|
||||||
|
|
||||||
#leaving session
|
#leaving session
|
||||||
if tag == "LEAVE" and sender["auth"] and sender["joined"] and sender["session"].name == tag_value:
|
if tag == "LEAVE" and sender.client.auth and sender.client.joined and sender.client.room.name == tag_value:
|
||||||
if sender["session"].host == client:
|
if sender.client.room.host == cs:
|
||||||
#destroy the session, sending messages inside the function
|
#destroy the session, sending messages inside the function
|
||||||
deleteSession(sender["session"])
|
deleteRoom(sender.client.room)
|
||||||
else:
|
else:
|
||||||
message = f":>>KICK:{sender['session'].name}:{sender['username']}"
|
message = f":>>KICK:{sender.client.room.name}:{sender.client.username}"
|
||||||
broadcast(sender["session"].players, message)
|
broadcast(sender.client.room.players, message)
|
||||||
sender["session"].leave(client)
|
sender.client.room.leave(cs)
|
||||||
sender["joined"] = False
|
sender.client.joined = False
|
||||||
updateStatus(sender["session"])
|
updateStatus(sender.client.room)
|
||||||
updateSessions()
|
updateRooms()
|
||||||
|
|
||||||
if tag == "READY" and sender["auth"] and sender["joined"] and sender["session"].name == tag_value:
|
if tag == "READY" and sender.client.auth and sender.client.joined and sender.client.room.name == tag_value:
|
||||||
if sender["session"].joined > 0 and sender["session"].host == client:
|
if sender.client.room.joined > 0 and sender.client.room.host == cs:
|
||||||
startSession(sender["session"])
|
startRoom(sender.client.room)
|
||||||
updateSessions()
|
updateRooms()
|
||||||
|
|
||||||
dispatch(client, sender, (_nextTag[1] + _nextTag[2]).encode())
|
dispatch(cs, sender, (_nextTag[1] + _nextTag[2]).encode())
|
||||||
|
|
||||||
|
|
||||||
def listen_for_client(cs):
|
def listen_for_client(cs):
|
||||||
@ -467,25 +549,32 @@ def listen_for_client(cs):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
# keep listening for a message from `cs` socket
|
# keep listening for a message from `cs` socket
|
||||||
if client_sockets[cs]["game"]:
|
if client_sockets[cs].isPipe() and client_sockets[cs].client.auth:
|
||||||
msg = cs.recv(4096)
|
msg = cs.recv(4096)
|
||||||
else:
|
else:
|
||||||
msg = recv_msg(cs)
|
msg = receive_packed(cs)
|
||||||
|
|
||||||
|
if msg == None or msg == b'':
|
||||||
|
print(f"[!] Disconnecting client {cs}")
|
||||||
|
handleDisconnection(cs)
|
||||||
|
return
|
||||||
|
|
||||||
|
dispatch(cs, client_sockets[cs], msg)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# client no longer connected
|
# client no longer connected
|
||||||
print(f"[!] Error: {e}")
|
print(f"[!] Error: {e}")
|
||||||
handleDisconnection(cs)
|
handleDisconnection(cs)
|
||||||
return
|
return
|
||||||
|
|
||||||
dispatch(cs, client_sockets[cs], msg)
|
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# we keep listening for new connections all the time
|
# we keep listening for new connections all the time
|
||||||
client_socket, client_address = s.accept()
|
client_socket, client_address = s.accept()
|
||||||
print(f"[+] {client_address} connected.")
|
print(f"[+] {client_address} connected.")
|
||||||
# add the new connected client to connected sockets
|
# add the new connected client to connected sockets
|
||||||
client_sockets[client_socket] = {"address": client_address, "auth": False, "username": "", "joined": False, "game": False, "pipe": False, "apptype": "", "prevmessages": []}
|
client_sockets[client_socket] = Sender()
|
||||||
|
client_sockets[client_socket].address = client_address
|
||||||
# start a new thread that listens for each client's messages
|
# start a new thread that listens for each client's messages
|
||||||
t = Thread(target=listen_for_client, args=(client_socket,))
|
t = Thread(target=listen_for_client, args=(client_socket,))
|
||||||
# make the thread daemon so it ends whenever the main thread ends
|
# make the thread daemon so it ends whenever the main thread ends
|
||||||
|
Loading…
Reference in New Issue
Block a user