feat: init

This commit is contained in:
hamster1963
2024-11-23 16:34:34 +08:00
parent e5682aacbd
commit 65902d5385
11 changed files with 122 additions and 98 deletions

View File

@@ -1,89 +1,89 @@
import { useState, useEffect, useRef, useCallback } from 'react'
import { useState, useEffect, useRef, useCallback } from "react";
export interface WebSocketHook {
socket: WebSocket | null
connected: boolean
onlineCount: number
message: string | null
sendMessage: (msg: string) => void
socket: WebSocket | null;
connected: boolean;
onlineCount: number;
message: string | null;
sendMessage: (msg: string) => void;
}
export default function useWebSocket(url: string): WebSocketHook {
const [socket, setSocket] = useState<WebSocket | null>(null)
const [message, setMessage] = useState<string | null>(null)
const [connected, setConnected] = useState<boolean>(false)
const [onlineCount, setOnlineCount] = useState<number>(0)
const socketRef = useRef<WebSocket | null>(null)
const reconnectAttempts = useRef<number>(0)
const reconnectTimeout = useRef<NodeJS.Timeout | null>(null)
const isUnmounted = useRef<boolean>(false)
const [socket, setSocket] = useState<WebSocket | null>(null);
const [message, setMessage] = useState<string | null>(null);
const [connected, setConnected] = useState<boolean>(false);
const [onlineCount, setOnlineCount] = useState<number>(0);
const socketRef = useRef<WebSocket | null>(null);
const reconnectAttempts = useRef<number>(0);
const reconnectTimeout = useRef<NodeJS.Timeout | null>(null);
const isUnmounted = useRef<boolean>(false);
const connect = useCallback(() => {
if (isUnmounted.current) return
if (isUnmounted.current) return;
const ws = new WebSocket(url)
setSocket(ws)
socketRef.current = ws
const ws = new WebSocket(url);
setSocket(ws);
socketRef.current = ws;
ws.onopen = () => {
setConnected(true)
reconnectAttempts.current = 0
}
setConnected(true);
reconnectAttempts.current = 0;
};
ws.onmessage = (event: MessageEvent) => {
setMessage(event.data)
const msgJson = JSON.parse(event.data)
if (msgJson.type === 'live') {
setOnlineCount(msgJson.data.count)
setMessage(event.data);
const msgJson = JSON.parse(event.data);
if (msgJson.type === "live") {
setOnlineCount(msgJson.data.count);
}
}
};
ws.onerror = (error) => {
console.error('WebSocket Error:', error)
}
console.error("WebSocket Error:", error);
};
ws.onclose = () => {
setConnected(false)
setConnected(false);
if (!isUnmounted.current) {
// Attempt to reconnect
if (reconnectAttempts.current < 5) {
const timeout = Math.pow(2, reconnectAttempts.current) * 1000 // Exponential backoff
reconnectAttempts.current += 1
const timeout = Math.pow(2, reconnectAttempts.current) * 1000; // Exponential backoff
reconnectAttempts.current += 1;
reconnectTimeout.current = setTimeout(() => {
connect()
}, timeout)
connect();
}, timeout);
} else {
console.warn('Max reconnect attempts reached.')
console.warn("Max reconnect attempts reached.");
}
}
}
}, [url])
};
}, [url]);
useEffect(() => {
connect()
connect();
return () => {
isUnmounted.current = true
isUnmounted.current = true;
if (socketRef.current) {
socketRef.current.close()
socketRef.current.close();
}
if (reconnectTimeout.current) {
clearTimeout(reconnectTimeout.current)
clearTimeout(reconnectTimeout.current);
}
}
}, [connect])
};
}, [connect]);
// Function to send messages
const sendMessage = useCallback((msg: string) => {
if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) {
socketRef.current.send(msg)
socketRef.current.send(msg);
} else {
console.warn(
'WebSocket is not open. Ready state:',
socketRef.current?.readyState
)
"WebSocket is not open. Ready state:",
socketRef.current?.readyState,
);
}
}, [])
}, []);
return { socket, message, sendMessage, connected, onlineCount }
return { socket, message, sendMessage, connected, onlineCount };
}

View File

@@ -1,26 +1,25 @@
import { createContext, useContext, ReactNode } from 'react'
import useWebSocket, { WebSocketHook } from './useWebsocket'
import { createContext, useContext, ReactNode } from "react";
import useWebSocket, { WebSocketHook } from "./useWebsocket";
interface WebSocketProviderProps {
children: ReactNode
children: ReactNode;
}
const WebSocketContext = createContext<WebSocketHook | undefined>(undefined)
const WebSocketContext = createContext<WebSocketHook | undefined>(undefined);
export const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
const ws = useWebSocket('wss://dev-next.buycoffee.top:4433/api/v1/ws/server')
const ws = useWebSocket("wss://dev-next.buycoffee.top:4433/api/v1/ws/server");
return (
<WebSocketContext.Provider value={ws}>{children}</WebSocketContext.Provider>
)
}
);
};
export const useWebSocketContext = (): WebSocketHook => {
const context = useContext(WebSocketContext)
const context = useContext(WebSocketContext);
if (!context) {
throw new Error(
'useWebSocketContext must be used within a WebSocketProvider'
)
"useWebSocketContext must be used within a WebSocketProvider",
);
}
return context
}
return context;
};