diff --git a/app/src/service-worker/serviceWorker.js b/app/src/service-worker/serviceWorker.js index d9a2567..72d1914 100644 --- a/app/src/service-worker/serviceWorker.js +++ b/app/src/service-worker/serviceWorker.js @@ -1,13 +1,13 @@ import { precacheAndRoute } from "workbox-precaching"; import { openDB } from "idb"; -import init, { Client as CoreClient } from "meal-core"; -import sqlite3InitModule from '@sqlite.org/sqlite-wasm'; +import init, { create_client } from "meal-core"; /** -* @import { Schema } from "./schema" -* @import { Operation } from "./operation" -*/ + * @import { Schema } from "./schema" + * @import { Operation } from "./operation" + */ +// Reduce noise // @ts-expect-error self.__WB_DISABLE_DEV_LOGS = true; @@ -24,23 +24,18 @@ const openDatabase = /** @type {typeof openDB} */ (openDB)("meal", 1, { }, }); - openDatabase.then((database) => { const transaction = database.transaction("configuration", "readwrite"); const store = transaction.objectStore("configuration"); if (store.add === undefined) throw new Error("Store is undefined"); store.add({}); - -}) +}); /** -* -* @param {Operation} operation -*/ -function handleDatabaseRequest(operation) { - console.debug("handle database request", arguments); -} + * + * @returns {Promise} + */ async function initializeClient() { // Get configuration const database = await openDatabase; @@ -52,26 +47,57 @@ async function initializeClient() { // Have to use wasm-pack --target web to build the wasm package to get the init function because with the bundler target // it is included as a top level await which is not supported by service workers according to the web spec await init(); - const client = new CoreClient( - configuration?.clientId, - configuration?.user?.name, - handleDatabaseRequest + + // Persist client state + const directory = await navigator.storage.getDirectory(); + + const FILE_NAME = "client.meal"; + /** @type {FileSystemFileHandle | undefined} */ + let fileHandle; + try { + fileHandle = await directory.getFileHandle(FILE_NAME); + } catch (error) { + // Finding out if the file does not exist is a bit unergonomic + if (!(error instanceof DOMException) || error.name !== "NotFoundError") + throw error; + + console.debug("No client.meal file found"); + } + + if (fileHandle !== undefined) { + const file = await fileHandle.getFile(); + return await file.arrayBuffer(); + } + + const client = create_client( + configuration.clientId, + configuration.user?.name ); - return client; + fileHandle = await directory.getFileHandle(FILE_NAME, { + create: true, + }); + + const writeStream = await fileHandle.createWritable(); + if (client.buffer instanceof SharedArrayBuffer) + throw new Error("Did not expect a SharedArrayBuffer"); + + try { + await writeStream.write(client.buffer); + } finally { + writeStream.close(); + } + + console.debug("Created new client", client); + + return client.buffer; } const setupClient = initializeClient(); -// const id = localStorage.getItem("id"); -// const name = localStorage.getItem("name"); -// const isOnboarded = localStorage.getItem("isOnboarded") !== null; -// const client = new Client(id ?? undefined, name ?? undefined); - /** The url for messages endpoint. Don't forget the trailing slash. */ const messagesUrl = new URL("/messages/", self.location.origin); -const broadcast = new BroadcastChannel("melt"); /** * @param {MessageEvent} event */ @@ -101,44 +127,44 @@ async function handleMessage(event) { } case "sendMessage": { const client = await setupClient; - const body = client.send_message(event.data.groupId, { - sent: event.data.sent.toISOString(), - text: event.data.text, - }); - const url = new URL(event.data.friendId, messagesUrl); - const request = new Request(url, { - method: "post", - headers: { - //https://www.rfc-editor.org/rfc/rfc9420.html#name-the-message-mls-media-type - "Content-Type": "message/mls", - }, - body, - }); - - //TODO error handling - //TODO retry - await fetch(request); + // const body = client.send_message(event.data.groupId, { + // sent: event.data.sent.toISOString(), + // text: event.data.text, + // }); + // const url = new URL(event.data.friendId, messagesUrl); + // const request = new Request(url, { + // method: "post", + // headers: { + // //https://www.rfc-editor.org/rfc/rfc9420.html#name-the-message-mls-media-type + // "Content-Type": "message/mls", + // }, + // body, + // }); + + // //TODO error handling + // //TODO retry + // await fetch(request); return; } case "createInvite": { const client = await setupClient; - const encodedInvite = client.create_invite(client.get_name()); - const inviteUrl = new URL(`/join/${encodedInvite}`, location.origin); - - if (event.source === null) - throw new Error( - "Expected browser context source to send invite url back to" - ); - - if (!(event.source instanceof Client)) - throw new Error("Expected message event source to be a client"); - - /** @type {ServiceWorkerResponse} */ - const response = { - type: "inviteUrl", - inviteUrl: inviteUrl.href, - }; - event.ports[0].postMessage(response); + // const encodedInvite = client.create_invite(client.get_name()); + // const inviteUrl = new URL(`/join/${encodedInvite}`, location.origin); + + // if (event.source === null) + // throw new Error( + // "Expected browser context source to send invite url back to" + // ); + + // if (!(event.source instanceof Client)) + // throw new Error("Expected message event source to be a client"); + + // /** @type {ServiceWorkerResponse} */ + // const response = { + // type: "inviteUrl", + // inviteUrl: inviteUrl.href, + // }; + // event.ports[0].postMessage(response); return; } case "inviteFromPackage": {