mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-25 22:42:04 +02:00
First working prototype
This commit is contained in:
@@ -61,7 +61,10 @@ void SocketLobby::requestReadySession(const QString & session)
|
|||||||
|
|
||||||
void SocketLobby::send(const QString & msg)
|
void SocketLobby::send(const QString & msg)
|
||||||
{
|
{
|
||||||
socket->write(qPrintable(msg));
|
int sz = msg.size();
|
||||||
|
QByteArray pack((const char *)&sz, sizeof(sz));
|
||||||
|
pack.append(qPrintable(msg));
|
||||||
|
socket->write(pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketLobby::connected()
|
void SocketLobby::connected()
|
||||||
|
|||||||
@@ -4,12 +4,39 @@ from pickletools import bytes8
|
|||||||
import socket
|
import socket
|
||||||
import re
|
import re
|
||||||
import uuid
|
import uuid
|
||||||
|
import struct
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
# server's IP address
|
# server's IP address
|
||||||
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):
|
||||||
|
# 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
|
||||||
|
raw_msglen = recvall(sock, 4)
|
||||||
|
if not raw_msglen:
|
||||||
|
return None
|
||||||
|
msglen = struct.unpack('<I', raw_msglen)[0]
|
||||||
|
# Read the message data
|
||||||
|
return recvall(sock, msglen)
|
||||||
|
|
||||||
|
def recvall(sock, n):
|
||||||
|
# Helper function to recv n bytes or return None if EOF is hit
|
||||||
|
data = bytearray()
|
||||||
|
while len(data) < n:
|
||||||
|
packet = sock.recv(n - len(data))
|
||||||
|
if not packet:
|
||||||
|
return None
|
||||||
|
data.extend(packet)
|
||||||
|
return data
|
||||||
|
|
||||||
# initialize list/set of all connected client's sockets
|
# initialize list/set of all connected client's sockets
|
||||||
client_sockets = dict()
|
client_sockets = dict()
|
||||||
|
|
||||||
@@ -23,6 +50,8 @@ class GameConnection:
|
|||||||
messageQueueOut = []
|
messageQueueOut = []
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
self.server = None
|
||||||
|
self.client = None
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Session:
|
class Session:
|
||||||
@@ -188,62 +217,81 @@ def startSession(session: Session):
|
|||||||
|
|
||||||
|
|
||||||
def dispatch(client: socket, sender: dict, arr: bytes):
|
def dispatch(client: socket, sender: dict, arr: bytes):
|
||||||
if len(arr) == 0:
|
|
||||||
|
if arr == None or len(arr) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
msg = str(arr)
|
#if len(sender["prevmessages"]):
|
||||||
print(msg)
|
# arr = sender["prevmessages"] + arr
|
||||||
if msg[-1] == '\n' or (msg[-1] == '\'' and msg[-2] == '\n'):
|
# sender["prevmessages"] = bytes()
|
||||||
sender["prevmessage"] += msg
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
msg = f"{sender['prevmessage']}{msg}"
|
|
||||||
sender["prevmessage"] = ""
|
|
||||||
|
|
||||||
#check for game mode connection
|
#check for game mode connection
|
||||||
_gameModeIdentifier = msg.partition('Aiya!')
|
msg = str(arr)
|
||||||
if _gameModeIdentifier[0] != '' and _gameModeIdentifier[1] == 'Aiya!':
|
if msg.find("Aiya!") != -1:
|
||||||
sender["aiya"] = True
|
sender["pipe"] = True
|
||||||
|
|
||||||
if sender["aiya"]:
|
if sender["pipe"]:
|
||||||
_uuid = msg.partition('$')[2]
|
if sender["game"]:
|
||||||
match = re.search(r"\((\w+)\)", msg)
|
sender["prevmessages"].append(arr)
|
||||||
_appType = ''
|
else:
|
||||||
if match != None:
|
sender["prevmessages"].append(struct.pack('<I', len(arr)) + arr)
|
||||||
_appType = match.group(1)
|
match = re.search(r"\((\w+)\)", msg)
|
||||||
if not _uuid == '' and not _appType == '':
|
_appType = ''
|
||||||
#search for uuid
|
if match != None:
|
||||||
for session in sessions.values():
|
_appType = match.group(1)
|
||||||
if session.started:
|
sender["apptype"] = _appType
|
||||||
if _uuid.find(session.host_uuid) != -1 and _appType == "server":
|
|
||||||
gc = session.addConnection(client, True)
|
_uuid = arr.decode()
|
||||||
for qmsg in gc.messageQueueIn:
|
if not _uuid == '' and not sender["apptype"] == '':
|
||||||
send(gc.server, qmsg)
|
#search for uuid
|
||||||
sender["session"] = session
|
for session in sessions.values():
|
||||||
sender["game"] = True
|
if session.started:
|
||||||
if not gc.clientInit:
|
if _uuid.find(session.host_uuid) != -1 and sender["apptype"] == "server":
|
||||||
gc.messageQueueOut.append(arr)
|
gc = session.addConnection(client, True)
|
||||||
return
|
#send_msg(gc.server, gc.messageQueueIn)
|
||||||
|
#gc.messageQueueIn = bytes()
|
||||||
|
sender["session"] = session
|
||||||
|
sender["game"] = True
|
||||||
|
#read boolean flag for the endian
|
||||||
|
sender["prevmessages"].append(client.recv(1))
|
||||||
|
#if not gc.clientInit:
|
||||||
|
# gc.messageQueueOut += arr
|
||||||
|
return
|
||||||
|
|
||||||
if _appType == "client":
|
if sender["apptype"] == "client":
|
||||||
for p in session.players:
|
for p in session.players:
|
||||||
if _uuid.find(client_sockets[p]["uuid"]) != -1:
|
if _uuid.find(client_sockets[p]["uuid"]) != -1:
|
||||||
#client connection
|
#client connection
|
||||||
gc = session.addConnection(client, False)
|
gc = session.addConnection(client, False)
|
||||||
for qmsg in gc.messageQueueOut:
|
#send_msg(gc.client, gc.messageQueueOut)
|
||||||
send(gc.client, qmsg)
|
#gc.messageQueueOut = bytes()
|
||||||
sender["session"] = session
|
sender["session"] = session
|
||||||
sender["game"] = True
|
sender["game"] = True
|
||||||
if not gc.serverInit:
|
#read boolean flag for the endian
|
||||||
gc.messageQueueIn.append(arr)
|
sender["prevmessages"].append(client.recv(1))
|
||||||
return
|
#if not gc.serverInit:
|
||||||
break
|
# gc.messageQueueIn += arr
|
||||||
|
# return
|
||||||
|
break
|
||||||
|
|
||||||
#game mode
|
#game mode
|
||||||
if sender["game"] and sender["session"].validPipe(client):
|
if sender["pipe"] and sender["game"] and sender["session"].validPipe(client):
|
||||||
sender["session"].getPipe(client).send(arr)
|
#send messages from queue
|
||||||
|
opposite = sender["session"].getPipe(client)
|
||||||
|
for x in client_sockets[opposite]["prevmessages"]:
|
||||||
|
client.sendall(x)
|
||||||
|
client_sockets[opposite]["prevmessages"].clear()
|
||||||
|
|
||||||
|
try:
|
||||||
|
for x in sender["prevmessages"]:
|
||||||
|
opposite.sendall(x)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[!] Error: {e}")
|
||||||
|
sender["prevmessages"].clear()
|
||||||
|
return
|
||||||
|
|
||||||
|
if sender["pipe"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
#lobby mode
|
#lobby mode
|
||||||
msg = arr.decode()
|
msg = arr.decode()
|
||||||
@@ -377,7 +425,11 @@ 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
|
||||||
msg = cs.recv(2048)
|
if client_sockets[cs]["game"]:
|
||||||
|
msg = cs.recv(4096)
|
||||||
|
else:
|
||||||
|
msg = recv_msg(cs)
|
||||||
|
#msg = cs.recv(2048)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# client no longer connected
|
# client no longer connected
|
||||||
print(f"[!] Error: {e}")
|
print(f"[!] Error: {e}")
|
||||||
@@ -392,7 +444,7 @@ while True:
|
|||||||
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, "aiya": False, "prevmessage": "", "game": False}
|
client_sockets[client_socket] = {"address": client_address, "auth": False, "username": "", "joined": False, "game": False, "pipe": False, "apptype": "", "prevmessages": []}
|
||||||
# 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
|
||||||
|
|||||||
@@ -170,7 +170,8 @@ void CVCMIServer::run()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
startAsyncAccept();
|
startAsyncAccept();
|
||||||
establishRemoteConnections();
|
if(!remoteConnectionsThread)
|
||||||
|
remoteConnectionsThread = vstd::make_unique<boost::thread>(&CVCMIServer::establishRemoteConnections, this);
|
||||||
|
|
||||||
#if defined(VCMI_ANDROID)
|
#if defined(VCMI_ANDROID)
|
||||||
CAndroidVMHelper vmHelper;
|
CAndroidVMHelper vmHelper;
|
||||||
@@ -216,23 +217,21 @@ void CVCMIServer::establishRemoteConnections()
|
|||||||
void CVCMIServer::connectToRemote(const std::string & addr, int port)
|
void CVCMIServer::connectToRemote(const std::string & addr, int port)
|
||||||
{
|
{
|
||||||
std::shared_ptr<CConnection> c;
|
std::shared_ptr<CConnection> c;
|
||||||
int attempts = 10;
|
try
|
||||||
while(!c && attempts--)
|
|
||||||
{
|
{
|
||||||
try
|
logNetwork->info("Establishing connection...");
|
||||||
{
|
c = std::make_shared<CConnection>(addr, port, SERVER_NAME, uuid);
|
||||||
logNetwork->info("Establishing connection...");
|
}
|
||||||
c = std::make_shared<CConnection>(addr, port, SERVER_NAME, uuid);
|
catch(...)
|
||||||
}
|
{
|
||||||
catch(...)
|
logNetwork->error("\nCannot establish remote connection!");
|
||||||
{
|
|
||||||
logNetwork->error("\nCannot establish connection! Retrying within 1 second");
|
|
||||||
boost::this_thread::sleep(boost::posix_time::seconds(1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connections.insert(c);
|
if(c)
|
||||||
c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
|
{
|
||||||
|
connections.insert(c);
|
||||||
|
c->handler = std::make_shared<boost::thread>(&CVCMIServer::threadHandleClient, this, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVCMIServer::threadAnnounceLobby()
|
void CVCMIServer::threadAnnounceLobby()
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class CVCMIServer : public LobbyInfo
|
|||||||
std::list<std::unique_ptr<CPackForLobby>> announceQueue;
|
std::list<std::unique_ptr<CPackForLobby>> announceQueue;
|
||||||
boost::recursive_mutex mx;
|
boost::recursive_mutex mx;
|
||||||
std::shared_ptr<CApplier<CBaseForServerApply>> applier;
|
std::shared_ptr<CApplier<CBaseForServerApply>> applier;
|
||||||
std::unique_ptr<boost::thread> announceLobbyThread;
|
std::unique_ptr<boost::thread> announceLobbyThread, remoteConnectionsThread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<CGameHandler> gh;
|
std::shared_ptr<CGameHandler> gh;
|
||||||
|
|||||||
Reference in New Issue
Block a user