* [#451] added websocket connexion * [#451] added tests * [#451] add missing cleanup for web socket causing memory leaks
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useAppSelector } from "../app/hooks";
|
||||
import { useSelectedCalendars } from "../utils/storage/useSelectedCalendars";
|
||||
import {
|
||||
createWebSocketConnection,
|
||||
WebSocketWithCleanup,
|
||||
} from "./createWebSocketConnection";
|
||||
import { registerToCalendars } from "./ws/registerToCalendars";
|
||||
import { unregisterToCalendars } from "./ws/unregisterToCalendars";
|
||||
|
||||
export function WebSocketGate() {
|
||||
const socketRef = useRef<WebSocketWithCleanup | null>(null);
|
||||
const previousCalendarListRef = useRef<string[]>([]);
|
||||
|
||||
const isAuthenticated = useAppSelector((state) =>
|
||||
Boolean(state.user.userData && state.user.tokens)
|
||||
);
|
||||
const [isSocketOpen, setIsSocketOpen] = useState(false);
|
||||
|
||||
const calendarList = useSelectedCalendars();
|
||||
|
||||
// Manage WebSocket connection
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated) {
|
||||
if (socketRef.current) {
|
||||
socketRef.current.cleanup();
|
||||
socketRef.current.close();
|
||||
socketRef.current = null;
|
||||
setIsSocketOpen(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const connect = async () => {
|
||||
try {
|
||||
const socket = await createWebSocketConnection();
|
||||
socketRef.current = socket;
|
||||
socket.addEventListener("close", () => {
|
||||
setIsSocketOpen(false);
|
||||
socketRef.current = null;
|
||||
});
|
||||
// Check if socket closed during setup
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
setIsSocketOpen(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to create WebSocket connection:", error);
|
||||
}
|
||||
};
|
||||
|
||||
connect();
|
||||
|
||||
return () => {
|
||||
if (socketRef.current) {
|
||||
socketRef.current.cleanup();
|
||||
socketRef.current.close();
|
||||
socketRef.current = null;
|
||||
setIsSocketOpen(false);
|
||||
}
|
||||
};
|
||||
}, [isAuthenticated]);
|
||||
|
||||
// Register using a diff with previous calendars
|
||||
useEffect(() => {
|
||||
if (
|
||||
!isSocketOpen ||
|
||||
!socketRef.current ||
|
||||
socketRef.current.readyState !== WebSocket.OPEN
|
||||
)
|
||||
return;
|
||||
|
||||
const currentPaths = calendarList.map((cal) => `/calendars/${cal}`);
|
||||
const previousPaths = previousCalendarListRef.current.map(
|
||||
(cal) => `/calendars/${cal}`
|
||||
);
|
||||
|
||||
// calendars to register
|
||||
const toRegister = currentPaths.filter(
|
||||
(path) => !previousPaths.includes(path)
|
||||
);
|
||||
|
||||
// calendars to unregister
|
||||
const toUnregister = previousPaths.filter(
|
||||
(path) => !currentPaths.includes(path)
|
||||
);
|
||||
|
||||
try {
|
||||
if (toRegister.length > 0) {
|
||||
registerToCalendars(socketRef.current, toRegister);
|
||||
}
|
||||
|
||||
if (toUnregister.length > 0) {
|
||||
unregisterToCalendars(socketRef.current, toUnregister);
|
||||
}
|
||||
|
||||
// Only update the ref if operations succeeded
|
||||
previousCalendarListRef.current = calendarList;
|
||||
} catch (error) {
|
||||
console.error("Failed to update calendar registrations:", error);
|
||||
}
|
||||
}, [isSocketOpen, calendarList]);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user