Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backend/src/utils/socket.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ io.on("connection", (socket) => {
}
})

socket.on("disconnect", async (reason) => {
logger.info(`User disconnected ${socket.id} beacuse of ${reason}`)
socket.on("disconnect", async (reason, details) => {
logger.error(`User disconnected, ${socket.id} reason: ${reason} details: ${details}`)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Routine disconnections are now logged at error level. Disconnects are a normal event (user closes tab, network blip) and will be written to logs/error.log per the winston transport in logging.ts and counted by any error-based monitoring, flooding them with non-errors and masking real failures. Keep this at info, or add a separate debug/warn level if you need it prominent during the load test.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/src/utils/socket.util.ts, line 144:

<comment>Routine disconnections are now logged at `error` level. Disconnects are a normal event (user closes tab, network blip) and will be written to `logs/error.log` per the winston transport in `logging.ts` and counted by any error-based monitoring, flooding them with non-errors and masking real failures. Keep this at `info`, or add a separate debug/warn level if you need it prominent during the load test.</comment>

<file context>
@@ -140,8 +140,8 @@ io.on("connection", (socket) => {
-  socket.on("disconnect", async (reason) => {
-    logger.info(`User disconnected ${socket.id} beacuse of ${reason}`)
+  socket.on("disconnect", async (reason, details) => {
+    logger.error(`User disconnected, ${socket.id} reason: ${reason} details: ${details}`)
     handleDisconnect(socket)
     await stopFfmpegRecording(socket.id)
</file context>
Suggested change
logger.error(`User disconnected, ${socket.id} reason: ${reason} details: ${details}`)
logger.info(`User disconnected, ${socket.id} reason: ${reason} details: ${details}`)

handleDisconnect(socket)
await stopFfmpegRecording(socket.id)
});
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/pages/Broadcaster.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useRef, useState } from "react";
import { useRef, useState, useEffect } from "react";
import { connectSocket , disconnectSocket } from "../socket";
import {
CameraOff,
Camera,
Expand Down Expand Up @@ -51,13 +52,24 @@
setLogs((prev) => [...prev, { message, timestamp: new Date() }]);
};



useEffect(() => {
const socket = connectSocket();

Check warning on line 58 in frontend/src/pages/Broadcaster.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "socket".

See more on https://sonarcloud.io/project/issues?id=Harxhit_CrowdStream&issues=AaBB7q2cExXsUzpNDCD7&open=AaBB7q2cExXsUzpNDCD7&pullRequest=63

return () => {
disconnectSocket();
};
}, []);

async function startBroadcast() {
try {
log("Creating room...");

const room = await broadcaster.createRoom();

setRoomId(room.id);
(window as any).__csRoomId = room.id;

log("Fetching RTP capabilities...");

Expand All @@ -84,6 +96,7 @@
await broadcaster.startProducing(stream);

setIsLive(true);
(window as any).__csLiveAt = Date.now();

log("Broadcast started successfully.");
} catch (err: any) {
Expand Down
12 changes: 11 additions & 1 deletion frontend/src/pages/ViewerPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { X, Circle } from "lucide-react";
import api from "../api/axios";

import { connectSocket , disconnectSocket } from "../socket";

Check warning on line 6 in frontend/src/pages/ViewerPage.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'../socket' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=Harxhit_CrowdStream&issues=AaBB7qyjExXsUzpNDCD4&open=AaBB7qyjExXsUzpNDCD4&pullRequest=63

Check warning on line 6 in frontend/src/pages/ViewerPage.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import of 'disconnectSocket'.

See more on https://sonarcloud.io/project/issues?id=Harxhit_CrowdStream&issues=AaBB7qyjExXsUzpNDCD3&open=AaBB7qyjExXsUzpNDCD3&pullRequest=63
import Viewer from "../viewer";

import SystemLogs from "../components/broadcaster/SystemLogs";
Expand All @@ -10,7 +11,7 @@
import StreamInfo from "../components/viewer/StreamInfo";
import LiveChat from "../components/broadcaster/LiveChat";
import ReactionOverlay from "../components/reactions/ReactionOverlay";
import { getSocket,startHeartBeat } from "../socket";

Check warning on line 14 in frontend/src/pages/ViewerPage.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import of 'getSocket'.

See more on https://sonarcloud.io/project/issues?id=Harxhit_CrowdStream&issues=AaBB7qyjExXsUzpNDCD5&open=AaBB7qyjExXsUzpNDCD5&pullRequest=63

Check warning on line 14 in frontend/src/pages/ViewerPage.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'../socket' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=Harxhit_CrowdStream&issues=AaBB7qyjExXsUzpNDCD6&open=AaBB7qyjExXsUzpNDCD6&pullRequest=63

interface Log {
message: string;
Expand All @@ -20,7 +21,7 @@
const viewer = new Viewer();

export default function ViewerPage() {
const socket = getSocket()
const socket = connectSocket()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: connectSocket() has side effects (opening the socket connection, attaching event listeners, mutating window.__csSocket) but is now called during the render body. Render-phase side effects violate React's purity contract and can open a connection for a render that is later discarded or re-run (e.g. under StrictMode/Suspense). Move the connection into the component's useEffect and keep the render body pure.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/pages/ViewerPage.tsx, line 24:

<comment>connectSocket() has side effects (opening the socket connection, attaching event listeners, mutating window.__csSocket) but is now called during the render body. Render-phase side effects violate React's purity contract and can open a connection for a render that is later discarded or re-run (e.g. under StrictMode/Suspense). Move the connection into the component's useEffect and keep the render body pure.</comment>

<file context>
@@ -20,7 +21,7 @@ interface Log {
 
 export default function ViewerPage() {
-  const socket = getSocket()
+  const socket = connectSocket()
   const [searchParams] = useSearchParams();
 
</file context>

const [searchParams] = useSearchParams();

const videoRef = useRef<HTMLVideoElement>(null);
Expand Down Expand Up @@ -52,6 +53,14 @@
]);
};

// useEffect(() => {
// const socket = connectSocket();

// return () => {
// disconnectSocket();
// };
// }, []);

async function joinRoom(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();

Expand Down Expand Up @@ -86,6 +95,7 @@

await viewer.connectionState(roomId);

(window as any).__csJoinedAt = Date.now();
setConnected(true);

startHeartBeat();
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export default function Router() {
<Route path="/signin" element={<SignInPage />} />
<Route path="/signup" element={<SignUpPage />} />

<Route path="/broadcaster" element={<BroadcasterPage />} />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: These routes are now siblings of ProtectedRoute, so React Router renders them without authentication or socket initialization. Move all three routes back inside the protected route.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/router/index.tsx, line 19:

<comment>These routes are now siblings of `ProtectedRoute`, so React Router renders them without authentication or socket initialization. Move all three routes back inside the protected route.</comment>

<file context>
@@ -16,10 +16,10 @@ export default function Router() {
         <Route path="/signin" element={<SignInPage />} />
         <Route path="/signup" element={<SignUpPage />} />
 
+        <Route path="/broadcaster" element={<BroadcasterPage />} />
+        <Route path="/viewer" element={<ViewerPage />} />
+        <Route path="/dashboard" element={<DashboardPage />} />
</file context>

<Route path="/viewer" element={<ViewerPage />} />
<Route path="/dashboard" element={<DashboardPage />} />
<Route element={<ProtectedRoute />}>
<Route path="/dashboard" element={<DashboardPage />} />
<Route path="/broadcaster" element={<BroadcasterPage />} />
<Route path="/viewer" element={<ViewerPage />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export function connectSocket() {
}

socket = io(window.location.origin);
(window as any).__csSocket = socket;

socket.on("connect", () => {
console.log("Client connected", socket?.id);
Expand All @@ -22,6 +23,7 @@ export function connectSocket() {

socket.on("connect_error", (error) => {
console.log("Error", error.message);
console.log("SOCKET CONNECT ERROR DETAILS:", error);
});

socket.on("debug:instance", (data) => {
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ class Viewer{
mediaStream.addTrack(track)
})
viewerVideo.current.srcObject = mediaStream
viewerVideo.current.addEventListener('loadeddata', () => {
(window as any).__csFirstFrameAt = Date.now();
}, { once: true });
if(viewerVideo.current){
console.log('Viewer started playing')
}else{
Expand Down
101 changes: 101 additions & 0 deletions load-test/sfu-capacity-results.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
timestamp,viewers,joinP50,joinP99,firstFrameP50,firstFrameP99,failures

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: P50 equals P99 in every row for both join and first-frame latency, so these columns convey no actual latency distribution. Because the run used one viewer per batch, each 'percentile' is computed over a single sample and the P50/P99 labels are misleading to anyone reading the capacity results. Rerun with a meaningful batch size (or report per-viewer samples) so P50/P99 differ and the spread is visible.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/sfu-capacity-results.csv, line 1:

<comment>P50 equals P99 in every row for both join and first-frame latency, so these columns convey no actual latency distribution. Because the run used one viewer per batch, each 'percentile' is computed over a single sample and the P50/P99 labels are misleading to anyone reading the capacity results. Rerun with a meaningful batch size (or report per-viewer samples) so P50/P99 differ and the spread is visible.</comment>

<file context>
@@ -0,0 +1,101 @@
+timestamp,viewers,joinP50,joinP99,firstFrameP50,firstFrameP99,failures
+2026-08-19T03:33:16.173Z,1,341,341,362,362,0
+2026-08-19T03:33:20.123Z,2,346,346,388,388,0
</file context>

2026-08-19T03:33:16.173Z,1,341,341,362,362,0
2026-08-19T03:33:20.123Z,2,346,346,388,388,0
2026-08-19T03:33:23.971Z,3,336,336,381,381,0
2026-08-19T03:33:28.038Z,4,373,373,397,397,0
2026-08-19T03:33:31.922Z,5,353,353,385,385,0
2026-08-19T03:33:36.021Z,6,366,366,410,410,0
2026-08-19T03:33:40.121Z,7,349,349,394,394,0
2026-08-19T03:33:44.121Z,8,387,387,434,434,0
2026-08-19T03:33:48.489Z,9,378,378,395,395,0
2026-08-19T03:33:52.587Z,10,395,395,419,419,0
2026-08-19T03:33:56.771Z,11,396,396,436,436,0
2026-08-19T03:34:01.380Z,12,389,389,408,408,0
2026-08-19T03:34:05.571Z,13,407,407,435,435,0
2026-08-19T03:34:09.634Z,14,428,428,461,461,0
2026-08-19T03:34:13.986Z,15,423,423,457,457,0
2026-08-19T03:34:18.386Z,16,410,410,442,442,0
2026-08-19T03:34:22.536Z,17,417,417,468,468,0
2026-08-19T03:34:26.983Z,18,445,445,465,465,0
2026-08-19T03:34:31.244Z,19,461,461,487,487,0
2026-08-19T03:34:35.383Z,20,475,475,494,494,0
2026-08-19T03:34:39.585Z,21,486,486,516,516,0
2026-08-19T03:34:43.967Z,22,457,457,489,489,0
2026-08-19T03:34:48.652Z,23,468,468,533,533,0
2026-08-19T03:34:53.038Z,24,507,507,563,563,0
2026-08-19T03:34:57.740Z,25,500,500,554,554,0
2026-08-19T03:35:02.559Z,26,486,486,516,516,0
2026-08-19T03:35:07.261Z,27,541,541,574,574,0
2026-08-19T03:35:12.083Z,28,559,559,580,580,0
2026-08-19T03:35:16.852Z,29,500,500,549,549,0
2026-08-19T03:35:21.758Z,30,552,552,597,597,0
2026-08-19T03:35:26.751Z,31,534,534,599,599,0
2026-08-19T03:35:31.664Z,32,535,535,577,577,0
2026-08-19T03:35:36.757Z,33,597,597,652,652,0
2026-08-19T03:35:41.663Z,34,556,556,610,610,0
2026-08-19T03:35:46.585Z,35,581,581,607,607,0
2026-08-19T03:35:51.574Z,36,630,630,675,675,0
2026-08-19T03:35:56.683Z,37,666,666,688,688,0
2026-08-19T03:36:01.866Z,38,690,690,760,760,0
2026-08-19T03:36:06.964Z,39,679,679,739,739,0
2026-08-19T03:36:12.085Z,40,673,673,699,699,0
2026-08-19T03:36:17.367Z,41,695,695,771,771,0
2026-08-19T03:36:22.760Z,42,695,695,750,750,0
2026-08-19T03:36:28.098Z,43,727,727,749,749,0
2026-08-19T03:36:33.672Z,44,737,737,821,821,0
2026-08-19T03:36:39.166Z,45,745,745,822,822,0
2026-08-19T03:36:44.684Z,46,813,813,894,894,0
2026-08-19T03:36:50.184Z,47,818,818,882,882,0
2026-08-19T03:36:55.881Z,48,850,850,926,926,0
2026-08-19T03:37:01.900Z,49,911,911,952,952,0
2026-08-19T03:37:07.882Z,50,800,800,876,876,0
2026-08-19T03:37:13.888Z,51,951,951,1029,1029,0
2026-08-19T03:37:20.212Z,52,978,978,1023,1023,0
2026-08-19T03:37:26.388Z,53,987,987,1084,1084,0
2026-08-19T03:37:32.855Z,54,1262,1262,1301,1301,0
2026-08-19T03:37:39.202Z,55,1037,1037,1097,1097,0
2026-08-19T03:37:46.003Z,56,1077,1077,1109,1109,0
2026-08-19T03:37:52.557Z,57,1062,1062,1107,1107,0
2026-08-19T03:37:59.297Z,58,1209,1209,1301,1301,0
2026-08-19T03:38:06.254Z,59,1210,1210,1308,1308,0
2026-08-19T03:38:13.195Z,60,1386,1386,1489,1489,0
2026-08-19T03:38:20.308Z,61,1333,1333,1422,1422,0
2026-08-19T03:38:28.064Z,62,1319,1319,1412,1412,0
2026-08-19T03:38:35.652Z,63,1412,1412,1505,1505,0
2026-08-19T03:38:44.576Z,64,2868,2868,2958,2958,0
2026-08-19T03:38:52.598Z,65,1935,1935,2032,2032,0
2026-08-19T03:39:41.698Z,66,n/a,n/a,n/a,n/a,1
2026-08-19T03:39:50.785Z,67,1782,1782,1860,1860,1
2026-08-19T03:40:00.474Z,68,1721,1721,1872,1872,1
2026-08-19T03:40:10.696Z,69,1821,1821,1968,1968,1
2026-08-19T03:40:20.764Z,70,2004,2004,2103,2103,1
2026-08-19T03:40:31.929Z,71,2290,2290,2400,2400,1
2026-08-19T03:41:22.868Z,72,n/a,n/a,n/a,n/a,2
2026-08-19T03:41:34.524Z,73,2372,2372,2581,2581,2
2026-08-19T03:41:47.701Z,74,2935,2935,3021,3021,2
2026-08-19T03:42:39.292Z,75,n/a,n/a,n/a,n/a,3
2026-08-19T03:42:51.845Z,76,2236,2236,2347,2347,3
2026-08-19T03:43:04.971Z,77,2510,2510,2545,2545,3
2026-08-19T03:43:21.097Z,78,3961,3961,4067,4067,3
2026-08-19T03:44:15.879Z,79,n/a,n/a,n/a,n/a,4
2026-08-19T03:44:32.753Z,80,4622,4622,4902,4902,4
2026-08-19T03:44:43.493Z,81,1798,1798,1902,1902,4
2026-08-19T03:44:51.573Z,82,1697,1697,1756,1756,4
2026-08-19T03:45:07.981Z,83,3197,3197,3389,3389,4
2026-08-19T03:45:23.895Z,84,3248,3248,3566,3566,4
2026-08-19T03:45:30.251Z,85,1241,1241,1373,1373,4
2026-08-19T03:45:40.065Z,86,1708,1708,1813,1813,4
2026-08-19T03:45:52.749Z,87,4098,4098,4200,4200,4
2026-08-19T03:46:04.922Z,88,2382,2382,2444,2444,4
2026-08-19T03:46:56.247Z,89,n/a,n/a,n/a,n/a,5
2026-08-19T03:47:08.676Z,90,748,748,874,874,5
2026-08-19T03:47:16.974Z,91,2736,2736,2854,2854,5
2026-08-19T03:47:28.818Z,92,2608,2608,2792,2792,5
2026-08-19T03:48:22.194Z,93,n/a,n/a,n/a,n/a,6
2026-08-19T03:48:28.777Z,94,1179,1179,1258,1258,6
2026-08-19T03:49:15.344Z,95,n/a,n/a,n/a,n/a,7
2026-08-19T03:49:26.690Z,96,1321,1321,1393,1393,7
2026-08-19T03:49:37.293Z,97,2924,2924,3184,3184,7
2026-08-19T03:50:28.698Z,98,n/a,n/a,n/a,n/a,8
2026-08-19T03:50:42.666Z,99,1211,1211,1274,1274,8
2026-08-19T03:50:56.765Z,100,3810,3810,3888,3888,8
Loading