BUGFIX: Don't spin forever if IDB can't be loaded (#1500)

Our IndexDB handling did not have very good error handling. It wasn't
reporting the actual errors that occured, nor was it using actual Error
objects. In some cases it also had overly convoluted Promise use, and it
didn't need to be .tsx either.

The biggest issue was that if any problem occured during the main
load(), this would end up as an unhandled rejection and so it would only
be logged to the console. This extends the previous catch to also cover
this, so that the recovery screen is activated.
This commit is contained in:
David Walker 2024-07-19 19:27:04 -07:00 committed by GitHub
parent b73816f9db
commit 4502fd443e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 24 additions and 31 deletions

@ -19,14 +19,14 @@ function getDB(): Promise<IDBObjectStore> {
db.createObjectStore("savestring");
};
indexedDbRequest.onerror = function (this: IDBRequest<IDBDatabase>, ev: Event) {
reject(`Failed to get IDB ${ev}`);
indexedDbRequest.onerror = function (this: IDBRequest<IDBDatabase>) {
reject(new Error("Failed to get IDB", { cause: this.error }));
};
indexedDbRequest.onsuccess = function (this: IDBRequest<IDBDatabase>) {
const db = this.result;
if (!db) {
reject("database loading result was undefined");
reject(new Error("database loading result was undefined"));
return;
}
resolve(db.transaction(["savestring"], "readwrite").objectStore("savestring"));
@ -35,21 +35,17 @@ function getDB(): Promise<IDBObjectStore> {
}
export function load(): Promise<SaveData> {
return new Promise((resolve, reject) => {
getDB()
.then((db) => {
return new Promise<SaveData>((resolve, reject) => {
const request: IDBRequest<SaveData> = db.get("save");
request.onerror = function (this: IDBRequest<SaveData>, ev: Event) {
reject("Error in Database request to get save data: " + ev);
};
return getDB().then((db) => {
return new Promise<SaveData>((resolve, reject) => {
const request: IDBRequest<SaveData> = db.get("save");
request.onerror = function (this: IDBRequest<SaveData>) {
reject(new Error("Error in Database request to get save data", { cause: this.error }));
};
request.onsuccess = function (this: IDBRequest<SaveData>) {
resolve(this.result);
};
}).then((saveData) => resolve(saveData));
})
.catch((r) => reject(r));
request.onsuccess = function (this: IDBRequest<SaveData>) {
resolve(this.result);
};
});
});
}
@ -59,8 +55,8 @@ export function save(saveData: SaveData): Promise<void> {
// We'll save to IndexedDB
const request = db.put(saveData, "save");
request.onerror = function (e) {
reject("Error saving game to IndexedDB: " + e);
request.onerror = function (this: IDBRequest<IDBValidKey>) {
reject(new Error("Error saving game to IndexedDB", { cause: this.error }));
};
request.onsuccess = () => resolve();

@ -32,21 +32,18 @@ export function LoadingScreen(): React.ReactElement {
});
useEffect(() => {
load().then(async (saveData) => {
try {
await initSwc();
await Engine.load(saveData);
} catch (error) {
load()
.then((saveData) => Promise.all([initSwc(), Engine.load(saveData)]))
.then(() => {
pushGameReady();
setLoaded(true);
})
.catch(async (error) => {
console.error(error);
ActivateRecoveryMode(error);
await Engine.load("");
setLoaded(true);
return;
}
pushGameReady();
setLoaded(true);
});
});
}, []);
return loaded ? (

@ -29,7 +29,7 @@ export function DeleteGameButton({ color = "primary" }: IProps): React.ReactElem
pushDisableRestore();
setTimeout(() => location.reload(), 1000);
})
.catch((r) => console.error(`Could not delete game: ${r}`));
.catch((r) => console.error("Could not delete game: %o", r));
}}
open={modalOpened}
onClose={() => setModalOpened(false)}