-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathWasmRunner.js
216 lines (189 loc) · 5.44 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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
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
// print input to terminal
stdoutProxy(input)
if (!promptCaption) stdoutProxy("\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
_onWasmerStdinCall(stdinBuffer, stdinProxy, stdoutProxy, stderrProxy) {
// 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)
if (!promptCaption) stdoutProxy("\r\n")
// copy input value to stdinBuffer
Array.from(input + "\n").forEach(
(char, i) => (stdinBuffer[i] = char.charCodeAt(0))
)
// return how much to read
return input.length + 1
}
}
export default WasmRunner
export const MODULE_ID = __webpack_module__.id