Skip to content

Commit

Permalink
fix: do not use broadcast channels to tell sw to update config
Browse files Browse the repository at this point in the history
  • Loading branch information
SgtPooki committed Nov 13, 2024
1 parent dae8b2a commit 91f8ba3
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 167 deletions.
120 changes: 0 additions & 120 deletions src/lib/channel.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,3 @@ export enum COLORS {
success = '#0cb892',
error = '#ea5037'
}

export enum ChannelActions {
RELOAD_CONFIG = 'RELOAD_CONFIG',
RELOAD_CONFIG_SUCCESS = 'RELOAD_CONFIG_SUCCESS'
}
6 changes: 6 additions & 0 deletions src/lib/sw-comms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export async function tellSwToReloadConfig (): Promise<void> {
const resp = await fetch('/#/ipfs-sw-config-reload')
if (!resp.ok) {
throw new Error('Failed to reload config')
}
}
17 changes: 10 additions & 7 deletions src/pages/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import Input from '../components/textarea-input.jsx'
import { ConfigContext, ConfigProvider } from '../context/config-context.jsx'
import { RouteContext } from '../context/router-context.jsx'
import { ServiceWorkerProvider } from '../context/service-worker-context.jsx'
import { HeliaServiceWorkerCommsChannel } from '../lib/channel.js'
import { getConfig, setConfig as storeConfig } from '../lib/config-db.js'

Check failure on line 11 in src/pages/config.tsx

View workflow job for this annotation

GitHub Actions / build

'getConfig' is declared but its value is never read.
import { convertDnsResolverInputToObject, convertDnsResolverObjectToInput, convertUrlArrayToInput, convertUrlInputToArray } from '../lib/input-helpers.js'
import { getUiComponentLogger, uiLogger } from '../lib/logger.js'
import './default-page-styles.css'
import { tellSwToReloadConfig } from '../lib/sw-comms.js'

const uiComponentLogger = getUiComponentLogger('config-page')
const log = uiLogger.forComponent('config-page')
const channel = new HeliaServiceWorkerCommsChannel('WINDOW', uiComponentLogger)

/**
* Converts newline delimited URLs to an array of URLs, and validates each URL.
Expand Down Expand Up @@ -79,6 +78,7 @@ const dnsJsonValidationFn = (value: string): Error | null => {
function ConfigPage (): React.JSX.Element | null {
const { gotoPage } = useContext(RouteContext)
const { setConfig, resetConfig, gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport } = useContext(ConfigContext)
const [isSaving, setIsSaving] = useState(false)
const [error, setError] = useState<Error | null>(null)
const [resetKey, setResetKey] = useState(0)

Expand All @@ -90,7 +90,7 @@ function ConfigPage (): React.JSX.Element | null {
}
// we get the iframe origin from a query parameter called 'origin', if this is loaded in an iframe
const targetOrigin = decodeURIComponent(window.location.hash.split('@origin=')[1])
const config = await getConfig(uiComponentLogger)
const config = { gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport }
log.trace('config-page: postMessage config to origin ', config, targetOrigin)
/**
* The reload page in the parent window is listening for this message, and then it passes a RELOAD_CONFIG message to the service worker
Expand All @@ -99,7 +99,7 @@ function ConfigPage (): React.JSX.Element | null {
targetOrigin
})
log.trace('config-page: RELOAD_CONFIG sent to parent window')
}, [])
}, [gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport])

useEffect(() => {
/**
Expand All @@ -110,10 +110,11 @@ function ConfigPage (): React.JSX.Element | null {

const saveConfig = useCallback(async () => {
try {
setIsSaving(true)
await storeConfig({ gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport }, uiComponentLogger)
log.trace('config-page: sending RELOAD_CONFIG to service worker')
// update the BASE_URL service worker
await channel.messageAndWaitForResponse('SW', { target: 'SW', action: 'RELOAD_CONFIG' })
await tellSwToReloadConfig()
// base_domain service worker is updated
log.trace('config-page: RELOAD_CONFIG_SUCCESS for %s', window.location.origin)
// update the <subdomain>.<namespace>.BASE_URL service worker
Expand All @@ -124,8 +125,10 @@ function ConfigPage (): React.JSX.Element | null {
} catch (err) {
log.error('Error saving config', err)
setError(err as Error)
} finally {
setIsSaving(false)
}
}, [gateways, routers, dnsJsonResolvers, debug])
}, [gateways, routers, dnsJsonResolvers, debug, enableGatewayProviders, enableRecursiveGateways, enableWss, enableWebTransport])

const doResetConfig = useCallback(async () => {
// we need to clear out the localStorage items and make sure default values are set, and that all of our inputs are updated
Expand Down Expand Up @@ -217,7 +220,7 @@ function ConfigPage (): React.JSX.Element | null {
</InputSection>
<div className="w-100 inline-flex flex-row justify-between">
<button className="e2e-config-page-button button-reset mr5 pv3 tc bg-animate hover-bg-gold pointer w-30 bn" id="reset-config" onClick={() => { void doResetConfig() }}>Reset Config</button>
<ServiceWorkerReadyButton className="e2e-config-page-button white w-100 pa3" id="save-config" label='Save Config' waitingLabel='Waiting for service worker registration...' onClick={() => { void saveConfig() }} />
<ServiceWorkerReadyButton className="e2e-config-page-button white w-100 pa3" id="save-config" label={isSaving ? 'Saving...' : 'Save Config'} waitingLabel='Waiting for service worker registration...' onClick={() => { void saveConfig() }} />
</div>
{error != null && <span style={{ color: 'red' }}>{error.message}</span>}
</Collapsible>
Expand Down
6 changes: 2 additions & 4 deletions src/pages/redirect-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from 're
import Header from '../components/Header.jsx'
import { ConfigProvider } from '../context/config-context.jsx'
import { ServiceWorkerContext, ServiceWorkerProvider } from '../context/service-worker-context.jsx'
import { HeliaServiceWorkerCommsChannel } from '../lib/channel.js'
import { setConfig, type ConfigDb } from '../lib/config-db.js'
import { getSubdomainParts } from '../lib/get-subdomain-parts.js'
import { isConfigPage } from '../lib/is-config-page.js'
import { getUiComponentLogger, uiLogger } from '../lib/logger.js'
import { tellSwToReloadConfig } from '../lib/sw-comms.js'
import { translateIpfsRedirectUrl } from '../lib/translate-ipfs-redirect-url.js'
import './default-page-styles.css'
import LoadingPage from './loading.jsx'
Expand All @@ -33,8 +33,6 @@ const ConfigIframe = (): JSX.Element => {
)
}

const channel = new HeliaServiceWorkerCommsChannel('WINDOW', uiComponentLogger)

function RedirectPage ({ showConfigIframe = true }: { showConfigIframe?: boolean }): React.JSX.Element {
const [isAutoReloadEnabled] = useState(true)
const { isServiceWorkerRegistered } = useContext(ServiceWorkerContext)
Expand All @@ -49,7 +47,7 @@ function RedirectPage ({ showConfigIframe = true }: { showConfigIframe?: boolean
async function doWork (config: ConfigDb): Promise<void> {
try {
await setConfig(config, uiComponentLogger)
await channel.messageAndWaitForResponse('SW', { target: 'SW', action: 'RELOAD_CONFIG' })
await tellSwToReloadConfig()
log.trace('redirect-page: RELOAD_CONFIG_SUCCESS on %s', window.location.origin)
} catch (err) {
log.error('redirect-page: error setting config on subdomain', err)
Expand Down
27 changes: 12 additions & 15 deletions src/sw.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { HeliaServiceWorkerCommsChannel, type ChannelMessage } from './lib/channel.js'
import { getConfig, type ConfigDb } from './lib/config-db.js'
import { getRedirectUrl, isDeregisterRequest } from './lib/deregister-request.js'
import { GenericIDB } from './lib/generic-db.js'
Expand Down Expand Up @@ -101,7 +100,6 @@ const CURRENT_CACHES = Object.freeze({
swAssets: `sw-assets-v${CACHE_VERSION}`
})
let verifiedFetch: VerifiedFetch
const channel = new HeliaServiceWorkerCommsChannel('SW', swLogger)
const timeoutAbortEventType = 'verified-fetch-timeout'
const ONE_HOUR_IN_SECONDS = 3600
const urlInterceptRegex = [new RegExp(`${self.location.origin}/ip(n|f)s/`)]
Expand Down Expand Up @@ -138,19 +136,6 @@ self.addEventListener('activate', (event) => {
* button.
*/
event.waitUntil(self.clients.claim())
channel.onmessagefrom('WINDOW', async (message: MessageEvent<ChannelMessage<'WINDOW', null>>) => {
const { action } = message.data
switch (action) {
case 'RELOAD_CONFIG':
void updateVerifiedFetch().then(async () => {
channel.postMessage<any>({ action: 'RELOAD_CONFIG_SUCCESS', data: { config: await getConfig(swLogger) } })
log.trace('RELOAD_CONFIG_SUCCESS for %s', self.location.origin)
})
break
default:
log('unknown action: ', action)
}
})

// Delete all caches that aren't named in CURRENT_CACHES.
const expectedCacheNames = Object.keys(CURRENT_CACHES).map(function (key) {
Expand Down Expand Up @@ -204,6 +189,14 @@ async function requestRouting (event: FetchEvent, url: URL): Promise<boolean> {
} else if (isConfigPageRequest(url)) {
log.trace('config page request, ignoring ', event.request.url)
return false
} else if (isSwConfigReloadRequest(event)) {
log.trace('sw-config reload request, updating verifiedFetch')
event.waitUntil(updateVerifiedFetch().then(() => {
log.trace('sw-config reload request, verifiedFetch updated')
}).catch((err) => {
log.error('sw-config reload request, error updating verifiedFetch', err)
}))
return false
} else if (isSwAssetRequest(event)) {
log.trace('sw-asset request, returning cached response ', event.request.url)
/**
Expand Down Expand Up @@ -283,6 +276,10 @@ function isAggregateError (err: unknown): err is AggregateError {
return err instanceof Error && (err as AggregateError).errors != null
}

function isSwConfigReloadRequest (event: FetchEvent): boolean {
return event.request.url.includes('/#/ipfs-sw-config-reload')
}

function isSwAssetRequest (event: FetchEvent): boolean {
const isActualSwAsset = /^.+\/(?:ipfs-sw-).+$/.test(event.request.url)
// if path is not set, then it's a request for index.html which we should consider a sw asset
Expand Down
21 changes: 5 additions & 16 deletions test-e2e/fixtures/set-sw-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,11 @@ export async function setConfig ({ page, config }: { page: Page, config: Partial

db.close()

/**
* We need to do an operation like HeliaServiceWorkerCommsChannel.messageAndWaitForResponse
* see {@link HeliaServiceWorkerCommsChannel} for more information
*/
const channel = new BroadcastChannel('helia:sw')
const swResponsePromise = new Promise<void>((resolve, reject) => {
const onSuccess = (e: MessageEvent): void => {
if (e.data.action === 'RELOAD_CONFIG_SUCCESS') {
resolve()
channel.removeEventListener('message', onSuccess)
}
}
channel.addEventListener('message', onSuccess)
})
channel.postMessage({ target: 'SW', action: 'RELOAD_CONFIG', source: 'WINDOW' })
await swResponsePromise
const resp = await fetch('/#/ipfs-sw-config-reload')

if (!resp.ok) {
throw new Error('Failed to reload config')
}
}, {
gateways: [process.env.KUBO_GATEWAY],
routers: [process.env.KUBO_GATEWAY],
Expand Down

0 comments on commit 91f8ba3

Please sign in to comment.