Skip to content

Commit

Permalink
EventSessionDB only in memory
Browse files Browse the repository at this point in the history
  • Loading branch information
enjikaka committed Apr 26, 2024
1 parent 2f27463 commit 3e10cbd
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 186 deletions.
1 change: 1 addition & 0 deletions packages/player/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@tidal-music/auth": "workspace:^",
"@tidal-music/common": "workspace:^",
"@tidal-music/true-time": "workspace:^",
"@types/chai": "4.3.14",
"@types/js-levenshtein": "1.1.3",
"@types/mocha": "10.0.6",
"@types/node": "20.12.7",
Expand Down
197 changes: 11 additions & 186 deletions packages/player/src/internal/helpers/event-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,65 +7,10 @@ type MaybeEvent<P> =
| undefined;

class EventSessionDB {
// @ts-expect-error - Assigned through private method #init.
#db: IDBDatabase;
// @ts-expect-error - Assigned through private method #init.
#name: string;
#openingDatabase: Promise<void> | undefined;
#db: Map<string, any>;

constructor() {
this.#createNewDatabase().catch(console.error);
}

/**
* Create a new database and set the #openingDatabase promise to undefined when it's done.
*/
async #createNewDatabase() {
this.#openingDatabase = this.#init().then(() => {
this.#openingDatabase = undefined;
});

return this.#openingDatabase;
}

/**
* Ensure that the database is open and ready to use. Using a promise to
* debounce multiple calls to this method.
*/
async #ensureDatabase() {
let isExisting = false;

if (this.#openingDatabase) {
await this.#openingDatabase;
} else {
// Attempt to open the database
this.#openingDatabase = new Promise<void>((resolve, reject) => {
const request = window.indexedDB.open(this.#name);

// This event means the database was found and successfully opened
request.onsuccess = () => {
isExisting = true; // Database exists
resolve();
request.result.close(); // Close the database connection
};

// This event means the database does not exist and is being created
request.onupgradeneeded = () => {
isExisting = false; // Trigger database creation
};

request.onerror = () => {
reject(request.error);
};
});

await this.#openingDatabase;

// If database didn't exist, create it
if (!isExisting) {
await this.#createNewDatabase();
}
}
this.#db = new Map();
}

async #generateCompositeKey(streamingSessionId: string, eventName: string) {
Expand All @@ -81,44 +26,6 @@ class EventSessionDB {
return hashHex;
}

async #init() {
return new Promise<void>((resolve, reject) => {
this.#removeOldDatabase();

const uuid = crypto.randomUUID();
const name = 'streaming-sessions-' + uuid;
this.#name = name;
const request = indexedDB.open(name, 1);

request.onupgradeneeded = () => {
this.#db = request.result;

if (!this.#db.objectStoreNames.contains('events')) {
this.#db.createObjectStore('events', {
keyPath: 'id',
});
}
};

request.onsuccess = () => {
this.#db = request.result;
localStorage.setItem('ssuid', uuid);

resolve();
};

request.onerror = () => reject(request.error);
});
}

#removeOldDatabase() {
const ssuid = localStorage.getItem('ssuid');

if (ssuid) {
indexedDB.deleteDatabase('streaming-sessions-' + ssuid);
}
}

/**
* Delete a logged event by name and streamingSessionId.
*/
Expand All @@ -129,39 +36,14 @@ class EventSessionDB {
name: string;
streamingSessionId: string;
}): Promise<void> {
await this.#ensureDatabase();

const compositeKey = await this.#generateCompositeKey(
streamingSessionId,
name,
);

return new Promise<void>((resolve, reject) => {
try {
const transaction = this.#db.transaction(['events'], 'readwrite');
const store = transaction.objectStore('events');
const request = store.delete(compositeKey);

request.onsuccess = () => resolve();

request.onerror = () => {
throw request.error;
};
} catch (error) {
reject(error);
}
}).catch(async error => {
if (
error instanceof DOMException &&
error.message.includes('The database connection is closing')
) {
await this.#ensureDatabase();
return this.delete({
name,
streamingSessionId,
});
}
});
this.#db.delete(compositeKey);
console.debug('[EventSessionDB] delete');
console.table(Object.fromEntries(this.#db.entries()));
}

/**
Expand All @@ -174,46 +56,15 @@ class EventSessionDB {
name: string;
streamingSessionId: string;
}): Promise<MaybeEvent<P>> {
await this.#ensureDatabase();

const compositeKey = await this.#generateCompositeKey(
streamingSessionId,
name,
);

return new Promise<MaybeEvent<P>>((resolve, reject) => {
try {
const transaction = this.#db.transaction(['events'], 'readonly');
const store = transaction.objectStore('events');
const request = store.get(compositeKey);

request.onsuccess = () => {
if (request.result) {
resolve(request.result as MaybeEvent<P>);
} else {
resolve(undefined);
}
};
console.debug('[EventSessionDB] get');
console.table(Object.fromEntries(this.#db.entries()));

request.onerror = () => {
throw request.error;
};
} catch (error) {
reject(error);
}
}).catch(async error => {
if (
error instanceof DOMException &&
error.message.includes('The database connection is closing')
) {
await this.#ensureDatabase();

return this.get<P>({
name,
streamingSessionId,
});
}
});
return this.#db.get(compositeKey);
}

/**
Expand All @@ -225,40 +76,14 @@ class EventSessionDB {
payload: unknown;
streamingSessionId: string;
}): Promise<void> {
await this.#ensureDatabase();

const compositeKey = await this.#generateCompositeKey(
value.streamingSessionId,
value.name,
);

return new Promise<void>((resolve, reject) => {
try {
const transaction = this.#db.transaction(['events'], 'readwrite');
const store = transaction.objectStore('events');

value.id = compositeKey;

const request = store.put(value);

request.onsuccess = () => resolve();

request.onerror = () => {
throw request.error;
};
} catch (error) {
reject(error);
}
}).catch(async error => {
if (
error instanceof DOMException &&
error.message.includes('The database connection is closing')
) {
await this.#ensureDatabase();

return this.put(value);
}
});
this.#db.set(compositeKey, value);
console.debug('[EventSessionDB] put');
console.table(Object.fromEntries(this.#db.entries()));
}
}

Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3e10cbd

Please sign in to comment.