From ddc09a102ca307a416a7b1533461579783a5d8f6 Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:25:22 -0500 Subject: [PATCH 1/3] feat: probe for local gateway and add to config --- src/lib/local-gateway.ts | 32 ++++++++++++++++++++++++++++++++ src/pages/config.tsx | 31 +++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/lib/local-gateway.ts diff --git a/src/lib/local-gateway.ts b/src/lib/local-gateway.ts new file mode 100644 index 00000000..f48dcfbf --- /dev/null +++ b/src/lib/local-gateway.ts @@ -0,0 +1,32 @@ +import { uiLogger } from './logger.js' + +export const localGwUrl = 'http://localhost:8080' +const localGwTestUrl = `${localGwUrl}/ipfs/bafkqablimvwgy3y?format=raw` +const expectedContentType = 'application/vnd.ipld.raw' +const expectedResponseBody = 'hello' + +const log = uiLogger.forComponent('local-gateway-prober') + +export async function hasLocalGateway (): Promise { + try { + log(`probing for local trustless gateway at ${localGwTestUrl}`) + const resp = await fetch(localGwTestUrl, { cache: 'no-store' }) + if (!resp.ok) { + return false + } + if (resp.headers.get('Content-Type') !== expectedContentType) { + return false + } + const respBody = await resp.text() + + if (respBody === expectedResponseBody) { + log(`found local trustless gateway at ${localGwTestUrl}`) + return true + } else { + return false + } + } catch (e: unknown) { + log.error('failed to probe trustless gateway', e) + return false + } +} diff --git a/src/pages/config.tsx b/src/pages/config.tsx index ba106b6b..75e09d08 100644 --- a/src/pages/config.tsx +++ b/src/pages/config.tsx @@ -10,6 +10,7 @@ import { RouteContext } from '../context/router-context.jsx' import { ServiceWorkerProvider } from '../context/service-worker-context.jsx' import { HeliaServiceWorkerCommsChannel } from '../lib/channel.js' import { defaultDnsJsonResolvers, defaultEnableGatewayProviders, defaultEnableRecursiveGateways, defaultEnableWebTransport, defaultEnableWss, defaultGateways, defaultRouters, getConfig, localStorageToIdb, resetConfig } from '../lib/config-db.js' +import { hasLocalGateway, localGwUrl } from '../lib/local-gateway.js' import { LOCAL_STORAGE_KEYS, convertDnsResolverInputToObject, convertDnsResolverObjectToInput, convertUrlArrayToInput, convertUrlInputToArray } from '../lib/local-storage.js' import { getUiComponentLogger, uiLogger } from '../lib/logger.js' import './default-page-styles.css' @@ -106,6 +107,36 @@ function ConfigPage (): React.JSX.Element | null { }, []) useEffect(() => { + hasLocalGateway() + .then(async hasLocalGw => { + // check if local storage has it. + const unparsedGwConf = localStorage.getItem(LOCAL_STORAGE_KEYS.config.gateways) + let gwConf = unparsedGwConf != null ? JSON.parse(unparsedGwConf) as string[] : defaultGateways + + if (hasLocalGw) { + // Add the local gateway to config if not there already + if (!gwConf.includes(localGwUrl)) { + log(`Adding ${localGwUrl} to gateway list`) + gwConf.unshift(localGwUrl) + } + } else if (gwConf.includes(localGwUrl)) { + // remove local gateway from the configuration if the gateway is not available + gwConf = gwConf.filter(gw => gw !== localGwUrl) + if (gwConf.length === 0) { + // if there are no gateways following the removal reset to the default gateways + gwConf = defaultGateways + } + } + + // persist to localstorage, idb and 🙃 + localStorage.setItem(LOCAL_STORAGE_KEYS.config.gateways, JSON.stringify(gwConf)) + await localStorageToIdb() + await channel.messageAndWaitForResponse('SW', { target: 'SW', action: 'RELOAD_CONFIG' }) + await postFromIframeToParentSw() + setResetKey((prev) => prev + 1) // needed to ensure the config is re-rendered + }).catch(err => { + log.error('failed to probe for local gateway', err) + }) /** * On initial load, we want to send the config to the parent window, so that the reload page can auto-reload if enabled, and the subdomain registered service worker gets the latest config without user interaction. */ From 102afab7018d70b3354d2e34d9e9a74c42a659a8 Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Thu, 24 Oct 2024 20:23:26 -0500 Subject: [PATCH 2/3] feat: initial UI for adding local gateway --- src/components/local-storage-toggle.tsx | 10 +++- src/hooks/use-local-gateway.ts | 36 +++++++++++++ src/lib/local-gateway.ts | 27 ++++------ src/lib/local-storage.ts | 1 + src/pages/config.tsx | 70 ++++++++++++++----------- src/sw.ts | 3 ++ 6 files changed, 97 insertions(+), 50 deletions(-) create mode 100644 src/hooks/use-local-gateway.ts diff --git a/src/components/local-storage-toggle.tsx b/src/components/local-storage-toggle.tsx index 19309b3e..ddbf70c8 100644 --- a/src/components/local-storage-toggle.tsx +++ b/src/components/local-storage-toggle.tsx @@ -14,6 +14,8 @@ interface LocalStorageToggleProps { className?: string onClick?: React.MouseEventHandler resetKey: number + disabled?: boolean + handleChange?(toggleValue: boolean): void } export const LocalStorageToggle: React.FC = ({ @@ -22,6 +24,8 @@ export const LocalStorageToggle: React.FC = ({ defaultValue, resetKey, localStorageKey, + disabled, + handleChange, ...props }) => { const [isChecked, setIsChecked] = useState(() => { @@ -32,10 +36,11 @@ export const LocalStorageToggle: React.FC = ({ setIsChecked(getLocalStorageValue(localStorageKey, defaultValue)) }, [resetKey]) - const handleChange = (event: React.ChangeEvent): void => { + const handleChangeInner = (event: React.ChangeEvent): void => { const newValue = event.target.checked setIsChecked(newValue) localStorage.setItem(localStorageKey, String(newValue)) + handleChange?.(newValue) } return ( @@ -45,9 +50,10 @@ export const LocalStorageToggle: React.FC = ({