import React from 'react' import { reducer, action, CONNECTION_STATE, INITIAL_STATE } from '../../common/state.mjs' function getConfig () { return { endpoint: process.env.NODE_ENV === 'development' ? 'http://localhost:3030' : '' } } function useConfig () { return getConfig() } export function useCommand (defaultCommand, defaultArgs = {}) { const config = useConfig() const url = config.endpoint + '/command' const headers = { 'content-type': 'application/json' } const [pending, setPending] = React.useState(false) const [error, setError] = React.useState(null) const [success, setSuccess] = React.useState(null) return { pending, error, success, dispatch } async function dispatch (command = defaultCommand, args = defaultArgs) { setPending(true) try { const res = await fetch(url, { headers, method: 'post', body: JSON.stringify({ command, args }) }) const json = await res.json() if (json.error) throw new Error('Remote error: ' + json.details) setSuccess(json) } catch (err) { setError(error) } finally { setPending(false) } } } export function useRemoteState (opts = {}) { const { retryInterval = 1000 } = opts const config = useConfig() const [retry, setRetry] = React.useState(0) const url = config.endpoint + '/sse' const [state, dispatch] = React.useReducer(reducer, INITIAL_STATE) const es = React.useRef() function reconnect () { if (es.current) es.current.close() es.current = null setRetry(retry => retry + 1) } // setup event source React.useEffect(() => { if (es.current) return es.current = new EventSource(url) }, [retry]) // process event source React.useEffect(() => { if (!es.current) return const eventSource = es.current eventSource.onmessage = (event) => { const action = JSON.parse(event.data) dispatch(action) } eventSource.onerror = () => { dispatch(action(CONNECTION_STATE, { error: `Failed to connect to backend` })) if (retryInterval) setTimeout(reconnect, retryInterval) } }, [es.current]) return { state } }