This commit is contained in:
parent
c4b5bace5d
commit
0f282fd003
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
@ -44,6 +44,7 @@
|
|||||||
"react-countup": "^6.5.3",
|
"react-countup": "^6.5.3",
|
||||||
"react-dom": "^19.0.0-rc-1460d67c-20241003",
|
"react-dom": "^19.0.0-rc-1460d67c-20241003",
|
||||||
"react-hook-form": "^7.53.0",
|
"react-hook-form": "^7.53.0",
|
||||||
|
"react-use-websocket": "^4.9.0",
|
||||||
"tailwind-merge": "^2.5.2",
|
"tailwind-merge": "^2.5.2",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
|
@ -5,18 +5,18 @@ import ScoreSaberPlayerScoreToken from "@ssr/common/types/token/scoresaber/score
|
|||||||
import Score from "@/components/score/score";
|
import Score from "@/components/score/score";
|
||||||
import { parseDate } from "@ssr/common/utils/time-utils";
|
import { parseDate } from "@ssr/common/utils/time-utils";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useWebSocket } from "@/hooks/use-websocket";
|
import useWebSocket, { ReadyState } from "react-use-websocket";
|
||||||
import { ScoreSaberWebsocketMessageToken } from "@ssr/common/types/token/scoresaber/websocket/scoresaber-websocket-message";
|
import { ScoreSaberWebsocketMessageToken } from "@ssr/common/types/token/scoresaber/websocket/scoresaber-websocket-message";
|
||||||
|
|
||||||
export default function ScoreFeed() {
|
export default function ScoreFeed() {
|
||||||
const { connected, message } = useWebSocket<ScoreSaberWebsocketMessageToken>("wss://scoresaber.com/ws");
|
const { readyState, lastJsonMessage } = useWebSocket<ScoreSaberWebsocketMessageToken>("wss://scoresaber.com/ws");
|
||||||
const [scores, setScores] = useState<ScoreSaberPlayerScoreToken[]>([]);
|
const [scores, setScores] = useState<ScoreSaberPlayerScoreToken[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!message) {
|
if (!lastJsonMessage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { commandName, commandData } = message;
|
const { commandName, commandData } = lastJsonMessage;
|
||||||
if (commandName !== "score") {
|
if (commandName !== "score") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -30,9 +30,9 @@ export default function ScoreFeed() {
|
|||||||
// Newest to oldest
|
// Newest to oldest
|
||||||
return newScores.sort((a, b) => parseDate(b.score.timeSet).getTime() - parseDate(a.score.timeSet).getTime());
|
return newScores.sort((a, b) => parseDate(b.score.timeSet).getTime() - parseDate(a.score.timeSet).getTime());
|
||||||
});
|
});
|
||||||
}, [message]);
|
}, [lastJsonMessage]);
|
||||||
|
|
||||||
if (!connected) {
|
if (readyState == ReadyState.CONNECTING) {
|
||||||
return <p>Not Connected to the ScoreSaber Websocket :(</p>;
|
return <p>Not Connected to the ScoreSaber Websocket :(</p>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generic WebSocket hook for connecting and handling WebSocket messages of type T.
|
|
||||||
*
|
|
||||||
* @param url - The WebSocket server URL.
|
|
||||||
* @param reconnectDelay - Optional delay (in milliseconds) before attempting to reconnect (default is 5000ms).
|
|
||||||
*/
|
|
||||||
export const useWebSocket = <T>(url: string, reconnectDelay: number = 5000) => {
|
|
||||||
const [connected, setConnected] = useState(false);
|
|
||||||
const [message, setMessage] = useState<T | null>(null); // Store the incoming message of type T
|
|
||||||
const socketRef = useRef<WebSocket | null>(null);
|
|
||||||
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectWebSocket = () => {
|
|
||||||
socketRef.current = new WebSocket(url);
|
|
||||||
|
|
||||||
socketRef.current.onopen = () => {
|
|
||||||
setConnected(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
socketRef.current.onmessage = event => {
|
|
||||||
try {
|
|
||||||
// Handle incoming messages and store them in state as type T
|
|
||||||
const messageData: T = JSON.parse(event.data);
|
|
||||||
setMessage(messageData);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error parsing WebSocket message:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
socketRef.current.onclose = () => {
|
|
||||||
setConnected(false);
|
|
||||||
attemptReconnect();
|
|
||||||
};
|
|
||||||
|
|
||||||
socketRef.current.onerror = () => {
|
|
||||||
socketRef.current?.close(); // Close the socket on error
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const attemptReconnect = () => {
|
|
||||||
// Clear any existing timeouts to avoid multiple reconnection attempts
|
|
||||||
if (reconnectTimeoutRef.current) {
|
|
||||||
clearTimeout(reconnectTimeoutRef.current);
|
|
||||||
}
|
|
||||||
// Try reconnecting after the specified delay
|
|
||||||
reconnectTimeoutRef.current = setTimeout(() => {
|
|
||||||
connectWebSocket();
|
|
||||||
}, reconnectDelay);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize WebSocket connection
|
|
||||||
connectWebSocket();
|
|
||||||
|
|
||||||
// Cleanup function when component unmounts
|
|
||||||
return () => {
|
|
||||||
if (socketRef.current) {
|
|
||||||
socketRef.current.close();
|
|
||||||
socketRef.current = null;
|
|
||||||
}
|
|
||||||
if (reconnectTimeoutRef.current) {
|
|
||||||
clearTimeout(reconnectTimeoutRef.current);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [mounted, url, reconnectDelay]);
|
|
||||||
|
|
||||||
return { connected, message };
|
|
||||||
};
|
|
Reference in New Issue
Block a user