diff --git a/apps/web/src/common/sqlite/shared-service.ts b/apps/web/src/common/sqlite/shared-service.ts
index b64fce1ed..6b78c8d54 100644
--- a/apps/web/src/common/sqlite/shared-service.ts
+++ b/apps/web/src/common/sqlite/shared-service.ts
@@ -18,6 +18,7 @@ along with this program. If not, see .
*/
import SharedWorker from "./shared-service.worker.ts?sharedworker";
+import { Mutex } from "async-mutex";
const sharedWorker = globalThis.SharedWorker
? new SharedWorker({
@@ -39,6 +40,7 @@ export class SharedService extends EventTarget {
// This is client state to track the provider. The provider state is
// mostly managed within activate().
#providerPort?: Promise;
+ #providerPortMutex = new Mutex();
providerCallbacks: Map<
string,
{
@@ -64,6 +66,7 @@ export class SharedService extends EventTarget {
this.#clientChannel.addEventListener(
"message",
async ({ data }) => {
+ console.log("got message from provider", data);
if (
data?.type === "provider" &&
data?.sharedService === this.serviceName &&
@@ -74,6 +77,7 @@ export class SharedService extends EventTarget {
// Discard any old provider and connect to the new one.
this.#providerPort?.then((port) => port?.close());
this.#providerPort = this.#providerChange();
+ this.#providerPortMutex.release();
await this.#resendPendingCallbacks();
}
},
@@ -83,6 +87,7 @@ export class SharedService extends EventTarget {
type: "client",
sharedService: this.serviceName
});
+ this.#providerPortMutex.acquire();
window.addEventListener("beforeunload", () => {
this.close();
@@ -104,9 +109,11 @@ export class SharedService extends EventTarget {
const LOCK_NAME = `SharedService-${this.serviceName}`;
navigator.locks
.request(LOCK_NAME, { signal: this.#onDeactivate.signal }, async () => {
+ console.time("getting provider port");
// Get the port to request client ports.
const { port, onclose } = await portProviderFunc();
port.start();
+ console.timeEnd("getting provider port");
// Listen for client requests. A separate BroadcastChannel
// instance is necessary because we may be serving our own
@@ -168,6 +175,7 @@ export class SharedService extends EventTarget {
{ signal: this.#onDeactivate?.signal }
);
+ console.log("sending message to clients", providerId, this.serviceName);
// Tell everyone that we are the new provider.
broadcastChannel.postMessage({
type: "provider",
@@ -207,9 +215,11 @@ export class SharedService extends EventTarget {
}
async #getClientId() {
+ console.time("getting client id");
// Use a Web Lock to determine our clientId.
const nonce = Math.random().toString();
const clientId = await navigator.locks.request(nonce, async () => {
+ console.log("got clientid lock");
const { held } = await navigator.locks.query();
return held?.find((lock) => lock.name === nonce)?.clientId;
});
@@ -231,6 +241,7 @@ export class SharedService extends EventTarget {
sharedWorker?.port.start();
sharedWorker?.port.postMessage({ clientId });
+ console.timeEnd("getting client id");
return clientId;
}
@@ -364,6 +375,10 @@ export class SharedService extends EventTarget {
})();
async getProviderPort() {
+ console.log("waiting for port provider to become available");
+ await this.#providerPortMutex.waitForUnlock();
+ console.log("port provider ready.");
+
let tries = 0;
let providerPort = await this.#providerPort;
while (!providerPort) {
@@ -371,7 +386,10 @@ export class SharedService extends EventTarget {
throw new Error("Could not find a provider port to communicate with.");
providerPort = await this.#providerPort;
- console.warn("Provider port not found. Retrying in 50ms...");
+ console.warn(
+ "Provider port not found. Retrying in 50ms...",
+ this.#providerPort
+ );
await new Promise((resolve) => setTimeout(resolve, 50));
}
return providerPort;
diff --git a/apps/web/src/common/sqlite/shared-service.worker.ts b/apps/web/src/common/sqlite/shared-service.worker.ts
index 92f011629..7a6c6cdad 100644
--- a/apps/web/src/common/sqlite/shared-service.worker.ts
+++ b/apps/web/src/common/sqlite/shared-service.worker.ts
@@ -26,11 +26,13 @@ declare var self: SharedWorkerGlobalScope & typeof globalThis;
const mapClientIdToPort: Map = new Map();
self.addEventListener("connect", (event) => {
+ console.log("connected", event);
// The first message from a client associates the clientId with the port.
const workerPort = event.ports[0];
workerPort.addEventListener(
"message",
(event) => {
+ console.log("received message", event.data);
mapClientIdToPort.set(event.data.clientId, workerPort);
// Remove the entry when the client goes away, which we detect when
@@ -43,6 +45,7 @@ self.addEventListener("connect", (event) => {
// Subsequent messages will be forwarded.
workerPort.addEventListener("message", (event) => {
const port = mapClientIdToPort.get(event.data.clientId);
+ console.log("sending message to client", event.data.clientId, port);
port?.postMessage(event.data, [...event.ports]);
});
},