| | import { useEffect, useRef, useCallback } from 'react'; |
| | import { Project } from '@/lib/api'; |
| |
|
| | export function useVncPreloader(project: Project | null) { |
| | const preloadedIframeRef = useRef<HTMLIFrameElement | null>(null); |
| | const isPreloadedRef = useRef(false); |
| | const retryTimeoutRef = useRef<NodeJS.Timeout | null>(null); |
| | const maxRetriesRef = useRef(0); |
| | const isRetryingRef = useRef(false); |
| |
|
| | const startPreloading = useCallback((vncUrl: string) => { |
| | |
| | if (isRetryingRef.current || isPreloadedRef.current) { |
| | return; |
| | } |
| |
|
| | isRetryingRef.current = true; |
| | console.log(`[VNC PRELOADER] Attempt ${maxRetriesRef.current + 1}/10 - Starting VNC preload:`, vncUrl); |
| |
|
| | |
| | const iframe = document.createElement('iframe'); |
| | iframe.src = vncUrl; |
| | iframe.style.position = 'absolute'; |
| | iframe.style.left = '-9999px'; |
| | iframe.style.top = '-9999px'; |
| | iframe.style.width = '1024px'; |
| | iframe.style.height = '768px'; |
| | iframe.style.border = '0'; |
| | iframe.title = 'VNC Preloader'; |
| |
|
| | |
| | const loadTimeout = setTimeout(() => { |
| | console.log('[VNC PRELOADER] Load timeout - VNC service likely not ready'); |
| | |
| | |
| | if (iframe.parentNode) { |
| | iframe.parentNode.removeChild(iframe); |
| | } |
| | |
| | |
| | if (maxRetriesRef.current < 10) { |
| | maxRetriesRef.current++; |
| | isRetryingRef.current = false; |
| | |
| | |
| | const delay = Math.min(2000 * Math.pow(1.5, maxRetriesRef.current - 1), 15000); |
| | console.log(`[VNC PRELOADER] Retrying in ${delay}ms (attempt ${maxRetriesRef.current + 1}/10)`); |
| | |
| | retryTimeoutRef.current = setTimeout(() => { |
| | startPreloading(vncUrl); |
| | }, delay); |
| | } else { |
| | console.log('[VNC PRELOADER] Max retries reached, giving up on preloading'); |
| | isRetryingRef.current = false; |
| | } |
| | }, 5000); |
| |
|
| | |
| | iframe.onload = () => { |
| | clearTimeout(loadTimeout); |
| | console.log('[VNC PRELOADER] ✅ VNC iframe preloaded successfully!'); |
| | isPreloadedRef.current = true; |
| | isRetryingRef.current = false; |
| | preloadedIframeRef.current = iframe; |
| | }; |
| |
|
| | |
| | iframe.onerror = () => { |
| | clearTimeout(loadTimeout); |
| | console.log('[VNC PRELOADER] VNC iframe failed to load (onerror)'); |
| | |
| | |
| | if (iframe.parentNode) { |
| | iframe.parentNode.removeChild(iframe); |
| | } |
| | |
| | |
| | if (maxRetriesRef.current < 10) { |
| | maxRetriesRef.current++; |
| | isRetryingRef.current = false; |
| | |
| | const delay = Math.min(2000 * Math.pow(1.5, maxRetriesRef.current - 1), 15000); |
| | console.log(`[VNC PRELOADER] Retrying in ${delay}ms (attempt ${maxRetriesRef.current + 1}/10)`); |
| | |
| | retryTimeoutRef.current = setTimeout(() => { |
| | startPreloading(vncUrl); |
| | }, delay); |
| | } else { |
| | console.log('[VNC PRELOADER] Max retries reached, giving up on preloading'); |
| | isRetryingRef.current = false; |
| | } |
| | }; |
| |
|
| | |
| | document.body.appendChild(iframe); |
| | console.log('[VNC PRELOADER] VNC iframe added to DOM, waiting for load...'); |
| | }, []); |
| |
|
| | useEffect(() => { |
| | |
| | if (!project?.sandbox?.vnc_preview || !project?.sandbox?.pass || isPreloadedRef.current || isRetryingRef.current) { |
| | return; |
| | } |
| |
|
| | const vncUrl = `${project.sandbox.vnc_preview}/vnc_lite.html?password=${project.sandbox.pass}&autoconnect=true&scale=local&width=1024&height=768`; |
| |
|
| | |
| | maxRetriesRef.current = 0; |
| | isRetryingRef.current = false; |
| |
|
| | |
| | const initialDelay = setTimeout(() => { |
| | startPreloading(vncUrl); |
| | }, 1000); |
| |
|
| | |
| | return () => { |
| | clearTimeout(initialDelay); |
| | |
| | if (retryTimeoutRef.current) { |
| | clearTimeout(retryTimeoutRef.current); |
| | retryTimeoutRef.current = null; |
| | } |
| | |
| | if (preloadedIframeRef.current && preloadedIframeRef.current.parentNode) { |
| | preloadedIframeRef.current.parentNode.removeChild(preloadedIframeRef.current); |
| | preloadedIframeRef.current = null; |
| | } |
| | |
| | isPreloadedRef.current = false; |
| | isRetryingRef.current = false; |
| | maxRetriesRef.current = 0; |
| | }; |
| | }, [project?.sandbox?.vnc_preview, project?.sandbox?.pass, startPreloading]); |
| |
|
| | return { |
| | isPreloaded: isPreloadedRef.current, |
| | preloadedIframe: preloadedIframeRef.current |
| | }; |
| | } |