diff --git a/web/apps/photos/src/services/download/index.ts b/web/apps/photos/src/services/download/index.ts index 79fff4da9..301788739 100644 --- a/web/apps/photos/src/services/download/index.ts +++ b/web/apps/photos/src/services/download/index.ts @@ -13,7 +13,6 @@ import { generateStreamFromArrayBuffer, getRenderableFileURL, } from "utils/file"; -import { isInternalUser } from "utils/user"; import { PhotosDownloadClient } from "./clients/photos"; import { PublicAlbumsDownloadClient } from "./clients/publicAlbums"; @@ -56,9 +55,15 @@ export interface DownloadClient { class DownloadManagerImpl { private ready: boolean = false; private downloadClient: DownloadClient; + /** Local cache for thumbnails. Might not be available. */ private thumbnailCache?: EnteCache; + /** + * Local cache for the files themselves. + * + * Only available when we're running in the desktop app. + */ // disk cache is only available on electron - private diskFileCache?: EnteCache; + private fileCache?: EnteCache; private cryptoWorker: Remote; private fileObjectURLPromises = new Map>(); @@ -74,21 +79,27 @@ class DownloadManagerImpl { tokens?: { token: string; passwordToken?: string } | { token: string }, timeout?: number, ) { - try { - if (this.ready) { - log.info("DownloadManager already initialized"); - return; - } - this.downloadClient = createDownloadClient(app, tokens, timeout); - this.thumbnailCache = await openThumbnailCache(); - this.diskFileCache = isElectron() && (await openDiskFileCache()); - this.cryptoWorker = await ComlinkCryptoWorker.getInstance(); - this.ready = true; - eventBus.on(Events.LOGOUT, this.logoutHandler.bind(this), this); - } catch (e) { - log.error("DownloadManager init failed", e); - throw e; + if (this.ready) { + log.info("DownloadManager already initialized"); + return; } + this.downloadClient = createDownloadClient(app, tokens, timeout); + try { + this.thumbnailCache = await openCache("thumbs"); + } catch (e) { + log.error( + "Failed to open thumbnail cache, will continue without it", + e, + ); + } + try { + if (isElectron()) this.fileCache = await openCache("files"); + } catch (e) { + log.error("Failed to open file cache, will continue without it", e); + } + this.cryptoWorker = await ComlinkCryptoWorker.getInstance(); + this.ready = true; + eventBus.on(Events.LOGOUT, this.logoutHandler.bind(this), this); } private async logoutHandler() { @@ -139,11 +150,11 @@ class DownloadManagerImpl { } } private async getCachedFile(file: EnteFile): Promise { + const fileCache = this.fileCache; + if (!fileCache) return null; + try { - if (!this.diskFileCache) { - return null; - } - const cacheResp: Response = await this.diskFileCache?.match( + const cacheResp: Response = await fileCache.match( file.id.toString(), ); return cacheResp?.clone(); @@ -312,8 +323,8 @@ class DownloadManagerImpl { onDownloadProgress, ), ); - if (this.diskFileCache) { - this.diskFileCache + if (this.fileCache) { + this.fileCache .put(file.id.toString(), encrypted.clone()) .catch((e) => { log.error("file cache put failed", e); @@ -345,8 +356,8 @@ class DownloadManagerImpl { let resp: Response = await this.getCachedFile(file); if (!resp) { resp = await this.downloadClient.downloadFileStream(file); - if (this.diskFileCache) { - this.diskFileCache + if (this.fileCache) { + this.fileCache .put(file.id.toString(), resp.clone()) .catch((e) => { log.error("file cache put failed", e); @@ -511,35 +522,6 @@ const DownloadManager = new DownloadManagerImpl(); export default DownloadManager; -async function openThumbnailCache() { - try { - return await openCache("thumbs"); - } catch (e) { - log.error("Failed to open thumbnail cache", e); - if (isInternalUser()) { - throw e; - } else { - return null; - } - } -} - -async function openDiskFileCache() { - try { - if (!isElectron()) { - throw Error(CustomError.NOT_AVAILABLE_ON_WEB); - } - return await openCache("files"); - } catch (e) { - log.error("Failed to open file cache", e); - if (isInternalUser()) { - throw e; - } else { - return null; - } - } -} - function createDownloadClient( app: APPS, tokens?: { token: string; passwordToken?: string } | { token: string }, diff --git a/web/apps/photos/src/utils/file/index.ts b/web/apps/photos/src/utils/file/index.ts index ad93dcb5a..089c5f40d 100644 --- a/web/apps/photos/src/utils/file/index.ts +++ b/web/apps/photos/src/utils/file/index.ts @@ -440,7 +440,7 @@ export async function getRenderableImage(fileName: string, imageBlob: Blob) { } if (!isElectron()) { - throw Error(CustomError.NOT_AVAILABLE_ON_WEB); + throw new Error("not available on web"); } log.info( `RawConverter called for ${fileName}-${convertBytesToHumanReadable( diff --git a/web/packages/next/cache.ts b/web/packages/next/cache.ts index 33cdee23d..4aba7ea36 100644 --- a/web/packages/next/cache.ts +++ b/web/packages/next/cache.ts @@ -1,3 +1,5 @@ +import isElectron from "is-electron"; + const cacheNames = [ "thumbs", "face-crops", @@ -77,7 +79,7 @@ export interface EnteCache { * across namespaces. */ export const openCache = async (name: CacheName) => - globalThis.electron ? openOPFSCacheWeb(name) : openWebCache(name); + isElectron() ? openOPFSCacheWeb(name) : openWebCache(name); /** An implementation of {@link EnteCache} using Web Cache APIs */ const openWebCache = async (name: CacheName) => { @@ -103,7 +105,7 @@ const openOPFSCacheWeb = async (name: CacheName) => { // this code will only run in our Electron app (which'll use Chromium as the // renderer). // - // So for our purpose, this can serve as the docs for what's available: + // So for our purpose, these can serve as the doc for what's available: // https://web.dev/articles/origin-private-file-system const cache = await caches.open(name); @@ -175,7 +177,7 @@ export async function cached( * Meant for use during logout, to reset the state of the user's account. */ export const clearCaches = async () => - globalThis.electron ? clearOPFSCaches() : clearWebCaches(); + isElectron() ? clearOPFSCaches() : clearWebCaches(); export const clearWebCaches = async () => { await Promise.all(cacheNames.map((name) => caches.delete(name))); diff --git a/web/packages/shared/error/index.ts b/web/packages/shared/error/index.ts index 6ed4c7486..744b14c66 100644 --- a/web/packages/shared/error/index.ts +++ b/web/packages/shared/error/index.ts @@ -74,7 +74,6 @@ export const CustomError = { EXIF_DATA_NOT_FOUND: "exif data not found", SELECT_FOLDER_ABORTED: "select folder aborted", NON_MEDIA_FILE: "non media file", - NOT_AVAILABLE_ON_WEB: "not available on web", UNSUPPORTED_RAW_FORMAT: "unsupported raw format", NON_PREVIEWABLE_FILE: "non previewable file", PROCESSING_FAILED: "processing failed",