wasm-idle 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,10 @@
1
1
  import App from "./app";
2
2
  import { MemFS } from "./memory";
3
+ import { type Writable } from "svelte/store";
3
4
  interface APIOption {
4
5
  stdin: () => string;
5
6
  stdout: (str: string) => void;
7
+ progress: (value: number) => void;
6
8
  log?: boolean;
7
9
  showTiming?: boolean;
8
10
  path: string;
@@ -19,10 +21,15 @@ export default class Clang {
19
21
  lastCode: string;
20
22
  path: string;
21
23
  wasm?: WebAssembly.Instance;
24
+ progress: {
25
+ clang: Writable<number>;
26
+ lld: Writable<number>;
27
+ memfs: Writable<number>;
28
+ };
22
29
  constructor(options: APIOption);
23
30
  hostLog(message: string): void;
24
31
  hostLogAsync(message: string, promise: Promise<any>): Promise<any>;
25
- getModule(name: string): Promise<any>;
32
+ getModule(name: string, progress?: Writable<number>): Promise<any>;
26
33
  compile(options: any): Promise<App | null>;
27
34
  link(obj: string, wasm: string): Promise<App | null>;
28
35
  run(module: WebAssembly.Module, out: boolean, ...args: string[]): Promise<App | null>;
@@ -3,6 +3,7 @@ import { MemFS, untar } from "./memory";
3
3
  import { green, yellow, normal } from "./color";
4
4
  import { compile, readBuffer } from "./wasm";
5
5
  import { clangUrl, lldUrl, rootUrl } from "./url";
6
+ import { derived, writable } from "svelte/store";
6
7
  const clangCommonArgs = [
7
8
  '-disable-free',
8
9
  '-isysroot', '/',
@@ -40,6 +41,11 @@ export default class Clang {
40
41
  lastCode = '';
41
42
  path;
42
43
  wasm;
44
+ progress = {
45
+ clang: writable(0),
46
+ lld: writable(0),
47
+ memfs: writable(0),
48
+ };
43
49
  constructor(options) {
44
50
  this.moduleCache = {};
45
51
  this.stdout = options.stdout;
@@ -49,10 +55,17 @@ export default class Clang {
49
55
  this.memfs = new MemFS({
50
56
  stdout: this.stdout,
51
57
  stdin: options.stdin,
52
- path: this.path
58
+ path: this.path,
59
+ progress: this.progress.memfs,
53
60
  });
54
- this.getModule(clangUrl(this.path));
55
- this.getModule(lldUrl(this.path));
61
+ const progress = derived([this.progress.clang, this.progress.lld, this.progress.memfs], ([clang, lld, memfs]) => {
62
+ return (clang + lld + memfs) / 3;
63
+ });
64
+ progress.subscribe(value => {
65
+ options.progress(value);
66
+ });
67
+ this.getModule(clangUrl(this.path), this.progress.clang);
68
+ this.getModule(lldUrl(this.path), this.progress.lld);
56
69
  this.ready = this.memfs.ready.then(() => this.hostLogAsync(`Untarring ${rootUrl(this.path)}`, readBuffer(rootUrl(this.path)).then(buffer => untar(buffer, this.memfs))));
57
70
  }
58
71
  hostLog(message) {
@@ -74,10 +87,10 @@ export default class Clang {
74
87
  this.stdout('\n');
75
88
  return result;
76
89
  }
77
- async getModule(name) {
90
+ async getModule(name, progress) {
78
91
  if (this.moduleCache[name])
79
92
  return this.moduleCache[name];
80
- const module = await this.hostLogAsync(`Fetching and compiling ${name}`, compile(name));
93
+ const module = await this.hostLogAsync(`Fetching and compiling ${name}`, compile(name, progress));
81
94
  this.moduleCache[name] = module;
82
95
  return module;
83
96
  }
@@ -1,9 +1,11 @@
1
1
  import { Memory } from './';
2
+ import type { Writable } from "svelte/store";
2
3
  interface MemFsOptions {
3
4
  stdin: () => string;
4
5
  stdout: (str: string) => void;
5
6
  stdinStr?: string;
6
7
  path: string;
8
+ progress?: Writable<number>;
7
9
  }
8
10
  export default class MemFS {
9
11
  ready: Promise<void>;
@@ -19,7 +19,7 @@ export default class MemFS {
19
19
  this.stdout = options.stdout;
20
20
  this.stdinStr = options.stdinStr || "";
21
21
  const env = bindNew(this, 'abort', 'host_write', 'host_read', 'memfs_log', 'copy_in', 'copy_out');
22
- this.ready = compile(memfsUrl(options.path))
22
+ this.ready = compile(memfsUrl(options.path), options.progress)
23
23
  .then(module => WebAssembly.instantiate(module, { env }))
24
24
  .then(instance => {
25
25
  this.instance = instance;
@@ -1,3 +1,4 @@
1
- export declare const readBuffer: (name: string) => Promise<Uint8Array | undefined>;
2
- export declare function compile(filename: string): Promise<any>;
1
+ import type { Writable } from "svelte/store";
2
+ export declare const readBuffer: (name: string, progress?: Writable<number>) => Promise<Uint8Array>;
3
+ export declare function compile(filename: string, progress?: Writable<number>): Promise<any>;
3
4
  export declare function getInstance(module: WebAssembly.Module, imports: WebAssembly.Imports): Promise<WebAssembly.Instance>;
@@ -1,21 +1,40 @@
1
1
  import * as zip from "@zip.js/zip.js";
2
2
  const store = {};
3
- export const readBuffer = async (name) => {
3
+ export const readBuffer = async (name, progress) => {
4
4
  const response = await fetch(name);
5
- const blob = await response.blob();
6
- const reader = new zip.ZipReader(new zip.BlobReader(blob));
5
+ const r = response.body.getReader();
6
+ const contentLength = +response.headers.get('Content-Length');
7
+ let receivedLength = 0;
8
+ let chunks = [];
9
+ while (true) {
10
+ const { done, value } = await r.read();
11
+ if (done)
12
+ break;
13
+ chunks.push(value);
14
+ receivedLength += value.length;
15
+ progress?.set?.(receivedLength / contentLength);
16
+ }
17
+ progress?.set?.(1);
18
+ const chunksAll = new Uint8Array(receivedLength); // (4.1)
19
+ let position = 0;
20
+ for (const chunk of chunks) {
21
+ chunksAll.set(chunk, position);
22
+ position += chunk.length;
23
+ }
24
+ const reader = new zip.ZipReader(new zip.Uint8ArrayReader(chunksAll));
7
25
  const entries = await reader.getEntries();
8
26
  for (const entry of entries) {
9
27
  const data = await entry.getData(new zip.Uint8ArrayWriter());
10
28
  return data;
11
29
  }
30
+ throw new Error('No entry found');
12
31
  };
13
- export async function compile(filename) {
32
+ export async function compile(filename, progress) {
14
33
  // TODO: make compileStreaming work. It needs the server to use the
15
34
  // application/wasm mimetype.
16
35
  if (store[filename])
17
36
  return store[filename];
18
- return store[filename] = WebAssembly.compile(await readBuffer(filename));
37
+ return store[filename] = WebAssembly.compile(await readBuffer(filename, progress));
19
38
  }
20
39
  export function getInstance(module, imports) {
21
40
  return WebAssembly.instantiate(module, imports);
@@ -1,4 +1,5 @@
1
1
  import type Sandbox from './sandbox';
2
+ import type { Writable } from "svelte/store";
2
3
  declare class Clang implements Sandbox {
3
4
  ts: number;
4
5
  output: any;
@@ -15,7 +16,7 @@ declare class Clang implements Sandbox {
15
16
  write(input: string): void;
16
17
  _write(input: string): void;
17
18
  eof(): void;
18
- run(code: string, prepare: boolean, log?: boolean): Promise<string>;
19
+ run(code: string, prepare: boolean, log?: boolean, prog?: Writable<number>): Promise<string>;
19
20
  terminate(): void;
20
21
  clear(): Promise<void>;
21
22
  }
@@ -40,7 +40,7 @@ class Clang {
40
40
  }
41
41
  eof() {
42
42
  }
43
- run(code, prepare, log = this.log) {
43
+ run(code, prepare, log = this.log, prog) {
44
44
  this.exit = false;
45
45
  return new Promise(async (resolve, reject) => {
46
46
  if (!this.worker)
@@ -51,7 +51,7 @@ class Clang {
51
51
  return reject('Worker not loaded');
52
52
  if (_uid !== this.uid)
53
53
  return this.worker.onmessage = null;
54
- const { id, output, results, log, error, buffer } = event.data;
54
+ const { id, output, results, log, error, buffer, progress } = event.data;
55
55
  if (buffer && this.internalBuffer.length)
56
56
  this._write(this.internalBuffer.splice(0, 1)[0]);
57
57
  if (output)
@@ -67,6 +67,8 @@ class Clang {
67
67
  this.elapse = Date.now() - this.begin;
68
68
  reject(error);
69
69
  }
70
+ if (progress)
71
+ prog?.set?.(progress);
70
72
  };
71
73
  interrupt[0] = 0;
72
74
  this.worker.onmessage = handler;
@@ -1,3 +1,4 @@
1
+ import Clang from './clang';
1
2
  import type Sandbox from './sandbox';
2
3
  export declare const supportedLanguages: string[];
3
- export default function load(language: string): Promise<Sandbox | undefined>;
4
+ export default function load(language: string): Promise<Sandbox | Clang | undefined>;
@@ -27,6 +27,7 @@ async function loadClang(path, log) {
27
27
  }
28
28
  }
29
29
  },
30
+ progress: (value) => postMessage({ progress: value }),
30
31
  log, path,
31
32
  });
32
33
  }
@@ -56,13 +56,13 @@ export const terminal = {
56
56
  first = true;
57
57
  await new Promise((r) => setTimeout(r, 100));
58
58
  },
59
- async prepare(language, code, log = true) {
59
+ async prepare(language, code, log = true, prog) {
60
60
  await Promise.all([initSandbox(language).then(() => sandbox.load(path, code, log)), initTerm(false)]);
61
- await runSandbox(sandbox.run(code, true, log));
61
+ await runSandbox(sandbox.run(code, true, log, prog));
62
62
  },
63
- async run(language, code, log = true) {
63
+ async run(language, code, log = true, prog) {
64
64
  await Promise.all([initSandbox(language).then(() => sandbox.load(path, code, log)), initTerm()]);
65
- await runSandbox(sandbox.run(code, false, log));
65
+ await runSandbox(sandbox.run(code, false, log, prog));
66
66
  },
67
67
  async destroy() {
68
68
  await wait();
@@ -7,8 +7,8 @@ declare const __propDef: {
7
7
  font?: string | undefined;
8
8
  terminal?: {
9
9
  clear(): Promise<void>;
10
- prepare(language: any, code: any, log?: boolean): Promise<void>;
11
- run(language: any, code: any, log?: boolean): Promise<void>;
10
+ prepare(language: any, code: any, log: boolean | undefined, prog: any): Promise<void>;
11
+ run(language: any, code: any, log: boolean | undefined, prog: any): Promise<void>;
12
12
  destroy(): Promise<void>;
13
13
  } | undefined;
14
14
  };
@@ -26,8 +26,8 @@ export type TerminalSlots = typeof __propDef.slots;
26
26
  export default class Terminal extends SvelteComponentTyped<TerminalProps, TerminalEvents, TerminalSlots> {
27
27
  get terminal(): {
28
28
  clear(): Promise<void>;
29
- prepare(language: any, code: any, log?: boolean): Promise<void>;
30
- run(language: any, code: any, log?: boolean): Promise<void>;
29
+ prepare(language: any, code: any, log: boolean | undefined, prog: any): Promise<void>;
30
+ run(language: any, code: any, log: boolean | undefined, prog: any): Promise<void>;
31
31
  destroy(): Promise<void>;
32
32
  };
33
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wasm-idle",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "A simple web app to run C++/Python code in the browser",
5
5
  "license": "MIT",
6
6
  "type": "module",