X-Git-Url: https://git.localhorst.tv/?a=blobdiff_plain;f=resources%2Fjs%2Fhooks%2Fsnes.js;fp=resources%2Fjs%2Fhooks%2Fsnes.js;h=05e84b2e496d488452a6e53fcfbc32e553cae1f2;hb=73c29bf37f10df401d87d14cc26999f88ce77379;hp=0000000000000000000000000000000000000000;hpb=2ba39c5f4632579146d2663d82149a156a4e96c1;p=alttp.git diff --git a/resources/js/hooks/snes.js b/resources/js/hooks/snes.js new file mode 100644 index 0000000..05e84b2 --- /dev/null +++ b/resources/js/hooks/snes.js @@ -0,0 +1,125 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +import SNESSocket from '../helpers/SNESSocket'; + +const context = React.createContext({}); + +export const useSNES = () => React.useContext(context); + +export const SNESProvider = ({ children }) => { + const [enabled, setEnabled] = React.useState(false); + + const sock = React.useRef(null); + + const [settings, setSettings] = React.useState({ + proto: 'ws', + host: 'localhost', + port: 8080, + device: '', + }); + + const [status, setStatus] = React.useState({ + connected: false, + device: '', + deviceList: [], + error: false, + }); + + React.useEffect(() => { + if (sock.current) { + sock.current.close(); + sock.current = null; + } + if (enabled) { + const tryAttach = () => { + const { deviceList } = sock.current; + let device = ''; + if (deviceList.includes(settings.device)) { + device = settings.device; + } else if (deviceList.length > 0) { + device = deviceList[0]; + } + setStatus(s => ({ ...s, device, deviceList })); + if (device) { + sock.current.attachDevice(device); + } + }; + sock.current = new SNESSocket(`${settings.proto}://${settings.host}:${settings.port}`); + sock.current.onclose = () => { + setStatus({ + connected: false, + device: '', + deviceList: [], + error: false, + }); + }; + sock.current.onerror = (e) => { + setStatus({ + connected: false, + device: '', + deviceList: [], + error: e, + }); + }; + sock.current.onopen = () => { + setStatus({ + connected: true, + device: '', + deviceList: [], + error: false, + }); + sock.current.requestDeviceList(() => { + tryAttach(); + }); + }; + const watchdog = setInterval(() => { + if (!sock.current.isOpen()) { + sock.current.open(); + return; + } + if (!sock.current.device) { + sock.current.requestDeviceList(() => { + tryAttach(); + }); + } + }, 5000); + return () => { + clearInterval(watchdog); + }; + } + }, [enabled, settings]); + + const enable = React.useCallback(() => { + setEnabled(prevEnabled => { + if (prevEnabled) return true; + return true; + }); + }, []); + + const disable = React.useCallback(() => { + setEnabled(prevEnabled => { + if (!prevEnabled) return false; + return false; + }); + }, []); + + React.useEffect(() => { + const savedSettings = localStorage.getItem('snes.settings'); + if (savedSettings) { + setSettings(JSON.parse(savedSettings)); + } + }, []); + + const value = React.useMemo(() => { + return { disable, enable, enabled, settings, sock, status }; + }, [disable, enable, enabled, settings, sock, status]); + + return + {children} + ; +}; + +SNESProvider.propTypes = { + children: PropTypes.node, +};