Skip to content

Commit c27952d

Browse files
authored
Merge pull request #234 from TUMFARSynchrony/ed-websocket-lobby-redirect
2 parents df94c8f + c6aba15 commit c27952d

File tree

4 files changed

+82
-1
lines changed

4 files changed

+82
-1
lines changed

backend/hub/hub.py

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import asyncio
66
import logging
77

8+
from jsonpickle import json
9+
810
from custom_types.message import MessageDict
911
from session.data.participant.participant_summary import ParticipantSummaryDict
1012
from connection.messages.rtc_ice_candidate_dict import RTCIceCandidateDict
@@ -122,6 +124,13 @@ def remove_experimenter(self, experimenter: Experimenter):
122124
"""
123125
self.experimenters.remove(experimenter)
124126

127+
async def notify_participants_experimenter_joined(self, message):
128+
"""Handle the event and broadcast a WebSocket message."""
129+
self._logger.info("Notifying participants experimenter joined")
130+
await self.server.broadcast_message(json.dumps(message))
131+
self._logger.info("Notified participants")
132+
133+
125134
async def handle_offer(
126135
self,
127136
offer: RTCSessionDescription,

backend/server/server.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import aiohttp_cors
55
import json
66
from typing import Any, Callable, Coroutine, Literal
7-
from aiohttp import web
7+
from aiohttp import web, WSMsgType
88
from datetime import datetime
99
from aiortc import RTCSessionDescription
1010
from ssl import SSLContext
@@ -64,12 +64,14 @@ def __init__(
6464
self._hub_handle_add_ice_candidate = hub_handle_add_ice_candidate
6565
self._config = config
6666

67+
self.websockets = set()
6768
self._app = web.Application()
6869
self._app.on_shutdown.append(self._shutdown)
6970
routes = [
7071
self._app.router.add_get("/hello-world", self.get_hello_world),
7172
self._app.router.add_post("/offer", self.handle_offer),
7273
self._app.router.add_post("/addIceCandidate", self.handle_add_ice_candidate),
74+
self._app.router.add_get('/ws', self.websocket_handler)
7375
]
7476

7577
# Serve frontend build
@@ -146,6 +148,28 @@ async def start(self):
146148
)
147149
await site.start()
148150

151+
async def websocket_handler(self, request):
152+
"""Handle incoming WebSocket connections."""
153+
ws = web.WebSocketResponse()
154+
await ws.prepare(request)
155+
self.websockets.add(ws)
156+
157+
async for msg in ws:
158+
if msg.type == WSMsgType.TEXT:
159+
# Handle incoming WebSocket messages if needed
160+
pass
161+
elif msg.type == WSMsgType.ERROR:
162+
print('WebSocket connection closed with exception %s' % ws.exception())
163+
164+
# Cleanup on disconnect
165+
self.websockets.remove(ws)
166+
return ws
167+
168+
async def broadcast_message(self, message):
169+
"""Send a message to all connected clients."""
170+
for ws in self.websockets:
171+
await ws.send_str(message)
172+
149173
async def _shutdown(self, app: web.Application):
150174
"""TODO document"""
151175
pass

backend/users/experimenter.py

+6
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ async def _handle_create_experiment(self, data: Any) -> MessageDict:
320320

321321
self._experiment = await self._hub.create_experiment(data["session_id"])
322322
self._experiment.add_experimenter(self)
323+
self._logger.info(f"sending ws message. {str(self)}")
324+
325+
await self._hub.notify_participants_experimenter_joined({"type": "EXPERIMENTER_JOINED"})
323326

324327
# Subscribe to participants in experiment
325328
await self._subscribe_to_participants_streams()
@@ -386,6 +389,9 @@ async def _handle_join_experiment(self, data: Any) -> MessageDict:
386389

387390
self._experiment = experiment
388391
self._experiment.add_experimenter(self)
392+
self._logger.info(f"sending ws message. {str(self)}")
393+
394+
await self._hub.notify_participants_experimenter_joined({"type": "EXPERIMENTER_JOINED"})
389395

390396
# Subscribe to participants in experiment
391397
await self._subscribe_to_participants_streams()

frontend/src/pages/Lobby/Lobby.js

+42
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { InstructionsTab } from "../../components/molecules/InstructionsTab/Inst
1313
import "./Lobby.css";
1414
import { ParticipantChatTab } from "../../components/molecules/ChatTab/ParticipantChatTab";
1515
import { ChatGptTab } from "../../components/molecules/ChatGptTab/ChatGptTab";
16+
import { BACKEND } from "../../utils/constants";
1617
import VideoCanvas from "../../components/organisms/VideoCanvas/VideoCanvas";
1718
import { ActionButton } from "../../components/atoms/Button";
1819

@@ -63,6 +64,47 @@ function Lobby({ localStream, connection, onGetSession, onChat }) {
6364
}
6465
}, [localStream, participantStream]);
6566

67+
useEffect(() => {
68+
const wsUrl = `${BACKEND.replace(/^http/, "ws")}/ws`;
69+
console.log(`Connecting to WebSocket at ${wsUrl}`);
70+
71+
console.log(`Attempting to connect to WebSocket at ${wsUrl}`);
72+
73+
const ws = new WebSocket(wsUrl);
74+
75+
ws.onopen = () => {
76+
console.log("WebSocket connection established");
77+
};
78+
79+
ws.onmessage = (event) => {
80+
const message = JSON.parse(event.data);
81+
if (message.type === "EXPERIMENTER_JOINED") {
82+
// Handle the experimenter joined message appropriately
83+
console.log("Experimenter connected");
84+
window.location.reload();
85+
}
86+
};
87+
88+
ws.onerror = (error) => {
89+
console.error("WebSocket error observed:", error);
90+
};
91+
92+
ws.onclose = (event) => {
93+
console.log("WebSocket connection closed:", event.reason);
94+
};
95+
96+
const handleUnload = () => {
97+
ws.close();
98+
};
99+
100+
window.addEventListener("beforeunload", handleUnload);
101+
102+
return () => {
103+
window.removeEventListener("beforeunload", handleUnload);
104+
ws.close();
105+
};
106+
}, []);
107+
66108
const streamChangeHandler = async () => {
67109
console.log("%cRemote Stream Change Handler", "color:blue");
68110
};

0 commit comments

Comments
 (0)