import { createContext, useEffect, useState } from 'react' import { engineCommandManager } from 'lib/singletons' import { isDesktop } from 'lib/isDesktop' import { components } from 'lib/machine-api' import { reportRejection } from 'lib/trap' import { toSync } from 'lib/utils' import { commandBarActor } from 'machines/commandBarMachine' export type MachinesListing = Array< components['schemas']['MachineInfoResponse'] > export interface MachineManager { machines: MachinesListing machineApiIp: string | null currentMachine: components['schemas']['MachineInfoResponse'] | null noMachinesReason: () => string | undefined setCurrentMachine: ( m: components['schemas']['MachineInfoResponse'] | null ) => void } export const MachineManagerContext = createContext({ machines: [], machineApiIp: null, currentMachine: null, setCurrentMachine: ( _: components['schemas']['MachineInfoResponse'] | null ) => {}, noMachinesReason: () => undefined, }) export const MachineManagerProvider = ({ children, }: { children: React.ReactNode }) => { const [machines, setMachines] = useState([]) const [machineApiIp, setMachineApiIp] = useState(null) const [currentMachine, setCurrentMachine] = useState< components['schemas']['MachineInfoResponse'] | null >(null) // Get the reason message for why there are no machines. const noMachinesReason = (): string | undefined => { if (machines.length > 0) { return undefined } if (machineApiIp === null) { return 'Machine API server was not discovered' } return 'Machine API server was discovered, but no machines are available' } useEffect(() => { if (!isDesktop()) return const update = async () => { const _machineApiIp = await window.electron.getMachineApiIp() if (_machineApiIp === null) return setMachineApiIp(_machineApiIp) const _machines = await window.electron.listMachines(_machineApiIp) setMachines(_machines) } // Start a background job to update the machines every ten seconds. // If MDNS is already watching, this timeout will wait until it's done to trigger the // finding again. let timeoutId: ReturnType | undefined = undefined const timeoutLoop = () => { clearTimeout(timeoutId) timeoutId = setTimeout( toSync(async () => { await update() timeoutLoop() }, reportRejection), 1000 ) } timeoutLoop() update().catch(reportRejection) }, []) // Update engineCommandManager's copy of this data. useEffect(() => { const machineManagerNext = { machines, machineApiIp, currentMachine, noMachinesReason, setCurrentMachine, } engineCommandManager.machineManager = machineManagerNext commandBarActor.send({ type: 'Set machine manager', data: machineManagerNext, }) }, [machines, machineApiIp, currentMachine]) return ( {' '} {children}{' '} ) }