Skip to content

Commit ae42181

Browse files
authored
Support stdin via service worker (#212)
* Support stdin via service worker * Linting * Move service worker implementation to comlink worker * Make XeusRemoteKernel.mount abstract
1 parent 2872782 commit ae42181

File tree

5 files changed

+69
-14
lines changed

5 files changed

+69
-14
lines changed

packages/xeus/src/coincident.worker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ export class XeusCoincidentKernel extends XeusRemoteKernel {
6565
FS.mount(drive, {}, mountpoint);
6666
FS.chdir(mountpoint);
6767
}
68+
69+
protected _initializeStdin(baseUrl: string, browsingContextId: string): void {
70+
// TODO: SharedArrayBuffer implementation
71+
}
6872
}
6973

7074
const worker = new XeusCoincidentKernel();

packages/xeus/src/comlink.worker.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import { expose } from 'comlink';
99

10+
import { URLExt } from '@jupyterlab/coreutils';
11+
1012
import { DriveFS } from '@jupyterlite/contents';
1113

1214
import { XeusRemoteKernel } from './worker';
@@ -41,6 +43,34 @@ export class XeusComlinkKernel extends XeusRemoteKernel {
4143
FS.mount(drive, {}, mountpoint);
4244
FS.chdir(mountpoint);
4345
}
46+
47+
protected _initializeStdin(baseUrl: string, browsingContextId: string): void {
48+
globalThis.get_stdin = (inputRequest: any): any => {
49+
// Send a input request to the front-end via the service worker and block until
50+
// the reply is received.
51+
try {
52+
const xhr = new XMLHttpRequest();
53+
const url = URLExt.join(baseUrl, '/stdin/kernel');
54+
xhr.open('POST', url, false); // Synchronous XMLHttpRequest
55+
const msg = JSON.stringify({
56+
browsingContextId,
57+
data: inputRequest
58+
});
59+
// Send input request, this blocks until the input reply is received.
60+
xhr.send(msg);
61+
const inputReply = JSON.parse(xhr.response as string);
62+
63+
if ('error' in inputReply) {
64+
// Service worker may return an error instead of an input reply message.
65+
throw new Error(inputReply['error']);
66+
}
67+
68+
return inputReply;
69+
} catch (err) {
70+
return { error: `Failed to request stdin via service worker: ${err}` };
71+
}
72+
};
73+
}
4474
}
4575

4676
const worker = new XeusComlinkKernel();

packages/xeus/src/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,6 @@ export namespace IXeusWorkerKernel {
8888
kernelSpec: any;
8989
mountDrive: boolean;
9090
empackEnvMetaLink?: string;
91+
browsingContextId: string;
9192
}
9293
}

packages/xeus/src/web_worker_kernel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ export class WebWorkerKernel implements IKernel {
113113
kernelSpec: this._kernelSpec,
114114
baseUrl: PageConfig.getBaseUrl(),
115115
mountDrive: options.mountDrive,
116-
empackEnvMetaLink: this._empackEnvMetaLink
116+
empackEnvMetaLink: this._empackEnvMetaLink,
117+
browsingContextId: options.browsingContextId
117118
})
118119
.then(this._ready.resolve.bind(this._ready));
119120

packages/xeus/src/worker.ts

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,10 @@ globalThis.toplevel_promise_py_proxy = null;
2929

3030
declare function createXeusModule(options: any): any;
3131

32-
let resolveInputReply: any;
3332
let kernelReady: (value: unknown) => void;
3433
let rawXKernel: any;
3534
let rawXServer: any;
3635

37-
async function get_stdin() {
38-
const replyPromise = new Promise(resolve => {
39-
resolveInputReply = resolve;
40-
});
41-
return replyPromise;
42-
}
43-
4436
async function fetchJson(url: string): Promise<any> {
4537
const response = await fetch(url);
4638
if (!response.ok) {
@@ -50,8 +42,6 @@ async function fetchJson(url: string): Promise<any> {
5042
return json;
5143
}
5244

53-
(self as any).get_stdin = get_stdin;
54-
5545
globalThis.ready = new Promise(resolve => {
5646
kernelReady = resolve;
5747
});
@@ -76,7 +66,7 @@ export class XeusWorkerLogger implements ILogger {
7666
private _channel: BroadcastChannel;
7767
}
7868

79-
export class XeusRemoteKernel {
69+
export abstract class XeusRemoteKernel {
8070
constructor(options: XeusRemoteKernel.IOptions = {}) {}
8171

8272
async ready(): Promise<void> {
@@ -116,14 +106,20 @@ export class XeusRemoteKernel {
116106
}
117107

118108
if (msg_type === 'input_reply') {
119-
resolveInputReply(event.msg);
109+
// Should never be called as input_reply messages are returned via service worker
120110
} else {
121111
rawXServer.notify_listener(event.msg);
122112
}
123113
}
124114

125115
async initialize(options: IXeusWorkerKernel.IOptions): Promise<void> {
126-
const { baseUrl, kernelSpec, empackEnvMetaLink, kernelId } = options;
116+
const {
117+
baseUrl,
118+
browsingContextId,
119+
kernelSpec,
120+
empackEnvMetaLink,
121+
kernelId
122+
} = options;
127123

128124
this._logger = new XeusWorkerLogger(kernelId);
129125

@@ -210,6 +206,8 @@ export class XeusRemoteKernel {
210206
});
211207
}
212208

209+
this._initializeStdin(baseUrl, browsingContextId);
210+
213211
rawXKernel = new globalThis.Module.xkernel();
214212
rawXServer = rawXKernel.get_server();
215213
if (!rawXServer) {
@@ -232,6 +230,27 @@ export class XeusRemoteKernel {
232230
kernelReady(1);
233231
}
234232

233+
/**
234+
* Setup custom Emscripten FileSystem
235+
*/
236+
abstract mount(
237+
driveName: string,
238+
mountpoint: string,
239+
baseUrl: string,
240+
browsingContextId: string
241+
): Promise<void>;
242+
243+
/**
244+
* Add get_stdin function to globalThis that takes an input_request message, blocks
245+
* until the corresponding input_reply is received and returns the input_reply message.
246+
* If an error occurs return an object of the form { error: "Error explanation" }
247+
* This function is called by xeus-lite's get_stdin.
248+
*/
249+
protected abstract _initializeStdin(
250+
baseUrl: string,
251+
browsingContextId: string
252+
): void;
253+
235254
private _logger: XeusWorkerLogger;
236255
}
237256

0 commit comments

Comments
 (0)