Skip to content

Commit

Permalink
kiosk: store built js in indexeddb, not local storage
Browse files Browse the repository at this point in the history
  • Loading branch information
eanders-ms committed Oct 22, 2023
1 parent 2e524af commit fd346f1
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 39 deletions.
1 change: 1 addition & 0 deletions kiosk/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kiosk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@types/node": "^16.11.33",
"howler": "^2.2.3",
"html5-qrcode": "^2.2.6",
"idb": "^7.1.1",
"nanoid": "^4.0.2",
"qrcode.react": "^3.1.0",
"react-scripts": "5.0.1",
Expand Down
28 changes: 21 additions & 7 deletions kiosk/src/Components/PlayingGame.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useContext, useMemo } from "react";
import { useContext, useEffect, useMemo, useState } from "react";
import { AppStateContext } from "../State/AppStateContext";
import { escapeGame } from "../Transforms/escapeGame";
import { playSoundEffect } from "../Services/SoundEffectService";
import { useOnControlPress } from "../Hooks";
import { stringifyQueryString } from "../Utils";
import * as GamepadManager from "../Services/GamepadManager";
import * as Storage from "../Services/LocalStorage";
import * as IndexedDb from "../Services/IndexedDb";
import configData from "../config.json";

export default function PlayingGame() {
Expand All @@ -23,9 +23,23 @@ export default function PlayingGame() {
GamepadManager.GamepadControl.MenuButton
);

const playUrl = useMemo(() => {
const [fetchingBuiltJsInfo, setFetchingBuiltJsInfo] = useState(true);
const [builtJsInfo, setBuiltJsInfo] = useState<
pxtc.BuiltSimJsInfo | undefined
>(undefined);

useEffect(() => {
if (gameId) {
const builtGame = Storage.getBuiltJsInfo(gameId);
// Try to fetch the built game from local storage.
IndexedDb.getBuiltJsInfoAsync(gameId).then(builtGame => {
setBuiltJsInfo(builtGame);
setFetchingBuiltJsInfo(false);
});
}
}, [gameId]);

const playUrl = useMemo(() => {
if (gameId && !fetchingBuiltJsInfo) {
return stringifyQueryString(configData.PlayUrlRoot, {
id: gameId,
// TODO: Show sim buttons on mobile & touch devices.
Expand All @@ -37,13 +51,13 @@ export default function PlayingGame() {
// If we have the built game cached, we will send it to the
// simulator once it loads. The `server` flag inhibits the
// simulator from trying to build it.
server: builtGame ? 1 : undefined,
server: builtJsInfo ? 1 : undefined,
// If we don't have the built game cached, tell the simulator to
// send it to us once it's built and we'll cache it.
sendBuilt: builtGame ? undefined : 1,
sendBuilt: builtJsInfo ? undefined : 1,
});
}
}, [gameId]);
}, [gameId, fetchingBuiltJsInfo]);

return (
<iframe
Expand Down
90 changes: 90 additions & 0 deletions kiosk/src/Services/IndexedDb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { openDB, IDBPDatabase } from "idb";

class KioskDb {
db: IDBPDatabase | undefined;

public async initializeAsync() {
if (this.db) return;
this.db = await openDB("kiosk", 1, {
upgrade(db) {
db.createObjectStore("builtjs");
},
});
}

private async getAsync<T>(storeName: string, key: string): Promise<T | undefined> {
if (!this.db) {
throw new Error("IndexedDb not initialized.");
}
try {
return await this.db.get(storeName, key);
} catch (e) {
console.error(e);
}
}

private async setAsync<T>(storeName: string, key: string, value: T): Promise<void> {
if (!this.db) {
throw new Error("IndexedDb not initialized.");
}
try {
await this.db.put(storeName, value, key);
} catch (e) {
console.error(e);
}
}

private async deleteAsync(storeName: string, key: string): Promise<void> {
if (!this.db) {
throw new Error("IndexedDb not initialized.");
}
try {
await this.db.delete(storeName, key);
} catch (e) {
console.error(e);
}
}

public async getBuiltJsInfoAsync(
gameId: string
): Promise<pxtc.BuiltSimJsInfo | undefined> {
const ver = pxt.appTarget?.versions?.target;
if (!ver) return undefined;
const key = `${ver}:${gameId}`;
const rec = await this.getAsync<pxtc.BuiltSimJsInfo>("builtjs", key);
return rec;
}

public async setBuiltJsInfoAsync(
gameId: string,
info: pxtc.BuiltSimJsInfo
): Promise<void> {
const ver = pxt.appTarget?.versions?.target;
if (!ver) return;
if (/^S/.test(gameId)) return; // skip persistent-share games for now (need to get their actual gameId and use that as the key)
const key = `${ver}:${gameId}`;
await this.setAsync("builtjs", key, info);
}
}

const db = new KioskDb();

let initializeAsync = async () => {
initializeAsync = async () => {};
await db.initializeAsync();
};

export async function getBuiltJsInfoAsync(
gameId: string
): Promise<pxtc.BuiltSimJsInfo | undefined> {
await initializeAsync();
return await db.getBuiltJsInfoAsync(gameId);
}

export async function setBuiltJsInfoAsync(
gameId: string,
info: pxtc.BuiltSimJsInfo
): Promise<void> {
await initializeAsync();
await db.setBuiltJsInfoAsync(gameId, info);
}
25 changes: 0 additions & 25 deletions kiosk/src/Services/LocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,29 +117,6 @@ function clearKioskCode() {
delValue(Constants.legacy_kioskCodeExpirationStorageKey);
}

function getBuiltJsInfo(gameId: string): ts.pxtc.BuiltSimJsInfo | undefined {
const ver = pxt.appTarget?.versions?.target;
if (!ver) return undefined;
const key = `kiosk/builtjs:${ver}:${gameId}`;
const rec = getJsonValue<ts.pxtc.BuiltSimJsInfo>(key);
return rec;
}

function setBuiltJsInfo(gameId: string, builtJs: ts.pxtc.BuiltSimJsInfo) {
// Need to switch to indexdb. We're hitting local storage size limit with just a few games.
return;
/*
try {
const ver = pxt.appTarget?.versions?.target;
if (!ver) return;
const key = `kiosk/builtjs:${ver}:${gameId}`;
setJsonValue(key, builtJs);
} catch (e) {
console.error(e);
}
*/
}

export {
getJsonValue,
setJsonValue,
Expand All @@ -151,6 +128,4 @@ export {
setKioskCode,
getKioskCode,
clearKioskCode,
getBuiltJsInfo,
setBuiltJsInfo,
};
14 changes: 7 additions & 7 deletions kiosk/src/Services/SimHostService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { resetHighScores } from "../Transforms/resetHighScores";
import * as GamepadManager from "./GamepadManager";
import { postNotification } from "../Transforms/postNotification";
import { makeNotification } from "../Utils";
import * as Storage from "./LocalStorage";
import * as IndexedDb from "./IndexedDb";

export function initialize() {
let controlStates: GamepadManager.ControlStates = {
Expand Down Expand Up @@ -63,8 +63,8 @@ export function initialize() {
GamepadManager.addKeydownListener(keydownhandler);
GamepadManager.addKeyupListener(keyuphandler);

function sendBuiltGame(gameId: string) {
const builtGame = Storage.getBuiltJsInfo(gameId);
async function sendBuiltGameAsync(gameId: string) {
const builtGame = await IndexedDb.getBuiltJsInfoAsync(gameId);
if (builtGame) {
const simIframe = document.getElementsByTagName(
"iframe"
Expand All @@ -76,10 +76,10 @@ export function initialize() {
}
}

window.addEventListener("message", event => {
window.addEventListener("message", async (event) => {
const { state, dispatch } = stateAndDispatch();
if (event.data?.js && state.launchedGameId) {
Storage.setBuiltJsInfo(state.launchedGameId, event.data);
await IndexedDb.setBuiltJsInfoAsync(state.launchedGameId, event.data);
}
switch (event.data.type) {
case "simulator":
Expand Down Expand Up @@ -111,9 +111,9 @@ export function initialize() {
break;

case "ready":
const builtGame = Storage.getBuiltJsInfo(state.launchedGameId!);
const builtGame = await IndexedDb.getBuiltJsInfoAsync(state.launchedGameId!);
if (builtGame) {
sendBuiltGame(state.launchedGameId!);
await sendBuiltGameAsync(state.launchedGameId!);
}
break;
}
Expand Down

0 comments on commit fd346f1

Please sign in to comment.