You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tobspr_shapez.io/src/js/platform/browser/storage_indexed_db.js

155 lines
5.1 KiB

import { FILE_NOT_FOUND, StorageInterface } from "../storage";
import { createLogger } from "../../core/logging";
const logger = createLogger("storage/browserIDB");
const LOCAL_STORAGE_UNAVAILABLE = "local-storage-unavailable";
const LOCAL_STORAGE_NO_WRITE_PERMISSION = "local-storage-no-write-permission";
let randomDelay = () => 0;
if (G_IS_DEV) {
// Random delay for testing
// randomDelay = () => 500;
}
export class StorageImplBrowserIndexedDB extends StorageInterface {
constructor(app) {
super(app);
this.currentBusyFilename = false;
/** @type {IDBDatabase} */
this.database = null;
}
initialize() {
logger.log("Using indexed DB storage");
return new Promise((resolve, reject) => {
const request = window.indexedDB.open("app_storage", 10);
request.onerror = event => {
logger.error("IDB error:", event);
alert(
"Sorry, it seems your browser has blocked the access to the storage system. This might be the case if you are browsing in private mode for example. I recommend to use google chrome or disable private browsing."
);
reject("Indexed DB access error");
};
// @ts-ignore
request.onsuccess = event => resolve(event.target.result);
request.onupgradeneeded = /** @type {IDBVersionChangeEvent} */ event => {
/** @type {IDBDatabase} */
// @ts-ignore
const database = event.target.result;
const objectStore = database.createObjectStore("files", {
keyPath: "filename",
});
objectStore.createIndex("filename", "filename", { unique: true });
objectStore.transaction.onerror = event => {
logger.error("IDB transaction error:", event);
reject("Indexed DB transaction error during migration, check console output.");
};
objectStore.transaction.oncomplete = event => {
logger.log("Object store completely initialized");
resolve(database);
};
};
}).then(database => {
this.database = database;
});
}
writeFileAsync(filename, contents) {
if (this.currentBusyFilename === filename) {
logger.warn("Attempt to write", filename, "while write process is not finished!");
}
if (!this.database) {
return Promise.reject("Storage not ready");
}
this.currentBusyFilename = filename;
const transaction = this.database.transaction(["files"], "readwrite");
return new Promise((resolve, reject) => {
transaction.oncomplete = () => {
this.currentBusyFilename = null;
resolve();
};
transaction.onerror = error => {
this.currentBusyFilename = null;
logger.error("Error while writing", filename, ":", error);
reject(error);
};
const store = transaction.objectStore("files");
store.put({
filename,
contents,
});
});
}
readFileAsync(filename) {
if (!this.database) {
return Promise.reject("Storage not ready");
}
this.currentBusyFilename = filename;
const transaction = this.database.transaction(["files"], "readonly");
return new Promise((resolve, reject) => {
const store = transaction.objectStore("files");
const request = store.get(filename);
request.onsuccess = event => {
this.currentBusyFilename = null;
if (!request.result) {
reject(FILE_NOT_FOUND);
return;
}
resolve(request.result.contents);
};
request.onerror = error => {
this.currentBusyFilename = null;
logger.error("Error while reading", filename, ":", error);
reject(error);
};
});
}
deleteFileAsync(filename) {
if (this.currentBusyFilename === filename) {
logger.warn("Attempt to delete", filename, "while write progres on it is ongoing!");
}
if (!this.database) {
return Promise.reject("Storage not ready");
}
this.currentBusyFilename = filename;
const transaction = this.database.transaction(["files"], "readwrite");
return new Promise((resolve, reject) => {
transaction.oncomplete = () => {
this.currentBusyFilename = null;
resolve();
};
transaction.onerror = error => {
this.currentBusyFilename = null;
logger.error("Error while deleting", filename, ":", error);
reject(error);
};
const store = transaction.objectStore("files");
store.delete(filename);
});
}
}