Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support IndexedDB base URL storage #677

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
38 changes: 23 additions & 15 deletions lib/browser/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
import DetailedError from '../error.js'
import { enableDebugLog } from '../logger.js'
import NoopUrlStorage from '../noopUrlStorage.js'
import BaseUpload from '../upload.js'
import NoopUrlStorage from '../noopUrlStorage.js'
import { enableDebugLog } from '../logger.js'
import DetailedError from '../error.js'

import { canStoreURLs, WebStorageUrlStorage } from './urlStorage.js'
import {IndexedDBUrlStorage,canStoreURLsInIndexedDB} from './urlStorageIndexedDB.js'
import DefaultHttpStack from './httpStack.js'
import FileReader from './fileReader.js'
import fingerprint from './fileSignature.js'
import DefaultHttpStack from './httpStack.js'
import { canStoreURLsInIndexDB, WebIndexDBStorageUrlStorage } from './urlStorageIndexDB.js'
import { canStoreURLsInLocalStorage, WebLocalStorageUrlStorage } from './urlStorageLocalStorage.js'

const getUrlStorage=(useIndexedDBForUrlStorage)=>{
if(useIndexedDBForUrlStorage && canStoreURLsInIndexedDB){
return new IndexedDBUrlStorage()
}
return canStoreURLs ? new WebStorageUrlStorage() : new NoopUrlStorage()
}

const defaultOptions = {
...BaseUpload.defaultOptions,
httpStack: new DefaultHttpStack(),
fileReader: new FileReader(),
urlStorage:canStoreURLsInIndexDB ? new WebIndexDBStorageUrlStorage() : canStoreURLsInLocalStorage ? new WebLocalStorageUrlStorage() : new NoopUrlStorage(),
urlStorage: canStoreURLs ? new WebStorageUrlStorage() : new NoopUrlStorage(),
fingerprint,
}

class Upload extends BaseUpload {
constructor(file = null, options = {}) {
options = { ...defaultOptions, ...options }
options = { ...defaultOptions, ...options, urlStorage: getUrlStorage(options.useIndexedDBForUrlStorage) }
super(file, options)
}

static terminate(url, options = {}) {
options = { ...defaultOptions, ...options }
options = { ...defaultOptions, ...options, urlStorage: getUrlStorage(options.useIndexedDBForUrlStorage) }
return BaseUpload.terminate(url, options)
}
}
@@ -35,12 +43,12 @@ const isSupported =
typeof Blob.prototype.slice === 'function'

export {
canStoreURLsInIndexDB,
canStoreURLsInLocalStorage,
DefaultHttpStack,
Upload,
canStoreURLs,
canStoreURLsInIndexedDB,
defaultOptions,
DetailedError,
enableDebugLog,
isSupported,
Upload
enableDebugLog,
DefaultHttpStack,
DetailedError,
}
Original file line number Diff line number Diff line change
@@ -22,9 +22,9 @@ try {
}
}

export const canStoreURLsInLocalStorage = hasStorage
export const canStoreURLs = hasStorage

export class WebLocalStorageUrlStorage {
export class WebStorageUrlStorage {
findAllUploads() {
const results = this._findEntries('tus::')
return Promise.resolve(results)
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const isSupportIndexDB = () => {
return 'indexedDB' in window && !/iPad|iPhone|iPod/.test(navigator.platform);
const isSupportIndexedDB = () => {
return 'indexedDB' in window

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some reason not to use globalThis rather than window here?

};

let hasStorage = false;
try {
hasStorage = isSupportIndexDB();
hasStorage = isSupportIndexedDB();
} catch (e) {
if (e.code === e.SECURITY_ERR || e.code === e.QUOTA_EXCEEDED_ERR) {
hasStorage = false;
@@ -12,9 +13,9 @@ const isSupportIndexDB = () => {
}
}

export const canStoreURLsInIndexDB = hasStorage;
export const canStoreURLsInIndexedDB = hasStorage;

export class WebIndexDBStorageUrlStorage {
export class IndexedDBUrlStorage {
constructor() {
this.dbName = 'tusUrlStorage';
this.storeName = 'upload';
@@ -23,19 +24,17 @@ const isSupportIndexDB = () => {

openDatabase() {
return new Promise((resolve, reject) => {
const openRequest = indexedDB.open(this.dbName);
openRequest.onupgradeneeded = function () {
const db = openRequest.result;
if (!db.objectStoreNames.contains(this.storeName)) {
db.createObjectStore(this.storeName, {keyPath: 'urlStorageKey'});
}
}.bind(this);
openRequest.onsuccess = function () {
resolve(openRequest.result);
};
openRequest.onerror = reject;
const openRequest = indexedDB.open(this.dbName);
openRequest.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(this.storeName)) {
db.createObjectStore(this.storeName, {keyPath: 'urlStorageKey'});
}
};
openRequest.onsuccess = () => resolve(openRequest.result);
openRequest.onerror = (event) => reject(event);
});
}
}

async _getAllUploadWithKeys() {
try {
@@ -52,7 +51,6 @@ const isSupportIndexDB = () => {
urlStorageKey: result.urlStorageKey,
}));
} catch (error) {
console.error('Error getting all uploads with keys:', error);
throw error;
}
}
@@ -62,7 +60,6 @@ const isSupportIndexDB = () => {
const results = await this._getAllUploadWithKeys();
return results;
} catch (error) {
console.error('Error finding all uploads:', error);
throw error;
}
}
@@ -76,7 +73,6 @@ const isSupportIndexDB = () => {

return results ? [results] : [];
} catch (error) {
console.error('Error finding uploads by fingerprint:', error);
throw error;
}
}
@@ -92,7 +88,6 @@ const isSupportIndexDB = () => {
request.onerror = reject;
});
} catch (error) {
console.error('Error removing upload:', error);
throw error;
}
}
@@ -111,7 +106,6 @@ const isSupportIndexDB = () => {
});
return key;
} catch (error) {
console.error('Error adding upload:', error);
throw error;
}
}
2 changes: 1 addition & 1 deletion lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ interface UploadOptions {
removeFingerprintOnSuccess?: boolean
uploadLengthDeferred?: boolean
uploadDataDuringCreation?: boolean

useIndexedDBForUrlStorage?: boolean
urlStorage?: UrlStorage
fileReader?: FileReader
httpStack?: HttpStack