Files
leporello-js/service_worker.js

119 lines
3.2 KiB
JavaScript
Raw Normal View History

2022-09-10 02:48:13 +08:00
/*
Should prevent navigator.serviceWorker.controller from being null on first load, but doesn't work for some reason.
TODO: compare with
https://googlechrome.github.io/samples/service-worker/post-message/
which seems to work on first load
self.addEventListener('install', function(event) {
//event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim()); // Become available to all pages
});
*/
let dir_handle
2022-09-10 02:48:13 +08:00
self.addEventListener('message', async function(e) {
const msg = e.data
let reply
if(msg.type == 'SET_DIR_HANDLE') {
dir_handle = msg.data
2022-09-10 02:48:13 +08:00
reply = null
} else if(msg.type == 'GET_DIR_HANDLE') {
reply = dir_handle
2022-09-10 02:48:13 +08:00
} else {
throw new Error('unknown message type: ' + msg.type)
}
e.ports[0].postMessage(reply)
})
const send_message = (client, message) => {
return new Promise(function(resolve) {
const messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
resolve(event.data)
};
client.postMessage(message,
[messageChannel.port2]);
});
}
2022-11-28 23:12:55 +08:00
// Fake directory, http requests to this directory intercepted by service_worker
const FILES_ROOT = new URL('.', globalThis.location).pathname + '__leporello_files/'
const serve_response_from_dir = async event => {
2022-11-28 23:12:55 +08:00
const url = new URL(event.request.url)
const path = url.pathname.replace(FILES_ROOT, '')
let file
if(path == '__leporello_blank.html') {
file = ''
} else if(dir_handle != null) {
file = await read_file(dir_handle, path)
} else {
let client = await self.clients.get(event.clientId)
if(client == null) {
// Try to find main window and get dir_handle from it
for(const c of await self.clients.matchAll()) {
if(new URL(c.url).pathname == '/') {
client = c
}
}
}
2022-11-28 23:12:55 +08:00
// client is null for run_window initial page load, and is run_window for
// js scripts
if(client == null) {
// User probably reloaded run_window by manually hitting F5 after IDE
// window was closed
return new Response("", {status: 404})
2022-11-28 23:12:55 +08:00
} else {
dir_handle = await send_message(client, {type: 'GET_DIR_HANDLE'})
if(dir_handle == null) {
return new Response("", {status: 404})
} else {
file = await read_file(dir_handle, path)
}
}
}
const headers = new Headers([
[
'Content-Type',
path.endsWith('.js') || path.endsWith('.mjs')
? 'text/javascript'
: 'text/html'
]
])
return new Response(file, {headers})
}
2022-11-28 23:12:55 +08:00
self.addEventListener("fetch", event => {
const url = new URL(event.request.url)
2023-06-19 10:26:39 +03:00
if(url.pathname.startsWith(FILES_ROOT)) {
event.respondWith(serve_response_from_dir(event))
}
})
const read_file = async (dir_handle, filename) => {
if(typeof(filename) == 'string') {
filename = filename.split('/')
}
const [first, ...rest] = filename
if(rest.length == 0) {
const fhandle = await dir_handle.getFileHandle(first)
const file_data = await fhandle.getFile()
return await file_data.text()
} else {
const nested_dir_handle = await dir_handle.getDirectoryHandle(first)
return read_file(nested_dir_handle, rest)
}
}