From f90c255656da7de8c1f684bcda2521ad99a293dd Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 10 Oct 2025 22:10:33 +0300 Subject: [PATCH] fix: prevent unnecessary RPC calls for pending sessions and increase rate limit Changes: - Add permission checks before making getVideoState, getKeyboardLedState, and getKeyDownState RPC calls to prevent rejected requests for sessions without VIDEO_VIEW permission - Fix infinite loop issue by excluding hasPermission from useEffect dependency arrays (functions recreated on render cause infinite loops) - Increase RPC rate limit from 100 to 500 per second to support 10+ concurrent sessions with broadcasts and state updates This eliminates console spam from permission denied errors and log spam from continuous RPC calls, while improving multi-session performance. --- ui/src/routes/devices.$id.tsx | 6 ++++++ webrtc.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ui/src/routes/devices.$id.tsx b/ui/src/routes/devices.$id.tsx index 4ab6e80f..cf82ad0a 100644 --- a/ui/src/routes/devices.$id.tsx +++ b/ui/src/routes/devices.$id.tsx @@ -807,11 +807,13 @@ export default function KvmIdRoute() { useEffect(() => { if (rpcDataChannel?.readyState !== "open") return; + if (!hasPermission(Permission.VIDEO_VIEW)) return; send("getVideoState", {}, (resp: JsonRpcResponse) => { if ("error" in resp) return; const hdmiState = resp.result as Parameters[0]; setHdmiState(hdmiState); }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [rpcDataChannel?.readyState, send, setHdmiState]); const [needLedState, setNeedLedState] = useState(true); @@ -820,6 +822,7 @@ export default function KvmIdRoute() { useEffect(() => { if (rpcDataChannel?.readyState !== "open") return; if (!needLedState) return; + if (!hasPermission(Permission.VIDEO_VIEW)) return; send("getKeyboardLedState", {}, (resp: JsonRpcResponse) => { if ("error" in resp) { @@ -831,6 +834,7 @@ export default function KvmIdRoute() { } setNeedLedState(false); }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [rpcDataChannel?.readyState, send, setKeyboardLedState, keyboardLedState, needLedState]); const [needKeyDownState, setNeedKeyDownState] = useState(true); @@ -839,6 +843,7 @@ export default function KvmIdRoute() { useEffect(() => { if (rpcDataChannel?.readyState !== "open") return; if (!needKeyDownState) return; + if (!hasPermission(Permission.VIDEO_VIEW)) return; send("getKeyDownState", {}, (resp: JsonRpcResponse) => { if ("error" in resp) { @@ -856,6 +861,7 @@ export default function KvmIdRoute() { } setNeedKeyDownState(false); }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [keysDownState, needKeyDownState, rpcDataChannel?.readyState, send, setKeysDownState, setHidRpcDisabled]); // When the update is successful, we need to refresh the client javascript and show a success modal diff --git a/webrtc.go b/webrtc.go index 865e5cf0..e6eec581 100644 --- a/webrtc.go +++ b/webrtc.go @@ -88,7 +88,7 @@ func getActiveSessions() int { // CheckRPCRateLimit checks if the session has exceeded RPC rate limits (DoS protection) func (s *Session) CheckRPCRateLimit() bool { const ( - maxRPCPerSecond = 100 // Increased from 20 to accommodate multi-session polling and reconnections + maxRPCPerSecond = 500 // Increased to support 10+ concurrent sessions with broadcasts and state updates rateLimitWindow = time.Second )