Skip to content

Commit a2b4f1a

Browse files
authored
Merge pull request #37 from MomHelpMe/fix/michang
[FIX] 예외적인 동작에 대한 방어
2 parents 8e43f5d + 1afd10c commit a2b4f1a

10 files changed

Lines changed: 336 additions & 216 deletions

File tree

‎backend/game/matchingConsumers.py‎

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ async def initialize(self, user1, user2):
5454
self.left_ball = Ball(0, SCREEN_HEIGHT, SCREEN_WIDTH, self.left_bar)
5555
self.right_ball = Ball(1, SCREEN_HEIGHT, SCREEN_WIDTH, self.right_bar)
5656
self.score = [0, 0]
57-
print("user1:", user1, "user2:", user2)
57+
# print("user1:", user1, "user2:", user2)
5858
user1_nickname, user2_nickname = await get_user_nicknames(user1, user2)
59-
print("user1_nickname:", user1_nickname, "user2_nickname:", user2_nickname)
59+
# print("user1_nickname:", user1_nickname, "user2_nickname:", user2_nickname)
6060
self.player = [user1_nickname, user2_nickname]
6161
self.penalty_time = [0, 0]
6262
print("initializing game state finished successfully!")
@@ -75,8 +75,12 @@ async def connect(self):
7575
self.authenticated = False
7676
self.start_time = timezone.now()
7777

78+
if self.room_group_name not in MatchingGameConsumer.game_states:
79+
return
80+
7881
await self.accept()
7982

83+
8084
async def receive(self, text_data):
8185
text_data_json = json.loads(text_data)
8286
action = text_data_json["action"]
@@ -85,10 +89,9 @@ async def receive(self, text_data):
8589
token = text_data_json.get("token")
8690
if not token or not self.authenticate(token):
8791
print("authentication failed")
88-
await self.close(code=4001)
92+
# await self.close(code=4001)
8993
return
9094
self.authenticated = True
91-
self.my_uid = 0
9295

9396
# Join room group after successful authentication
9497
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
@@ -108,8 +111,6 @@ async def receive(self, text_data):
108111
MatchingGameConsumer.game_tasks[self.room_group_name] = (
109112
asyncio.create_task(self.game_loop())
110113
)
111-
elif not self.authenticated:
112-
await self.close(code=4001)
113114
else:
114115
bar = text_data_json.get("bar")
115116
state = MatchingGameConsumer.game_states[self.room_group_name]
@@ -158,22 +159,40 @@ def authenticate(self, token):
158159
return False
159160

160161
async def disconnect(self, close_code):
161-
# Leave room group
162+
# 인증된 소켓만 처리
162163
if self.authenticated:
163-
await self.channel_layer.group_discard(
164-
self.room_group_name, self.channel_name
165-
)
166-
# Decrease the client count for this room
164+
print("disconnected: ", self.user_index)
165+
await self.channel_layer.group_discard(self.room_group_name, self.channel_name)
166+
167+
# 현재 방의 접속자 수를 1 줄임
167168
if self.room_group_name in MatchingGameConsumer.client_counts:
168169
MatchingGameConsumer.client_counts[self.room_group_name] -= 1
169-
if MatchingGameConsumer.client_counts[self.room_group_name] <= 0:
170-
MatchingGameConsumer.game_tasks[self.room_group_name].cancel()
171-
del MatchingGameConsumer.game_tasks[self.room_group_name]
172-
del MatchingGameConsumer.game_states[self.room_group_name]
173-
del MatchingGameConsumer.client_counts[self.room_group_name]
170+
171+
# 만약 이제 방에 1명만 남았다면 -> 남은 사람이 승자
172+
if MatchingGameConsumer.client_counts[self.room_group_name] == 1:
173+
# 누가 남았는지 판별 (내가 0이라면 1이 승자, 내가 1이라면 0이 승자)
174+
winner_index = 1 - self.user_index
175+
state = MatchingGameConsumer.game_states[self.room_group_name]
176+
177+
# send_game_result를 통해 DB에 게임결과 저장 및
178+
# 나머지(승자)에게 게임 종료 메시지 전송
179+
await self.send_game_result(winner_index)
180+
await asyncio.sleep(0.1)
181+
await self.close()
182+
183+
# 아무도 안 남았다면 방을 완전히 정리
184+
elif MatchingGameConsumer.client_counts[self.room_group_name] <= 0:
185+
if self.room_group_name in MatchingGameConsumer.game_tasks:
186+
MatchingGameConsumer.game_tasks[self.room_group_name].cancel()
187+
del MatchingGameConsumer.game_tasks[self.room_group_name]
188+
if self.room_group_name in MatchingGameConsumer.game_states:
189+
del MatchingGameConsumer.game_states[self.room_group_name]
190+
if self.room_group_name in MatchingGameConsumer.client_counts:
191+
del MatchingGameConsumer.client_counts[self.room_group_name]
174192
else:
175193
MatchingGameConsumer.client_counts[self.room_group_name] = 0
176194

195+
177196
async def send_initialize_game(self):
178197
state = MatchingGameConsumer.game_states[self.room_group_name]
179198
await self.send(
@@ -248,6 +267,7 @@ async def game_loop(self):
248267
async def send_game_result(self, winner):
249268
state = MatchingGameConsumer.game_states[self.room_group_name]
250269

270+
print("Game result for", self.room_group_name, ":", state.score, "Winner:", winner)
251271
await self.save_game_result(state, winner)
252272
await self.channel_layer.group_send(
253273
self.room_group_name,
@@ -270,6 +290,10 @@ def save_game_result(self, state, winner):
270290
user2_obj = None
271291

272292
score1, score2 = state.score
293+
if winner == 0:
294+
score1 = MAX_SCORE
295+
else:
296+
score2 = MAX_SCORE
273297

274298
game = Game.objects.create(
275299
game_type="PvP",
@@ -300,16 +324,21 @@ async def game_result_message(self, event):
300324
score = event["score"]
301325
winner = event["winner"]
302326

303-
# Send the game result to the WebSocket
304-
await self.send(
305-
text_data=json.dumps(
306-
{
307-
"type": "game_result",
308-
"score": score,
309-
"winner": winner,
310-
}
327+
if not self.scope["client"]:
328+
return
329+
try:
330+
await self.send(
331+
text_data=json.dumps(
332+
{
333+
"type": "game_result",
334+
"score": score,
335+
"winner": winner,
336+
}
337+
)
311338
)
312-
)
339+
except Exception as e:
340+
print("Failed to send game_result_message:", e, "for", self.user_index)
341+
313342

314343
async def send_game_state(self):
315344
state = MatchingGameConsumer.game_states[self.room_group_name]

‎backend/game/onlineConsumers.py‎

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from django.conf import settings
66
from channels.exceptions import DenyConnection
77
from .matchingConsumers import MatchingGameConsumer, MatchingGameState
8+
import random
9+
import uuid
810

911

1012
class OnlineConsumer(AsyncWebsocketConsumer):
@@ -26,7 +28,7 @@ async def start_game(cls):
2628
user1 = cls.matching_queue.pop(0)
2729
user2 = cls.matching_queue.pop(0)
2830

29-
room_name = f"{user1.uid}_{user2.uid}"
31+
room_name = f"{user1.uid}_{user2.uid}_{str(uuid.uuid4())[:8]}"
3032

3133
game_state = MatchingGameState()
3234
await game_state.initialize(user1.uid, user2.uid) # 비동기 초기화
@@ -94,23 +96,28 @@ def authenticate(self, token):
9496
return False
9597

9698
async def enter_matching(self):
97-
# Add user to matching queue
98-
if self not in OnlineConsumer.matching_queue:
99-
OnlineConsumer.matching_queue.append(self)
100-
print(
101-
"Matching queue: ", [user.uid for user in OnlineConsumer.matching_queue]
102-
)
99+
for user in list(OnlineConsumer.matching_queue):
100+
if user.uid == self.uid:
101+
OnlineConsumer.matching_queue.remove(user)
102+
print(f"Replaced existing user {self.uid} in the matching queue.")
103+
break
104+
OnlineConsumer.matching_queue.append(self)
105+
print(
106+
"Matching queue: ", [user.uid for user in OnlineConsumer.matching_queue]
107+
)
103108

104109
async def leave_matching(self):
105-
# Remove user from matching queue
106-
if self in OnlineConsumer.matching_queue:
107-
OnlineConsumer.matching_queue.remove(self)
108-
print(f"User {self.uid} removed from matching queue")
109-
print(
110-
"Matching queue: ", [user.uid for user in OnlineConsumer.matching_queue]
111-
)
110+
for user in list(OnlineConsumer.matching_queue):
111+
if user.uid == self.uid:
112+
OnlineConsumer.matching_queue.remove(user)
113+
print(f"User {self.uid} removed from matching queue")
114+
break
115+
print(
116+
"Matching queue: ", [user.uid for user in OnlineConsumer.matching_queue]
117+
)
112118

113119
async def disconnect(self, close_code):
120+
await self.leave_matching()
114121
try:
115122
if self.uid in OnlineConsumer.online_user_list:
116123
OnlineConsumer.online_user_list.remove(self.uid)

‎backend/login/views.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@ def login(request):
2424
def callback(request):
2525
code = request.data.get("code")
2626
if not code:
27+
print("No code in request")
2728
return Response(status=401)
2829

2930
access_token = get_acccess_token(code)
3031
if not access_token:
32+
print("Failed to get access token!!!")
3133
return Response(status=401)
3234

3335
user_data = get_user_info(access_token)
3436
if not user_data:
37+
print("Failed to get user info")
3538
return Response(status=401)
3639

3740
user, created = get_or_save_user(user_data)

‎frontend/src/app.js‎

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { initializeRouter, createRoutes, changeUrl } from "./core/router.js";
2-
import { getCookie } from "./core/jwt.js";
1+
import { createRoutes } from "./core/router.js";
2+
import { showLoading } from "./core/showLoading.js";
33

44
class App {
55
app;
@@ -12,37 +12,6 @@ class App {
1212

1313
export const root = new App();
1414
export const routes = createRoutes(root);
15-
1615
export let socketList = [];
1716

18-
const closeAllSockets = () => {
19-
socketList.forEach(socket => {
20-
if (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) {
21-
socket.close();
22-
}
23-
});
24-
socketList = [];
25-
};
26-
27-
const online = () => {
28-
const onlineSocket = new WebSocket(
29-
'wss://'
30-
+ "localhost:443"
31-
+ '/ws/online/'
32-
);
33-
socketList.push(onlineSocket);
34-
35-
console.log(onlineSocket);
36-
onlineSocket.onopen = () => {
37-
const token = getCookie("jwt");
38-
onlineSocket.send(JSON.stringify({ 'action': 'authenticate', 'token': token }));
39-
};
40-
onlineSocket.onclose = () => {
41-
console.log("online socket closed");
42-
closeAllSockets();
43-
changeUrl("/error", false);
44-
};
45-
}
46-
47-
initializeRouter(routes);
48-
online();
17+
showLoading(routes, socketList);

0 commit comments

Comments
 (0)