mirror of https://github.com/jetkvm/kvm.git
fix: resolve activity tracking and UI race conditions
- Remove LastActive reset on emergency promotion to preserve actual activity state - Fix UI rejection count race by tracking whether rejection was already counted - Optimize browser detection to avoid redundant string searches
This commit is contained in:
parent
587f8b5e4c
commit
79b5ec3e29
|
|
@ -1226,10 +1226,8 @@ func (sm *SessionManager) transferPrimaryRole(fromSessionID, toSessionID, transf
|
|||
// Promote target session
|
||||
toSession.Mode = SessionModePrimary
|
||||
toSession.hidRPCAvailable = false
|
||||
// Reset LastActive for all emergency promotions to prevent immediate re-timeout
|
||||
if strings.HasPrefix(transferType, "emergency_") {
|
||||
toSession.LastActive = time.Now()
|
||||
}
|
||||
// For manual transfers, preserve the session's actual LastActive timestamp
|
||||
// Emergency promotions inherit the observer's activity state - no free time
|
||||
sm.primarySessionID = toSessionID
|
||||
|
||||
// ALWAYS set lastPrimaryID to the new primary to support WebRTC reconnections
|
||||
|
|
@ -1476,16 +1474,19 @@ func extractBrowserFromUserAgent(userAgent string) *string {
|
|||
ua := strings.ToLower(userAgent)
|
||||
|
||||
// Check for common browsers (order matters - Chrome contains Safari, etc.)
|
||||
// Optimize Safari check by caching Chrome detection
|
||||
hasChrome := strings.Contains(ua, "chrome")
|
||||
|
||||
if strings.Contains(ua, "edg/") || strings.Contains(ua, "edge") {
|
||||
return &BrowserEdge
|
||||
}
|
||||
if strings.Contains(ua, "firefox") {
|
||||
return &BrowserFirefox
|
||||
}
|
||||
if strings.Contains(ua, "chrome") {
|
||||
if hasChrome {
|
||||
return &BrowserChrome
|
||||
}
|
||||
if strings.Contains(ua, "safari") && !strings.Contains(ua, "chrome") {
|
||||
if strings.Contains(ua, "safari") {
|
||||
return &BrowserSafari
|
||||
}
|
||||
if strings.Contains(ua, "opera") || strings.Contains(ua, "opr/") {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useEffect, useState, useCallback, useRef } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { XCircleIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
|
|
@ -30,6 +30,7 @@ export default function AccessDeniedOverlay({
|
|||
const { maxRejectionAttempts } = useSettingsStore();
|
||||
const [countdown, setCountdown] = useState(10);
|
||||
const [isRetrying, setIsRetrying] = useState(false);
|
||||
const hasCountedRef = useRef(false);
|
||||
|
||||
const handleLogout = useCallback(async () => {
|
||||
try {
|
||||
|
|
@ -50,7 +51,15 @@ export default function AccessDeniedOverlay({
|
|||
}, [navigate, setUser, clearSession, clearNickname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!show) return;
|
||||
if (!show) {
|
||||
hasCountedRef.current = false;
|
||||
setCountdown(10);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only count rejection once per showing
|
||||
if (hasCountedRef.current) return;
|
||||
hasCountedRef.current = true;
|
||||
|
||||
const newCount = incrementRejectionCount();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue