Fix session replica behaviour (merge with session)

The harder-to-refactor parts are the places where exists/username/token
are called within a React component. However, `resetAndRedirect` and
`store` are already called from async contexts, so adding an `await`
is simple.

This thus merges the logic, keeping localStorage for the components to
call, but making sure reset/store behaviour works correctly for the
replica.
This commit is contained in:
nimbleghost 2023-06-13 14:00:51 +02:00
parent 4e44b034bd
commit 8ccfa5c3fb
15 changed files with 43 additions and 78 deletions

View file

@ -367,7 +367,7 @@ class AccountApi {
} catch (e) {
console.log(`[AccountApi] Error fetching account`, e);
if (e instanceof UnauthorizedError) {
session.resetAndRedirect(routes.login);
await session.resetAndRedirect(routes.login);
}
return undefined;
}

View file

@ -1,29 +1,36 @@
import sessionReplica from "./SessionReplica";
import Dexie from "dexie";
/**
* Manages the logged-in user's session and access token.
* The session replica is stored in IndexedDB so that the service worker can access it.
*/
class Session {
constructor(replica) {
this.replica = replica;
constructor() {
const db = new Dexie("session-replica");
db.version(1).stores({
kv: "&key",
});
this.db = db;
}
store(username, token) {
async store(username, token) {
await this.db.kv.bulkPut([
{ key: "user", value: username },
{ key: "token", value: token },
]);
localStorage.setItem("user", username);
localStorage.setItem("token", token);
this.replica.store(username, token);
}
reset() {
async resetAndRedirect(url) {
await this.db.delete();
localStorage.removeItem("user");
localStorage.removeItem("token");
this.replica.reset();
window.location.href = url;
}
resetAndRedirect(url) {
this.reset();
window.location.href = url;
async usernameAsync() {
return (await this.db.kv.get({ key: "user" }))?.value;
}
exists() {
@ -39,5 +46,5 @@ class Session {
}
}
const session = new Session(sessionReplica);
const session = new Session();
export default session;

View file

@ -1,41 +0,0 @@
import Dexie from "dexie";
/**
* Replica of the session in IndexedDB. This is used by the service
* worker to access the session. This is a bit of a hack.
*/
class SessionReplica {
constructor() {
const db = new Dexie("session-replica");
db.version(1).stores({
kv: "&key",
});
this.db = db;
}
async store(username, token) {
try {
await this.db.kv.bulkPut([
{ key: "user", value: username },
{ key: "token", value: token },
]);
} catch (e) {
console.error("[Session] Error replicating session to IndexedDB", e);
}
}
async reset() {
try {
await this.db.delete();
} catch (e) {
console.error("[Session] Error resetting session on IndexedDB", e);
}
}
async username() {
return (await this.db.kv.get({ key: "user" }))?.value;
}
}
const sessionReplica = new SessionReplica();
export default sessionReplica;

View file

@ -1,6 +1,5 @@
import Dexie from "dexie";
import session from "./Session";
import sessionReplica from "./SessionReplica";
// Uses Dexie.js
// https://dexie.org/docs/API-Reference#quick-reference
@ -23,7 +22,7 @@ const createDatabase = (username) => {
};
export const dbAsync = async () => {
const username = await sessionReplica.username();
const username = await session.usernameAsync();
return createDatabase(username);
};