]> git.localhorst.tv Git - alttp.git/blobdiff - resources/js/hooks/snes.js
guessing game auto-tracking
[alttp.git] / resources / js / hooks / snes.js
diff --git a/resources/js/hooks/snes.js b/resources/js/hooks/snes.js
new file mode 100644 (file)
index 0000000..05e84b2
--- /dev/null
@@ -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 <context.Provider value={value}>
+               {children}
+       </context.Provider>;
+};
+
+SNESProvider.propTypes = {
+       children: PropTypes.node,
+};