-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
169 lines (139 loc) · 5.3 KB
/
client.py
File metadata and controls
169 lines (139 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import asyncio
import pickle
from PyQt5.QtCore import QObject, pyqtSignal, QThread
from PyQt5.QtWidgets import QApplication
from online.networked_chess_board import NetworkedChessBoard
from online.network_gui import NetworkedChessBoardUI
from login_window import LoginWindow
import websockets
import sys
import json
import logging
import uuid
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
class WebSocketThread(QThread):
data_received = pyqtSignal(bytes)
move_to_send = None
def __init__(self, websocket_url: str, username: str):
super().__init__()
self.websocket_url = websocket_url
self.username = username
self.websocket = None
self.running = True
async def connect_and_receive(self):
"""Main async method for websocket operations"""
async with websockets.connect(self.websocket_url) as websocket:
self.websocket = websocket
while self.running:
try:
# Use _ for unused variable
_ = await websocket.receive()
# Handle message...
except Exception:
self.running = False
break
async def stop(self):
"""Async method to stop the websocket connection"""
self.running = False
if self.websocket:
await self.websocket.close()
def run(self):
"""Run in thread context"""
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(self.connect_and_receive())
def queue_move(self, move_data):
"""Queue a move to be sent in the websocket thread"""
self.move_to_send = move_data
class ChessClient(QObject):
def __init__(self, websocket_url: str, username: str):
super().__init__()
self.username = username
self.chess_board = NetworkedChessBoard(is_server=False)
self.chess_board_ui = NetworkedChessBoardUI()
self.websocket_thread = WebSocketThread(websocket_url, username)
# Connect the WebSocket thread signal to a handler
self.websocket_thread.data_received.connect(self.handle_data)
# Set the client reference in the UI
self.chess_board_ui.set_client(self)
# Start the WebSocket thread
self.websocket_thread.start()
# Show the UI
self.chess_board_ui.show()
def handle_data(self, data: bytes):
try:
move = pickle.loads(data)
self.chess_board.move_piece(*move)
self.chess_board_ui.update_ui()
except Exception as e:
logging.error(f"Error handling data: {e}")
def teardown(self):
self.websocket_thread.stop()
self.chess_board_ui.close()
async def send_message(self, message_type, **kwargs):
"""Send a message to the server"""
if not self.websocket_thread.websocket:
logger.error("Not connected to server")
return False
message = {"type": message_type, "username": self.username, **kwargs}
try:
await self.websocket_thread.websocket.send(json.dumps(message))
logger.debug(f"Sent message: {message}")
return True
except Exception as e:
logger.error(f"Error sending message: {e}")
return False
async def receive_message(self):
"""Receive a message from the server"""
if not self.websocket_thread.websocket:
logger.error("Not connected to server")
return None
try:
message = await self.websocket_thread.websocket.recv()
return json.loads(message)
except Exception as e:
logger.error(f"Error receiving message: {e}")
return None
def send_move(self, from_pos, to_pos):
"""Send a move to the server synchronously"""
message = {
"type": "move",
"username": self.username,
"move": {"from": from_pos, "to": to_pos},
}
self.websocket_thread.queue_move(message)
def start_chess_client(username):
# Get the websocket URL
if len(sys.argv) != 2:
# use production socket
server_url = "wss://appori2n7.azurewebsites.net/ws"
else:
server_url = sys.argv[1]
# Add client ID to the WebSocket URL
client_id = str(uuid.uuid4())
if not server_url.endswith("/"):
server_url += "/"
full_url = server_url + client_id
# Create chess client with authenticated username
global client
client = ChessClient(full_url, username)
if __name__ == "__main__":
app = QApplication(sys.argv)
# Check if running in test mode (add --test or -t flag)
if len(sys.argv) > 1 and sys.argv[1] in ["--test", "-t"]:
# Skip login and create chess client directly with test user
server_url = "ws://localhost:8000/ws" # Use local test server
client_id = str(uuid.uuid4())
full_url = f"{server_url}/{client_id}"
client = ChessClient(full_url, "test_user")
else:
# Normal login flow
login_window = LoginWindow()
login_window.login_successful.connect(start_chess_client)
login_window.show()
sys.exit(app.exec_())