/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useCallback, useEffect, useRef, useState } from 'react' import { getDeploymentSettings, testDeploymentConnection } from '../api' interface ConnectionState { loading: boolean ok: boolean | null error: string | null } // Connection cache (5 minutes TTL) const CONNECTION_CACHE_TTL = 5 * 60 * 1000 let connectionCache: { ok: boolean timestamp: number } | null = null function getCachedConnection(): boolean | null { if (!connectionCache) return null if (Date.now() - connectionCache.timestamp > CONNECTION_CACHE_TTL) { connectionCache = null return null } return connectionCache.ok } function setCachedConnection(ok: boolean) { connectionCache = { ok, timestamp: Date.now() } } export function clearConnectionCache() { connectionCache = null } type LoadingPhase = 'idle' | 'settings' | 'connection' | 'done' export function useModelDeploymentSettings() { const [loading, setLoading] = useState(true) const [loadingPhase, setLoadingPhase] = useState('settings') const [settings, setSettings] = useState>({ 'model_deployment.ionet.enabled': false, }) const [connectionState, setConnectionState] = useState({ loading: false, ok: null, error: null, }) const initialLoadRef = useRef(true) // Parallel fetch: settings + connection test (when enabled) const fetchAll = useCallback(async (useCache = true) => { setLoading(true) setLoadingPhase('settings') try { // Step 1: Fetch settings first (usually fast) const response = await getDeploymentSettings() const isEnabled = response?.success && response?.data?.enabled === true setSettings({ 'model_deployment.ionet.enabled': isEnabled, }) if (!isEnabled) { // Not enabled, done setConnectionState({ loading: false, ok: null, error: null }) setLoadingPhase('done') setLoading(false) return } // Step 2: Check connection (check cache first) if (useCache) { const cached = getCachedConnection() if (cached !== null) { setConnectionState({ loading: false, ok: cached, error: null }) setLoadingPhase('done') setLoading(false) return } } // Test connection setLoadingPhase('connection') setConnectionState({ loading: true, ok: null, error: null }) try { const connResponse = await testDeploymentConnection() if (connResponse?.success) { setCachedConnection(true) setConnectionState({ loading: false, ok: true, error: null }) } else { const message = connResponse?.message || 'Connection failed' setCachedConnection(false) setConnectionState({ loading: false, ok: false, error: message }) } } catch (error: unknown) { const errMsg = error instanceof Error ? error.message : 'Connection failed' setCachedConnection(false) setConnectionState({ loading: false, ok: false, error: errMsg }) } } catch { // Settings fetch failed, use defaults setConnectionState({ loading: false, ok: null, error: null }) } finally { setLoadingPhase('done') setLoading(false) } }, []) // Initial load useEffect(() => { if (initialLoadRef.current) { initialLoadRef.current = false fetchAll(true) } }, [fetchAll]) const isIoNetEnabled = Boolean(settings['model_deployment.ionet.enabled']) // Manual retry (skip cache) const testConnection = useCallback(async () => { clearConnectionCache() setConnectionState({ loading: true, ok: null, error: null }) setLoadingPhase('connection') try { const response = await testDeploymentConnection() if (response?.success) { setCachedConnection(true) setConnectionState({ loading: false, ok: true, error: null }) return } const message = response?.message || 'Connection failed' setCachedConnection(false) setConnectionState({ loading: false, ok: false, error: message }) } catch (error: unknown) { const errMsg = error instanceof Error ? error.message : 'Connection failed' setCachedConnection(false) setConnectionState({ loading: false, ok: false, error: errMsg }) } finally { setLoadingPhase('done') } }, []) // Refresh all (skip cache) const refresh = useCallback(() => { clearConnectionCache() return fetchAll(false) }, [fetchAll]) // Refresh on window focus (useful after saving settings in another page) useEffect(() => { const handler = () => { // Use cache on focus to avoid unnecessary requests fetchAll(true) } window.addEventListener('focus', handler) return () => window.removeEventListener('focus', handler) }, [fetchAll]) return { loading, loadingPhase, settings, isIoNetEnabled, refresh, connectionLoading: connectionState.loading, connectionOk: connectionState.ok, connectionError: connectionState.error, testConnection, } }