import { useCallback, useEffect, useState } from 'react' import { MonitorDot } from 'lucide-react' import { activeInterconnectNodeId, api, setActiveInterconnectNodeId, } from '@/api' import { getNodes, type InterconnectNode } from '@/api/interconnect' import { useEventBus } from '@/hooks/useEventBus' import { SYSTEM_EVENTS } from '@/constants' import { cn } from '@/lib/utils' export function NodeSwitcher() { const [nodes, setNodes] = useState([]) const [selected, setSelected] = useState(activeInterconnectNodeId || 'local') const [isMaster, setIsMaster] = useState(false) const [open, setOpen] = useState(false) const fetchNodes = useCallback(async () => { try { const res = await getNodes() setNodes(Array.isArray(res) ? res : []) } catch { setNodes([]) } }, []) const updateRoleState = useCallback( (role: string) => { const master = role === 'master' setIsMaster(master) if (master) { setSelected(activeInterconnectNodeId || 'local') fetchNodes() } else { setNodes([]) setSelected('local') const traveling = !!document.cookie.match(/(?:^| )active_interconnect_node_id=([^;]*)/) if (activeInterconnectNodeId && !traveling) { setActiveInterconnectNodeId('') } } }, [fetchNodes], ) useEffect(() => { ;(async () => { try { const role = await api.settings.get('interconnect', 'interconnect_role') updateRoleState(role || 'none') } catch { updateRoleState('none') } })() }, [updateRoleState]) useEventBus(SYSTEM_EVENTS.INTERCONNECT_ROLE_CHANGED, (role) => { updateRoleState(String(role || 'none')) }) useEffect(() => { if (!isMaster) return const t = window.setInterval(fetchNodes, 120000) const onVis = () => { if (document.visibilityState === 'visible') fetchNodes() } document.addEventListener('visibilitychange', onVis) return () => { clearInterval(t) document.removeEventListener('visibilitychange', onVis) } }, [isMaster, fetchNodes]) if (!isMaster) return null const handleSelect = (val: string) => { setSelected(val) setOpen(false) if (val === 'local') { setActiveInterconnectNodeId('') } else { const name = nodes.find((n) => n.id === val)?.name || '' setActiveInterconnectNodeId(val, name) } window.location.reload() } const allOptions = [ { value: 'local', label: '本机节点' }, ...nodes.map((n) => ({ value: n.id, label: n.name })), ] const currentLabel = allOptions.find((o) => o.value === selected)?.label || '本机节点' return (
{open && (
{allOptions.map((opt) => ( ))}
)} {open && (
setOpen(false)} /> )}
) }