diff --git a/app/src/App.svelte b/app/src/App.svelte index 448f0fe..d2a57d4 100644 --- a/app/src/App.svelte +++ b/app/src/App.svelte @@ -2,13 +2,14 @@ import { Router, Route } from 'svelte-routing'; import { onMount } from 'svelte'; import TopBar from './components/TopBar.svelte'; - import { connect } from './lib/socket'; + import { connect } from '$lib/socket'; import Controller from './routes/Controller.svelte'; - import FileCache from './lib/cache'; - import { socketLocation } from './lib/location'; + import FileService from '$lib/services/file-service'; + import { socketLocation } from '$lib/location'; import Settings from './routes/Settings.svelte'; - import { jointNames, model } from './lib/store'; - import { loadModelAsync } from './lib/modelLoader'; + import { jointNames, model } from '$lib/store'; + import { loadModelAsync } from '$lib/utilities'; + import type { Result } from '$lib/utilities/result'; export let url = window.location.pathname onMount(async () => { @@ -23,16 +24,10 @@ const { fetch: originalFetch } = window; window.fetch = async (...args) => { const [resource, config] = args; - await FileCache.openDatabase(); - let file: BodyInit | Uint8Array | undefined | null; - try { - file = await FileCache.getFile(resource.toString()); - } catch (error) { - console.log(error); - } - - return file - ? new Response(file) + let file: Result; + file = await FileService.getFile(resource.toString()); + return file.isOk() + ? new Response(file.inner) : originalFetch(resource, config) }; } diff --git a/app/src/components/Views/Model.svelte b/app/src/components/Views/Model.svelte index bc7ca07..a3b0097 100644 --- a/app/src/components/Views/Model.svelte +++ b/app/src/components/Views/Model.svelte @@ -7,7 +7,7 @@ import uzip from 'uzip'; import { model, outControllerData } from '$lib/store'; import { ForwardKinematics } from '$lib/kinematic'; import location from '$lib/location'; -import FileCache from '$lib/cache'; +import FileService from '$lib/services/file-service'; import SceneBuilder from '$lib/sceneBuilder'; let sceneManager:SceneBuilder @@ -59,11 +59,11 @@ const cacheModelFiles = async () => { let data = await fetch("/stl.zip").then(data => data.arrayBuffer()) var files = uzip.parse(data); - await FileCache.openDatabase() + await FileService.openDatabase() for(const [path, data] of Object.entries(files) as [path:string, data:Uint8Array][]){ const url = new URL(path, window.location.href) - FileCache.saveFile(url.toString(), data) + FileService.saveFile(url.toString(), data) } } diff --git a/app/src/lib/cache.ts b/app/src/lib/cache.ts deleted file mode 100644 index e298621..0000000 --- a/app/src/lib/cache.ts +++ /dev/null @@ -1,102 +0,0 @@ -class FileCache { - private request: IDBOpenDBRequest; - private db: IDBDatabase | null = null; - private store: IDBObjectStore | null = null; - - dbName = 'fileStorageDB'; - dbVersion = 1; - storeName = 'files'; - constructor() { - this.request = indexedDB.open(this.dbName, this.dbVersion); - this.request.onerror = (event) => { - console.error("An error occurred with IndexedDB", event); - }; - - this.request.onupgradeneeded = () => { - this.db = this.request.result; - this.store = this.db.createObjectStore(this.storeName); - }; - - this.request.onsuccess = () => { - this.db = this.request.result; - const transaction = this.db.transaction(this.storeName, "readwrite"); - this.store = transaction.objectStore(this.storeName); - } - } - - public isOpen(): boolean { - return this.db !== null; - } - - public async saveFile(key:string, file: Uint8Array): Promise { - return new Promise((resolve, reject) => { - if(!this.db) { - reject("Database not open") - return; - } - const transaction = this.db.transaction(this.storeName, "readwrite"); - const store = transaction.objectStore(this.storeName); - const request = store.put(file, key); - if(!request) { - reject("Request not created") - return - } - request.onsuccess = () => { - resolve(request.result); - }; - request.onerror = () => { - reject(request.error); - }; - }); - } - - public async getFile(key:string): Promise { - return new Promise((resolve, reject) => { - if(!key) { - reject("Key was not defined") - return; - } - if(!this.db) { - reject("Database not open") - return; - } - const transaction = this.db.transaction(this.storeName, "readwrite"); - const store = transaction.objectStore(this.storeName); - - const request = store.get(key); - if(!request) { - reject("Request not created") - return - } - request.onsuccess = () => { - resolve(request.result); - }; - request.onerror = () => { - reject(request.error); - }; - }); - } - - public async openDatabase(): Promise { - return new Promise((resolve, reject) => { - const request = indexedDB.open(this.dbName, this.dbVersion); - - request.onerror = (event) => { - reject('Error opening database'); - }; - - request.onsuccess = (event) => { - const db = event.target?.result; - this.db = db; - resolve(db); - }; - - request.onupgradeneeded = (event) => { - this.db = event.target?.result; - this.db?.createObjectStore('files', { autoIncrement: true }); - }; - }); - } -} - -export default new FileCache(); \ No newline at end of file diff --git a/app/src/lib/services/file-service.ts b/app/src/lib/services/file-service.ts new file mode 100644 index 0000000..4cf1cfa --- /dev/null +++ b/app/src/lib/services/file-service.ts @@ -0,0 +1,72 @@ +import { Result } from '$lib/utilities/result'; + +class FileService { + private dbName = 'fileStorageDB'; + private dbVersion = 1; + private storeName = 'files'; + private dbPromise: Promise>; + + constructor() { + this.dbPromise = this.openDatabase(); + } + + private async openDatabase(): Promise> { + return new Promise((resolve) => { + const request = indexedDB.open(this.dbName, this.dbVersion); + + request.onerror = () => resolve(Result.err("Error opening database")); + + request.onsuccess = () => resolve(Result.ok(request.result)); + + request.onupgradeneeded = (event) => { + const db = request.result; + if (!db.objectStoreNames.contains(this.storeName)) { + db.createObjectStore(this.storeName); + } + }; + }); + } + + private async getStore(mode: IDBTransactionMode): Promise> { + const dbResult = await this.dbPromise; + if (dbResult.isErr()) { + return Result.err("Database not initialized properly"); + } + const db = dbResult.inner; + const transaction = db.transaction(this.storeName, mode); + return Result.ok(transaction.objectStore(this.storeName)); + } + + public async saveFile(key: string, file: Uint8Array): Promise> { + const storeResult = await this.getStore("readwrite"); + if (storeResult.isErr()) { + return Result.err("Failed to access object store for writing"); + } + const store = storeResult.inner; + + return new Promise((resolve) => { + const request = store.put(file, key); + request.onsuccess = () => resolve(Result.ok(request.result)); + request.onerror = () => resolve(Result.err("Failed to save file")); + }); + } + + public async getFile(key: string): Promise> { + const storeResult = await this.getStore("readonly"); + if (storeResult.isErr()) { + return Result.err("Failed to access object store for reading"); + } + const store = storeResult.inner; + + return new Promise((resolve) => { + const request = store.get(key); + + request.onsuccess = () => + resolve(request.result ? Result.ok(request.result) : Result.err("File content not found")) + request.onerror = () => + resolve(Result.err("Failed to retrieve file")); + }); + } +} + +export default new FileService(); \ No newline at end of file diff --git a/app/src/lib/services/index.ts b/app/src/lib/services/index.ts new file mode 100644 index 0000000..6bd4139 --- /dev/null +++ b/app/src/lib/services/index.ts @@ -0,0 +1 @@ +export * from './file-service'