diff --git a/docs/index.html b/docs/index.html index 0468b95..9a60a59 100644 --- a/docs/index.html +++ b/docs/index.html @@ -20,22 +20,7 @@ \ No newline at end of file diff --git a/docs/sw.js b/docs/sw.js deleted file mode 100644 index 5d3690d..0000000 --- a/docs/sw.js +++ /dev/null @@ -1,23 +0,0 @@ -importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.13.4/misc/wasm/wasm_exec.js') - -addEventListener('install', (event) => { - console.log('install!') - // wasmhttp.serve({ - // wasm: 'api.wasm', - // base: '/api', - // }) - event.waitUntil(skipWaiting()) -}) - -addEventListener('activate', event => { - console.log('activate!') - event.waitUntil(clients.claim()) -}) - -addEventListener('fetch', () => { - console.log('fetch!') -}) - -addEventListener('message', ({ data }) => { - console.log('message', data) -}) diff --git a/index.js b/index.js new file mode 100644 index 0000000..f35a13a --- /dev/null +++ b/index.js @@ -0,0 +1,14 @@ +window.wasmhttp = { + register: async (wasm, { scope, base = '' } = {}) => { + const options = {} + if (scope) options.scope = scope + //FIXME register once + const registration = await navigator.serviceWorker.register('sw.js', options) + await navigator.serviceWorker.ready + registration.active.postMessage({ + type: 'wasmhttp.register', + wasm, + base, + }) + } +} diff --git a/sw.js b/sw.js index 7460c39..0442478 100644 --- a/sw.js +++ b/sw.js @@ -1,5 +1,4 @@ -let nextHandlerId = 1 -const handlerResolvers = {} +importScripts('https://cdn.jsdelivr.net/gh/golang/go@go1.13.4/misc/wasm/wasm_exec.js') const startWasm = async (wasm, WASMHTTP_HANDLER_ID, WASMHTTP_PATH) => { const go = new Go() @@ -23,33 +22,50 @@ const trimEnd = (s, c) => { return r } +// addEventListener('install', (event) => { +// event.waitUntil(skipWaiting()) +// }) + +const running = new Set() +let nextHandlerId = 1 +const handlerResolvers = {} +const handlers = [] + self.wasmhttp = { - serve: ({ wasm, base } = {}) => { - try { - if (!wasm) throw TypeError('options.wasm must be defined') - - const handlerId = `${nextHandlerId++}` - const handler = new Promise(resolve => handlerResolvers[handlerId] = resolve) - - let path = new URL(registration.scope).pathname - if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}` - - startWasm(wasm, handlerId, path) - - addEventListener('fetch', async e => { - if (!new URL(e.request.url).pathname.startsWith(path)) return - - // FIXME try catch - e.respondWith((await handler)(e.request)) - }) - } catch (e) { - console.error('wasmhttp: error:', e) - throw e - } - }, - registerHandler: (handlerId, handler) => { handlerResolvers[handlerId](handler) delete handlerResolvers[handlerId] }, } + +addEventListener('activate', event => event.waitUntil(clients.claim())) + +addEventListener('message', async ({ data }) => { + if (data.type !== 'wasmhttp.register') return + + const { wasm, base } = data + + let path = new URL(registration.scope).pathname + if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}` + + const key = `${wasm}:${path}` + + if (!running.has(key)) { + const handlerId = `${nextHandlerId++}` + const handler = new Promise(resolve => handlerResolvers[handlerId] = resolve) + + startWasm(wasm, handlerId, path) + running.add(key) + + // FIXME try catch + handlers.push([path, await handler]) + } +}) + +addEventListener('fetch', e => { + const { pathname } = new URL(e.request.url) + const [, handler] = handlers.find(([path]) => pathname.startsWith(path)) || [] + if (!handler) return + + e.respondWith((handler)(e.request)) +})