From 2b73e83b234d8f0ec02be133b035681457f90394 Mon Sep 17 00:00:00 2001 From: Jack Italiano Date: Wed, 12 Jun 2024 14:20:41 -0400 Subject: [PATCH 1/2] db requests ensure db has been created - each db request ensures the db has been created before request. - if takes too long, reject with error - could be better fix, but this gets quick one in for live --- src/utils/bidaraDB.js | 68 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/utils/bidaraDB.js b/src/utils/bidaraDB.js index 3f2bc1c..d4584f2 100644 --- a/src/utils/bidaraDB.js +++ b/src/utils/bidaraDB.js @@ -79,29 +79,65 @@ export async function closeBidaraDB() { await dbUtils.closeDB(BIDARA_DB); } +async function waitForDB() { + if (BIDARA_DB) return; + const maxWaitCount = 10; + + return await new Promise(async (resolve, reject) => { + let waitCount = 0; + while (true) { + if (BIDARA_DB) { + resolve(); + return; + } + + waitCount++; + + if (waitCount > maxWaitCount) { + reject("Database took too long to respond."); + return; + } + + await new Promise((resolveTimeout) => setTimeout(resolveTimeout, 10)); + } + }); +} + export async function getAllThreads() { + await waitForDB(); + const threads = await dbUtils.readAll(BIDARA_DB, CHAT_STORE_NAME, "created_time", true); return threads; } export async function getThreadById(id) { + await waitForDB(); + const thread = await dbUtils.readByKey(BIDARA_DB, CHAT_STORE_NAME, id); return thread; } export async function getActiveThread() { + await waitForDB(); + return await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "active", true); } export async function getMostRecentlyCreatedThread() { + await waitForDB(); + return await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "created_time", false); } export async function getMostRecentlyUpdatedThread() { + await waitForDB(); + return await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "updated_time", true); } export async function getThreadFiles(threadId) { + await waitForDB(); + const files = await dbUtils.readByProperty(BIDARA_DB, FILE_STORE_NAME, "threadId", threadId); if (!files) { @@ -112,11 +148,15 @@ export async function getThreadFiles(threadId) { } export async function getFileById(fileId) { + await waitForDB(); + const file = await dbUtils.readByKey(BIDARA_DB, FILE_STORE_NAME, fileId); return file; } export async function getEmptyThread(emptyLength) { + await waitForDB(); + const emptyThread = await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "length", false); if (emptyThread && emptyThread.length <= emptyLength) { return emptyThread; @@ -126,25 +166,35 @@ export async function getEmptyThread(emptyLength) { } export async function getNameById(id) { + await waitForDB(); + const thread = await getThreadById(id); return thread.name; } export async function getLengthById(id) { + await waitForDB(); + const thread = await getThreadById(id); return thread.length; } export async function getFilteredThreads(thread_filter) { + await waitForDB(); + return await getAllThreads().filter(thread_filter); } async function updateTimeById(id) { + await waitForDB(); + const updated_time = Date.now(); await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "update_time", updated_time) } export async function pushMessageToId(id, message) { + await waitForDB(); + await dbUtils.pushToListProperty(BIDARA_DB, CHAT_STORE_NAME, id, "messages", message,); const length = await getLengthById(id); await setLengthById(id, length + 1); @@ -152,39 +202,57 @@ export async function pushMessageToId(id, message) { } export async function pushFile(file) { + await waitForDB(); + // { index: int, file: b64Data } await dbUtils.write(BIDARA_DB, FILE_STORE_NAME, file); } export async function setThread(thread) { + await waitForDB(); + await dbUtils.write(BIDARA_DB, CHAT_STORE_NAME, thread); } export async function setMessagesById(id, messages) { + await waitForDB(); + await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "messages", messages); } export async function setNameById(id, name) { + await waitForDB(); + await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "name", name); } export async function setLengthById(id, length) { + await waitForDB(); + await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "length", length); } export async function setAsstById(id, asst) { + await waitForDB(); + await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "asst", asst); } export async function setActiveStatusById(id, status) { + await waitForDB(); + if (status) { await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "active", ACTIVE_STATUS); } else { await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "active", INACTIVE_STATUS); } + await waitForDB(); + } export async function deleteThreadById(id) { + await waitForDB(); + await dbUtils.deleteByKey(BIDARA_DB, CHAT_STORE_NAME, id); } From ac1010b7b44605db8cef61cff9e3116d0f296307 Mon Sep 17 00:00:00 2001 From: Jack Italiano Date: Wed, 12 Jun 2024 14:59:26 -0400 Subject: [PATCH 2/2] properly open and close DB on individual requests --- src/App.svelte | 9 -- src/utils/bidaraDB.js | 176 ++++++++++++++++++++++---------------- src/utils/indexDBUtils.js | 19 +++- 3 files changed, 120 insertions(+), 84 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index 366548a..13d64b8 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -3,7 +3,6 @@ import { Navbar, Sidebar, AssistantDeepChat, Login } from './components'; import { ASSISTANT_OPTIONS, DEFAULT_ASSISTANT } from "./assistant"; import { getKeyAndThread, getNewAsst } from './utils/openaiUtils'; - import { createBidaraDB, closeBidaraDB } from "./utils/bidaraDB"; import * as threadUtils from './utils/threadUtils'; import hljs from "highlight.js"; window.hljs = hljs; @@ -48,14 +47,6 @@ loggedIn = true; } - onMount(async () => { - await createBidaraDB(); - }); - - onDestroy(async () => { - await closeBidaraDB(); - }) - async function newThreadAndSwitch() { // If the thread is already "new", stay on it if (activeThread && activeThread.length <= 0) { diff --git a/src/utils/bidaraDB.js b/src/utils/bidaraDB.js index d4584f2..252e4cb 100644 --- a/src/utils/bidaraDB.js +++ b/src/utils/bidaraDB.js @@ -65,80 +65,89 @@ const BIDARA_DB_CONFIG = { ] } -let BIDARA_DB = null; +const DB = BidaraDB(); -export async function createBidaraDB() { - if (BIDARA_DB) { - throw new Error("Bidara DB already instantiated."); - } - - BIDARA_DB = await dbUtils.openDB(BIDARA_DB_CONFIG.name, BIDARA_DB_CONFIG.stores, BIDARA_DB_CONFIG.version); -} - -export async function closeBidaraDB() { - await dbUtils.closeDB(BIDARA_DB); -} - -async function waitForDB() { - if (BIDARA_DB) return; - const maxWaitCount = 10; +function BidaraDB() { + let BIDARA_DB = null; + let created = false; - return await new Promise(async (resolve, reject) => { - let waitCount = 0; - while (true) { - if (BIDARA_DB) { - resolve(); - return; - } + return { + get: async () => { + if (BIDARA_DB) return BIDARA_DB; - waitCount++; - - if (waitCount > maxWaitCount) { - reject("Database took too long to respond."); - return; + if (created) { + BIDARA_DB = await dbUtils.openDB(BIDARA_DB_CONFIG.name, BIDARA_DB_CONFIG.version); + return BIDARA_DB; } - await new Promise((resolveTimeout) => setTimeout(resolveTimeout, 10)); + BIDARA_DB = await dbUtils.createDB(BIDARA_DB_CONFIG.name, BIDARA_DB_CONFIG.stores, BIDARA_DB_CONFIG.version); + created = true; + + return BIDARA_DB; + }, + close: async () => { + await dbUtils.closeDB(BIDARA_DB); + BIDARA_DB = null; } - }); + } } export async function getAllThreads() { - await waitForDB(); + const db = await DB.get(); + + const threads = await dbUtils.readAll(db, CHAT_STORE_NAME, "created_time", true); + + await DB.close(); - const threads = await dbUtils.readAll(BIDARA_DB, CHAT_STORE_NAME, "created_time", true); return threads; } export async function getThreadById(id) { - await waitForDB(); + const db = await DB.get(); + + const thread = await dbUtils.readByKey(db, CHAT_STORE_NAME, id); + + await DB.close(); - const thread = await dbUtils.readByKey(BIDARA_DB, CHAT_STORE_NAME, id); return thread; } export async function getActiveThread() { - await waitForDB(); + const db = await DB.get(); + + const thread = await dbUtils.readFirstByIndex(db, CHAT_STORE_NAME, "active", true); + + await DB.close(); - return await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "active", true); + return thread; } export async function getMostRecentlyCreatedThread() { - await waitForDB(); + const db = await DB.get(); + + const thread = await dbUtils.readFirstByIndex(db, CHAT_STORE_NAME, "created_time", false); + + await DB.close(); - return await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "created_time", false); + return thread; } export async function getMostRecentlyUpdatedThread() { - await waitForDB(); + const db = await DB.get(); + + const thread = await dbUtils.readFirstByIndex(db, CHAT_STORE_NAME, "updated_time", true); - return await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "updated_time", true); + await DB.close(); + + return thread; } export async function getThreadFiles(threadId) { - await waitForDB(); + const db = await DB.get(); + + const files = await dbUtils.readByProperty(db, FILE_STORE_NAME, "threadId", threadId); - const files = await dbUtils.readByProperty(BIDARA_DB, FILE_STORE_NAME, "threadId", threadId); + await DB.close(); if (!files) { return []; @@ -148,16 +157,22 @@ export async function getThreadFiles(threadId) { } export async function getFileById(fileId) { - await waitForDB(); + const db = await DB.get(); + + const file = await dbUtils.readByKey(db, FILE_STORE_NAME, fileId); + + await DB.close(); - const file = await dbUtils.readByKey(BIDARA_DB, FILE_STORE_NAME, fileId); return file; } export async function getEmptyThread(emptyLength) { - await waitForDB(); + const db = await DB.get(); + + const emptyThread = await dbUtils.readFirstByIndex(db, CHAT_STORE_NAME, "length", false); + + await DB.close(); - const emptyThread = await dbUtils.readFirstByIndex(BIDARA_DB, CHAT_STORE_NAME, "length", false); if (emptyThread && emptyThread.length <= emptyLength) { return emptyThread; } @@ -166,93 +181,106 @@ export async function getEmptyThread(emptyLength) { } export async function getNameById(id) { - await waitForDB(); - const thread = await getThreadById(id); return thread.name; } export async function getLengthById(id) { - await waitForDB(); - const thread = await getThreadById(id); return thread.length; } export async function getFilteredThreads(thread_filter) { - await waitForDB(); - return await getAllThreads().filter(thread_filter); } async function updateTimeById(id) { - await waitForDB(); + const db = await DB.get(); const updated_time = Date.now(); - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "update_time", updated_time) + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "update_time", updated_time) + + await DB.close(); } export async function pushMessageToId(id, message) { - await waitForDB(); + const db = await DB.get(); + + await dbUtils.pushToListProperty(db, CHAT_STORE_NAME, id, "messages", message,); - await dbUtils.pushToListProperty(BIDARA_DB, CHAT_STORE_NAME, id, "messages", message,); const length = await getLengthById(id); await setLengthById(id, length + 1); await updateTimeById(id); + + await DB.close(); } export async function pushFile(file) { - await waitForDB(); + const db = await DB.get(); // { index: int, file: b64Data } - await dbUtils.write(BIDARA_DB, FILE_STORE_NAME, file); + await dbUtils.write(db, FILE_STORE_NAME, file); + + await DB.close(); } export async function setThread(thread) { - await waitForDB(); + const db = await DB.get(); + + await dbUtils.write(db, CHAT_STORE_NAME, thread); - await dbUtils.write(BIDARA_DB, CHAT_STORE_NAME, thread); + await DB.close(); } export async function setMessagesById(id, messages) { - await waitForDB(); + const db = await DB.get(); - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "messages", messages); + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "messages", messages); + + await DB.close(); } export async function setNameById(id, name) { - await waitForDB(); + const db = await DB.get(); + + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "name", name); - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "name", name); + await DB.close(); } export async function setLengthById(id, length) { - await waitForDB(); + const db = await DB.get(); + + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "length", length); - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "length", length); + await DB.close(); } export async function setAsstById(id, asst) { - await waitForDB(); + const db = await DB.get(); - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "asst", asst); + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "asst", asst); + + await DB.close(); } export async function setActiveStatusById(id, status) { - await waitForDB(); + const db = await DB.get(); if (status) { - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "active", ACTIVE_STATUS); + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "active", ACTIVE_STATUS); } else { - await dbUtils.updateProperty(BIDARA_DB, CHAT_STORE_NAME, id, "active", INACTIVE_STATUS); + await dbUtils.updateProperty(db, CHAT_STORE_NAME, id, "active", INACTIVE_STATUS); } - await waitForDB(); + await DB.close(); } export async function deleteThreadById(id) { - await waitForDB(); + const db = await DB.get(); + + await dbUtils.deleteByKey(db, CHAT_STORE_NAME, id); - await dbUtils.deleteByKey(BIDARA_DB, CHAT_STORE_NAME, id); + await DB.close(); } diff --git a/src/utils/indexDBUtils.js b/src/utils/indexDBUtils.js index cf0745d..706b79e 100644 --- a/src/utils/indexDBUtils.js +++ b/src/utils/indexDBUtils.js @@ -1,4 +1,4 @@ -export async function openDB(name, stores, version) { +export async function createDB(name, stores, version) { return new Promise((resolve, reject) => { const request = indexedDB.open(name, version) @@ -24,6 +24,23 @@ export async function openDB(name, stores, version) { }); } +export async function openDB(name, version) { + return new Promise((resolve, reject) => { + const request = indexedDB.open(name, version) + + request.onsuccess = (event) => { + const db = event.target.result; + resolve(db); + } + + request.onerror = (event) => { + const error = event.target.error; + reject(error); + return; + } + }); +} + export async function closeDB(db) { if (!db) { throw new Error("Attempting to close DB when DB is null.");