Skip to content

Commit

Permalink
Load nested zip files in wasm frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
pipe01 committed Oct 28, 2024
1 parent 972782d commit b432107
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 21 deletions.
4 changes: 0 additions & 4 deletions frontend/wasm/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ async function loadFileFromURL(url: string) {
}
}
function loadSampleFile() {
location.search = "?firmware=https://share.pipe01.net/-XpJvumKzSS/pinetime-app-1.14.0.bin";
}
function loadFile(file: File) {
const reader = new FileReader();
Expand Down
26 changes: 23 additions & 3 deletions frontend/wasm/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { customRef, onUnmounted, type Ref } from "vue";
import type { MessageFromWorkerType, MessageToWorkerType } from "./common";
import { type FS, fs, type ZipEntry, type ZipFileEntry } from "@zip.js/zip.js";

export function useAverage(interval: number): Ref<number> {
let sum = 0;
Expand Down Expand Up @@ -46,9 +47,10 @@ export function sendMessage<Type extends MessageToWorkerType["type"]>(worker: Wo
// I'm sorry
export function sendMessageAndWait<Type extends MessageToWorkerType["type"], ReplyType extends MessageFromWorkerType["type"]>(
worker: Worker, type: Type,
data: Extract<MessageToWorkerType, { type: Type }>["data"], replyType: ReplyType = "done" as ReplyType, transfer?: Transferable[]):
Promise<Extract<MessageFromWorkerType, { type: ReplyType }>["data"]> {
return new Promise((resolve, reject) => {
data: Extract<MessageToWorkerType, { type: Type }>["data"],
replyType: ReplyType = "done" as ReplyType,
transfer?: Transferable[]): Promise<Extract<MessageFromWorkerType, { type: ReplyType }>["data"]> {
return new Promise<any>((resolve, reject) => {
let messageId: number;

const listener = (e: MessageEvent) => {
Expand Down Expand Up @@ -91,3 +93,21 @@ export function downloadBuffer(data: BlobPart, filename: string) {
export function joinLFSPaths(...paths: string[]) {
return paths.join("/").replace(/^\//, "").replace(/\/+/g, "/");
}

export function isFile(file: ZipEntry): file is ZipFileEntry<void, void> {
return !(file as any).directory;
}

export async function getZipOrNested(data: Uint8Array, maxDepth = 5): Promise<FS> {
const zip = new fs.FS();
await zip.importUint8Array(data);

if (zip.root.children.length == 1 && isFile(zip.root.children[0]) && zip.root.children[0].name.endsWith(".zip")) {
if (maxDepth == 0)
throw new Error("Max depth reached");

return await getZipOrNested(await zip.root.children[0].getUint8Array(), maxDepth - 1);
} else {
return zip;
}
}
39 changes: 25 additions & 14 deletions frontend/wasm/src/worker.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { ZipEntry, ZipFileEntry, fs } from "@zip.js/zip.js";
import type { CPU, CST816S, Commander, LFS, NRF52832, Pinetime, Pins, Pointer, Program, RTT, SPINorFlash, ST7789 } from "../infiniemu.js"
import createModule from "../infiniemu.js"
import type { FileInfo, MessageFromWorkerType, MessageToWorkerType } from "./common";
import { joinLFSPaths } from "./utils.js";
import { getZipOrNested, isFile, joinLFSPaths } from "./utils";

const iterations = 100000;

Expand Down Expand Up @@ -51,10 +50,6 @@ function sendMessage<Type extends MessageFromWorkerType["type"]>(type: Type, dat
postMessage({ type, data, replyToId: replyTo });
}

function isFile(file: ZipEntry): file is ZipFileEntry<void, void> {
return !(file as any).directory;
}

class Emulator {
private readonly rttReadBufferSize = 1024;

Expand Down Expand Up @@ -95,8 +90,12 @@ class Emulator {
this.program = Module._program_new(0x800000);

const args = [this.program, 0, programFile, programFile.length];
if (Module.ccall("program_load_elf", "number", ["number", "number", "array", "number"], args) === 0)
if (Module.ccall("program_load_elf", "number", ["number", "number", "array", "number"], args) === 0) {
console.log("Failed to load ELF, trying binary");
Module.ccall("program_load_binary", null, ["number", "number", "array", "number"], args);
} else {
console.log("Loaded ELF");
}

this.pinetime = Module._pinetime_new(this.program);
this.nrf52 = Module._pinetime_get_nrf52832(this.pinetime);
Expand Down Expand Up @@ -365,8 +364,7 @@ class Emulator {
}

async loadArchiveFS(toPath: string, data: Uint8Array) {
const zip = new fs.FS();
await zip.importUint8Array(data);
const zip = await getZipOrNested(data);

let importedResources = false;

Expand Down Expand Up @@ -460,14 +458,27 @@ createModule({
},
onAbort(what: any) {
console.error("wasm aborted", what);
emulator?.stop();
sendMessage("aborted", what);
},
}).then((mod) => {
Module = mod;
sendMessage("ready", undefined);
});

function handleMessage(msg: MessageToWorkerType) {
async function loadZipFirmware(data: Uint8Array): Promise<Uint8Array> {
try {
const zip = await getZipOrNested(data);

if (zip.children.length == 1 && isFile(zip.children[0]))
return await zip.children[0].getUint8Array();
} catch (error) {
}

return data;
}

async function handleMessage(msg: MessageToWorkerType) {
const { type, data } = msg;

if (type == "setProgram") {
Expand All @@ -480,9 +491,9 @@ function handleMessage(msg: MessageToWorkerType) {
return;
}

const buf = data as ArrayBuffer;
const arr = new Uint8Array(data);

emulator = new Emulator(Module, new Uint8Array(buf));
emulator = new Emulator(Module, await loadZipFirmware(arr));
}
else if (emulator) {
switch (type) {
Expand Down Expand Up @@ -572,9 +583,9 @@ function handleMessage(msg: MessageToWorkerType) {
sendMessage("done", undefined, msg.messageId);
}

onmessage = event => {
onmessage = async event => {
try {
handleMessage(event.data as MessageToWorkerType);
await handleMessage(event.data as MessageToWorkerType);
} catch (error: any) {
sendMessage("error", {
message: "message" in error ? error.message : undefined,
Expand Down

0 comments on commit b432107

Please sign in to comment.