-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: enable client-side notifications for all runs #736
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,17 +1,21 @@ | ||||||||||||||||||||
import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; | ||||||||||||||||||||
import React, { createContext, useCallback, useContext, useState, useRef, useEffect } from 'react'; | ||||||||||||||||||||
import { io, Socket } from 'socket.io-client'; | ||||||||||||||||||||
import { apiUrl } from "../apiConfig"; | ||||||||||||||||||||
|
||||||||||||||||||||
const SERVER_ENDPOINT = apiUrl; | ||||||||||||||||||||
|
||||||||||||||||||||
interface SocketState { | ||||||||||||||||||||
socket: Socket | null; | ||||||||||||||||||||
queueSocket: Socket | null; | ||||||||||||||||||||
id: string; | ||||||||||||||||||||
setId: (id: string) => void; | ||||||||||||||||||||
connectToQueueSocket: (userId: string, onRunCompleted?: (data: any) => void) => void; | ||||||||||||||||||||
disconnectQueueSocket: () => void; | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
class SocketStore implements Partial<SocketState> { | ||||||||||||||||||||
socket = null; | ||||||||||||||||||||
socket: Socket | null = null; | ||||||||||||||||||||
queueSocket: Socket | null = null; | ||||||||||||||||||||
id = ''; | ||||||||||||||||||||
}; | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -22,7 +26,9 @@ export const useSocketStore = () => useContext(socketStoreContext); | |||||||||||||||||||
|
||||||||||||||||||||
export const SocketProvider = ({ children }: { children: JSX.Element }) => { | ||||||||||||||||||||
const [socket, setSocket] = useState<Socket | null>(socketStore.socket); | ||||||||||||||||||||
const [queueSocket, setQueueSocket] = useState<Socket | null>(socketStore.queueSocket); | ||||||||||||||||||||
const [id, setActiveId] = useState<string>(socketStore.id); | ||||||||||||||||||||
const runCompletedCallbackRef = useRef<((data: any) => void) | null>(null); | ||||||||||||||||||||
|
||||||||||||||||||||
const setId = useCallback((id: string) => { | ||||||||||||||||||||
// the socket client connection is recomputed whenever id changes -> the new browser has been initialized | ||||||||||||||||||||
|
@@ -39,12 +45,70 @@ export const SocketProvider = ({ children }: { children: JSX.Element }) => { | |||||||||||||||||||
setActiveId(id); | ||||||||||||||||||||
}, [setSocket]); | ||||||||||||||||||||
|
||||||||||||||||||||
const connectToQueueSocket = useCallback((userId: string, onRunCompleted?: (data: any) => void) => { | ||||||||||||||||||||
runCompletedCallbackRef.current = onRunCompleted || null; | ||||||||||||||||||||
|
||||||||||||||||||||
const newQueueSocket = io(`${SERVER_ENDPOINT}/queued-run`, { | ||||||||||||||||||||
transports: ["websocket"], | ||||||||||||||||||||
rejectUnauthorized: false, | ||||||||||||||||||||
query: { userId } | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
Comment on lines
+51
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove ineffective/insecure option and prefer authenticated handshake over query
Apply this minimal cleanup: - const newQueueSocket = io(`${SERVER_ENDPOINT}/queued-run`, {
- transports: ["websocket"],
- rejectUnauthorized: false,
- query: { userId }
- });
+ const newQueueSocket = io(`${SERVER_ENDPOINT}/queued-run`, {
+ transports: ["websocket"],
+ query: { userId }
+ }); Longer-term: move to 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||
newQueueSocket.on('connect', () => { | ||||||||||||||||||||
console.log('Queue socket connected for user:', userId); | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
newQueueSocket.on('connect_error', (error) => { | ||||||||||||||||||||
console.log('Queue socket connection error:', error); | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
newQueueSocket.on('run-completed', (completionData) => { | ||||||||||||||||||||
console.log('Run completed event received:', completionData); | ||||||||||||||||||||
if (runCompletedCallbackRef.current) { | ||||||||||||||||||||
runCompletedCallbackRef.current(completionData); | ||||||||||||||||||||
} | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
setQueueSocket(currentSocket => { | ||||||||||||||||||||
if (currentSocket) { | ||||||||||||||||||||
currentSocket.disconnect(); | ||||||||||||||||||||
} | ||||||||||||||||||||
return newQueueSocket; | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
socketStore.queueSocket = newQueueSocket; | ||||||||||||||||||||
}, []); | ||||||||||||||||||||
|
||||||||||||||||||||
const disconnectQueueSocket = useCallback(() => { | ||||||||||||||||||||
setQueueSocket(currentSocket => { | ||||||||||||||||||||
if (currentSocket) { | ||||||||||||||||||||
currentSocket.disconnect(); | ||||||||||||||||||||
} | ||||||||||||||||||||
return null; | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
socketStore.queueSocket = null; | ||||||||||||||||||||
runCompletedCallbackRef.current = null; | ||||||||||||||||||||
}, []); | ||||||||||||||||||||
|
||||||||||||||||||||
// Cleanup on unmount | ||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||
return () => { | ||||||||||||||||||||
if (queueSocket) { | ||||||||||||||||||||
queueSocket.disconnect(); | ||||||||||||||||||||
} | ||||||||||||||||||||
}; | ||||||||||||||||||||
}, [queueSocket]); | ||||||||||||||||||||
|
||||||||||||||||||||
return ( | ||||||||||||||||||||
<socketStoreContext.Provider | ||||||||||||||||||||
value={{ | ||||||||||||||||||||
socket, | ||||||||||||||||||||
queueSocket, | ||||||||||||||||||||
id, | ||||||||||||||||||||
setId, | ||||||||||||||||||||
connectToQueueSocket, | ||||||||||||||||||||
disconnectQueueSocket, | ||||||||||||||||||||
}} | ||||||||||||||||||||
> | ||||||||||||||||||||
{children} | ||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -15,6 +15,7 @@ import { ScheduleSettings } from "../components/robot/ScheduleSettings"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { apiUrl } from "../apiConfig"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useNavigate } from 'react-router-dom'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { AuthContext } from '../context/auth'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useSocketStore } from '../context/socket'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
interface MainPageProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
handleEditRecording: (id: string, fileName: string) => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -54,6 +55,8 @@ export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { state } = useContext(AuthContext); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { user } = state; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { connectToQueueSocket, disconnectQueueSocket } = useSocketStore(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const abortRunHandler = (runId: string, robotName: string, browserId: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notify('info', t('main_page.notifications.abort_initiated', { name: robotName })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -138,50 +141,7 @@ export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
navigate(`/runs/${robotMetaId}/run/${runId}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (queued) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log('Creating queue socket for queued run:', runId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setQueuedRuns(prev => new Set([...prev, runId])); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const queueSocket = io(`${apiUrl}/queued-run`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
transports: ["websocket"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
rejectUnauthorized: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query: { userId: user?.id } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
queueSocket.on('connect', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log('Queue socket connected for user:', user?.id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
queueSocket.on('connect_error', (error) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.log('Queue socket connection error:', error); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
queueSocket.on('run-completed', (completionData) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (completionData.runId === runId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setRunningRecordingName(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setCurrentInterpretationLog(''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setRerenderRuns(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setQueuedRuns(prev => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const newSet = new Set(prev); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
newSet.delete(runId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return newSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const robotName = completionData.robotName || runningRecordingName; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (completionData.status === 'success') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notify('success', t('main_page.notifications.interpretation_success', { name: robotName })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notify('error', t('main_page.notifications.interpretation_failed', { name: robotName })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
queueSocket.disconnect(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setSockets(sockets => [...sockets, queueSocket]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notify('info', `Run queued: ${runningRecordingName}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const socket = io(`${apiUrl}/${browserId}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -245,6 +205,36 @@ export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return message === 'success'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (user?.id) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const handleRunCompleted = (completionData: any) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setRerenderRuns(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (queuedRuns.has(completionData.runId)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setQueuedRuns(prev => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const newSet = new Set(prev); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
newSet.delete(completionData.runId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return newSet; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const robotName = completionData.robotName || 'Unknown Robot'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (completionData.status === 'success') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notify('success', t('main_page.notifications.interpretation_success', { name: robotName })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notify('error', t('main_page.notifications.interpretation_failed', { name: robotName })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
connectToQueueSocket(user.id, handleRunCompleted); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
disconnectQueueSocket(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, [user?.id, connectToQueueSocket, disconnectQueueSocket, t, setRerenderRuns, queuedRuns, setQueuedRuns]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+208
to
+237
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Prevent unnecessary socket reconnections caused by Including Apply this diff: useEffect(() => {
if (user?.id) {
const handleRunCompleted = (completionData: any) => {
setRerenderRuns(true);
-
- if (queuedRuns.has(completionData.runId)) {
- setQueuedRuns(prev => {
- const newSet = new Set(prev);
- newSet.delete(completionData.runId);
- return newSet;
- });
- }
+ setQueuedRuns(prev => {
+ const newSet = new Set(prev);
+ newSet.delete(completionData.runId); // idempotent
+ return newSet;
+ });
const robotName = completionData.robotName || 'Unknown Robot';
if (completionData.status === 'success') {
notify('success', t('main_page.notifications.interpretation_success', { name: robotName }));
} else {
notify('error', t('main_page.notifications.interpretation_failed', { name: robotName }));
}
};
- connectToQueueSocket(user.id, handleRunCompleted);
+ connectToQueueSocket(String(user.id), handleRunCompleted);
return () => {
disconnectQueueSocket();
};
}
- }, [user?.id, connectToQueueSocket, disconnectQueueSocket, t, setRerenderRuns, queuedRuns, setQueuedRuns]);
+ }, [user?.id, connectToQueueSocket, disconnectQueueSocket, t, setRerenderRuns, setQueuedRuns]); Notes:
📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const DisplayContent = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
switch (content) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
case 'robots': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Do not trust client-supplied userId; validate and type-guard handshake input before joining rooms
Currently, a client can arbitrarily provide any userId via query and subscribe to another user's room, which is a PII leakage risk. Also,
socket.handshake.query.userId as string
may be an array at runtime. Add runtime guards and avoid trusting client-provided identifiers without authentication.Refactor to bind the namespace to a variable, export it for emitters, and add strict parsing of userId:
Follow-up: Strongly consider authenticating the socket (e.g., via a signed token in
handshake.auth
, or reading the server session and derivinguserId
on the server) instead of accepting it from the client. This prevents room hijacking. If you want, I can provide a middleware example for JWT/session validation.📝 Committable suggestion