forked from cryptool-org/wasm-webterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWasmRunner.js
149 lines (101 loc) · 5.45 KB
/
WasmRunner.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import EmscrWasmRunnable from "../runnables/EmscriptenRunnable"
import WasmerRunnable from "../runnables/WasmerRunnable"
/* executes wasm on the main thread. asks for stdin by using prompts.
this class will be extented by WasmWorker to run on worker thread. */
class WasmRunner {
outputBuffer
constructor() { this.outputBuffer = "" }
runCommand(programName, wasmModule, wasmModuleType, argv, stdinProxy, stdoutProxy,
stderrProxy, files, onFinish, onError, onSuccess, stdinPreset, emscrJsRuntime) {
// initialize default callbacks
if(typeof onFinish != "function") onFinish = () => {}
if(typeof onError != "function") onError = (e) => { console.error(e) }
if(typeof onSuccess != "function") onSuccess = () => {}
// store outputs of stdout in buffer (for stdin prompts)
const bufferOutputs = (value) => { this.outputBuffer += (typeof value == "number") ? String.fromCharCode(value) : value }
const stdoutHandler = (value) => { bufferOutputs(value); return stdoutProxy(value) }
const stderrHandler = (value) => { bufferOutputs(value); return stderrProxy(value) }
if(wasmModuleType == "emscripten") {
// instantiate new emscr runnable
console.log("wasm runner creates new emscr runnable")
let emscrWasmExe = new EmscrWasmRunnable(programName, wasmModule, emscrJsRuntime)
// pipe stdin calls through stdin handler (which pauses thread)
const stdinHandler = (tty) => this._onEmscrStdinCall(tty, stdinProxy, stdoutHandler, stderrHandler)
// run command on it
emscrWasmExe.run(argv, stdinHandler, stdoutHandler, stderrHandler, files, onFinish, onError, onSuccess, stdinPreset)
}
else if(wasmModuleType == "wasmer") {
// instantiate new wasmer runnable
console.log("wasm runner creates new wasmer runnable")
let wasmerExe = new WasmerRunnable(programName, wasmModule)
// pipe stdin calls through stdin handler (which pauses thread)
const stdinHandler = (stdinBuffer) => this._onWasmerStdinCall(stdinBuffer, stdinProxy, stdoutHandler, stderrHandler)
// run command on it
wasmerExe.run(argv, stdinHandler, stdoutHandler, stderrHandler, files, onFinish, onError, onSuccess, stdinPreset)
}
else throw new Error("Unknown wasm module type (can only handle emscripten or wasmer)")
}
runCommandHeadless(programName, wasmModule, wasmModuleType, argv,
files, onFinish, onError, onSuccess, stdinPreset, emscrJsRuntime) {
// initialize default callbacks
if(typeof onFinish != "function") onFinish = () => {}
if(typeof onError != "function") onError = (e) => { console.error(e) }
if(typeof onSuccess != "function") onSuccess = () => {}
if(wasmModuleType == "emscripten") {
// instantiate new emscr runnable
console.log("wasm runner creates new emscr runnable")
let emscrWasmExe = new EmscrWasmRunnable(programName, wasmModule, emscrJsRuntime)
// run command on it
emscrWasmExe.runHeadless(argv, files, onFinish, onError, onSuccess, stdinPreset)
}
else if(wasmModuleType == "wasmer") {
// instantiate new wasmer runnable
let wasmerExe = new WasmerRunnable(programName, wasmModule)
// run command on it
wasmerExe.runHeadless(argv, files, onFinish, onError, onSuccess, stdinPreset)
}
else throw new Error("Unknown wasm module type (can only handle emscripten or wasmer)")
}
// handles stdin calls from emscr (tty is passed by emscr js runtime)
_onEmscrStdinCall(tty, stdinProxy, stdoutProxy, stderrProxy) {
if(tty.input.length == 0) {
// use last line from output buffer as prompt caption
const promptCaption = this.outputBuffer.split(/\r?\n/g).pop()
// get input from user via prompt
const input = window.prompt(promptCaption)
// if aborted -> end
if(input == null) return null
// if input was empty -> prompt again
// if(input == "") return this._onEmscrStdinCall(tty)
// print input to terminal
stdoutProxy(input + "\r\n")
// copy input value to tty input
tty.input = (input + "\n").split("").map(char => char.charCodeAt(0))
tty.input.push(null) // marks end
}
// deliver input
return tty.input.shift()
}
// handles stdin calls from wasmer
_wasmerStdinCallCounter = 0
_onWasmerStdinCall(stdinBuffer, stdinProxy, stdoutProxy, stderrProxy) {
// second read means end of string
if(this._wasmerStdinCallCounter % 2 !== 0) {
this._wasmerStdinCallCounter++; return 0 }
// use last line from output buffer as prompt caption
const promptCaption = this.outputBuffer.split(/\r?\n/g).pop()
// get input from user via prompt
const input = window.prompt(promptCaption)
// if aborted -> end
if(input == null) return 0
// print input to terminal
stdoutProxy(input + "\r\n")
// copy input value to stdinBuffer
input.forEach((char, i) => stdinBuffer[i] = char.charCodeAt(0))
// indicate we've read once
this._wasmerStdinCallCounter++
// return how much to read
return input.length
}
}
export default WasmRunner