@jupyterlite/services 0.1.0 → 0.7.0-rc.0
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.
- package/lib/contents/drive.d.ts +277 -0
- package/lib/contents/drive.js +888 -0
- package/lib/contents/drive.js.map +1 -0
- package/lib/contents/drivecontents.d.ts +92 -0
- package/lib/contents/drivecontents.js +132 -0
- package/lib/contents/drivecontents.js.map +1 -0
- package/lib/contents/drivefs.d.ts +245 -0
- package/lib/contents/drivefs.js +481 -0
- package/lib/contents/drivefs.js.map +1 -0
- package/lib/contents/emscripten.d.ts +96 -0
- package/lib/contents/emscripten.js +10 -0
- package/lib/contents/emscripten.js.map +1 -0
- package/lib/contents/index.d.ts +5 -0
- package/lib/contents/index.js +8 -0
- package/lib/contents/index.js.map +1 -0
- package/lib/contents/tokens.d.ts +21 -0
- package/lib/contents/tokens.js +55 -0
- package/lib/contents/tokens.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/lib/kernel/base.d.ts +245 -0
- package/lib/kernel/base.js +457 -0
- package/lib/kernel/base.js.map +1 -0
- package/lib/kernel/client.d.ts +114 -0
- package/lib/kernel/client.js +375 -0
- package/lib/kernel/client.js.map +1 -0
- package/lib/kernel/index.d.ts +5 -0
- package/lib/kernel/index.js +8 -0
- package/lib/kernel/index.js.map +1 -0
- package/lib/kernel/kernelspecclient.d.ts +39 -0
- package/lib/kernel/kernelspecclient.js +37 -0
- package/lib/kernel/kernelspecclient.js.map +1 -0
- package/lib/kernel/kernelspecs.d.ts +59 -0
- package/lib/kernel/kernelspecs.js +62 -0
- package/lib/kernel/kernelspecs.js.map +1 -0
- package/lib/kernel/tokens.d.ts +163 -0
- package/lib/kernel/tokens.js +20 -0
- package/lib/kernel/tokens.js.map +1 -0
- package/lib/nbconvert/exporters.d.ts +80 -0
- package/lib/nbconvert/exporters.js +154 -0
- package/lib/nbconvert/exporters.js.map +1 -0
- package/lib/nbconvert/index.d.ts +3 -0
- package/lib/nbconvert/index.js +6 -0
- package/lib/nbconvert/index.js.map +1 -0
- package/lib/nbconvert/manager.d.ts +66 -0
- package/lib/nbconvert/manager.js +77 -0
- package/lib/nbconvert/manager.js.map +1 -0
- package/lib/nbconvert/tokens.d.ts +49 -0
- package/lib/nbconvert/tokens.js +8 -0
- package/lib/nbconvert/tokens.js.map +1 -0
- package/lib/session/client.d.ts +85 -0
- package/lib/session/client.js +200 -0
- package/lib/session/client.js.map +1 -0
- package/lib/session/index.d.ts +1 -0
- package/lib/session/index.js +4 -0
- package/lib/session/index.js.map +1 -0
- package/lib/settings/index.d.ts +1 -0
- package/lib/settings/index.js +4 -0
- package/lib/settings/index.js.map +1 -0
- package/lib/settings/settings.d.ts +91 -0
- package/lib/settings/settings.js +185 -0
- package/lib/settings/settings.js.map +1 -0
- package/package.json +67 -8
- package/src/contents/drive.ts +1030 -0
- package/src/contents/drivecontents.ts +253 -0
- package/src/contents/drivefs.ts +824 -0
- package/src/contents/emscripten.ts +148 -0
- package/src/contents/index.ts +8 -0
- package/src/contents/tokens.ts +61 -0
- package/src/index.ts +13 -0
- package/src/kernel/base.ts +637 -0
- package/src/kernel/client.ts +483 -0
- package/src/kernel/index.ts +8 -0
- package/src/kernel/kernelspecclient.ts +64 -0
- package/src/kernel/kernelspecs.ts +103 -0
- package/src/kernel/tokens.ts +222 -0
- package/src/nbconvert/exporters.ts +177 -0
- package/src/nbconvert/index.ts +6 -0
- package/src/nbconvert/manager.ts +105 -0
- package/src/nbconvert/tokens.ts +60 -0
- package/src/session/client.ts +251 -0
- package/src/session/index.ts +4 -0
- package/src/settings/index.ts +4 -0
- package/src/settings/settings.ts +236 -0
- package/style/index.css +6 -0
- package/style/index.js +6 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
2
|
+
|
|
3
|
+
import { IObservableMap, ObservableMap } from '@jupyterlab/observables';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
KernelAPI,
|
|
7
|
+
Kernel,
|
|
8
|
+
KernelMessage,
|
|
9
|
+
ServerConnection,
|
|
10
|
+
} from '@jupyterlab/services';
|
|
11
|
+
|
|
12
|
+
import { deserialize, serialize } from '@jupyterlab/services/lib/kernel/serialize';
|
|
13
|
+
|
|
14
|
+
import { supportedKernelWebSocketProtocols } from '@jupyterlab/services/lib/kernel/messages';
|
|
15
|
+
|
|
16
|
+
import { PromiseDelegate, UUID } from '@lumino/coreutils';
|
|
17
|
+
|
|
18
|
+
import { ISignal, Signal } from '@lumino/signaling';
|
|
19
|
+
|
|
20
|
+
import { Mutex } from 'async-mutex';
|
|
21
|
+
|
|
22
|
+
import { Server as WebSocketServer, Client as WebSocketClient } from 'mock-socket';
|
|
23
|
+
|
|
24
|
+
import { FALLBACK_KERNEL, IKernel, IKernelSpecs } from './tokens';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Use the default kernel wire protocol.
|
|
28
|
+
*/
|
|
29
|
+
const KERNEL_WEBSOCKET_PROTOCOL =
|
|
30
|
+
supportedKernelWebSocketProtocols.v1KernelWebsocketJupyterOrg;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A class to handle requests to /api/kernels
|
|
34
|
+
*/
|
|
35
|
+
export class LiteKernelClient implements Kernel.IKernelAPIClient {
|
|
36
|
+
/**
|
|
37
|
+
* Construct a new Kernels
|
|
38
|
+
*
|
|
39
|
+
* @param options The instantiation options
|
|
40
|
+
*/
|
|
41
|
+
constructor(options: LiteKernelClient.IOptions) {
|
|
42
|
+
const { kernelSpecs } = options;
|
|
43
|
+
this._kernelspecs = kernelSpecs;
|
|
44
|
+
this._serverSettings = options.serverSettings ?? ServerConnection.makeSettings();
|
|
45
|
+
// Forward the changed signal from _kernels
|
|
46
|
+
this._kernels.changed.connect((_, args) => {
|
|
47
|
+
this._changed.emit(args);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The server settings for the kernel client.
|
|
53
|
+
*/
|
|
54
|
+
get serverSettings() {
|
|
55
|
+
return this._serverSettings;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Signal emitted when the kernels map changes
|
|
60
|
+
*/
|
|
61
|
+
get changed(): ISignal<this, IObservableMap.IChangedArgs<IKernel>> {
|
|
62
|
+
return this._changed;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Start a new kernel.
|
|
67
|
+
*
|
|
68
|
+
* @param options The kernel start options.
|
|
69
|
+
*/
|
|
70
|
+
async startNew(options: LiteKernelClient.IKernelOptions): Promise<Kernel.IModel> {
|
|
71
|
+
const { id, name, location } = options;
|
|
72
|
+
|
|
73
|
+
const kernelName = name ?? FALLBACK_KERNEL;
|
|
74
|
+
const factory = this._kernelspecs.factories.get(kernelName);
|
|
75
|
+
// bail if there is no factory associated with the requested kernel
|
|
76
|
+
if (!factory) {
|
|
77
|
+
throw Error(`No factory for kernel ${kernelName}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// create a synchronization mechanism to allow only one message
|
|
81
|
+
// to be processed at a time
|
|
82
|
+
const mutex = new Mutex();
|
|
83
|
+
|
|
84
|
+
// hook a new client to a kernel
|
|
85
|
+
const hook = (
|
|
86
|
+
kernelId: string,
|
|
87
|
+
clientId: string,
|
|
88
|
+
socket: WebSocketClient,
|
|
89
|
+
): void => {
|
|
90
|
+
const kernel = this._kernels.get(kernelId);
|
|
91
|
+
|
|
92
|
+
if (!kernel) {
|
|
93
|
+
throw Error(`No kernel ${kernelId}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this._clients.set(clientId, socket);
|
|
97
|
+
this._mutexMap.set(kernelId, mutex);
|
|
98
|
+
this._kernelClients.get(kernelId)?.add(clientId);
|
|
99
|
+
|
|
100
|
+
const processMsg = async (msg: KernelMessage.IMessage) => {
|
|
101
|
+
try {
|
|
102
|
+
await mutex.runExclusive(async () => {
|
|
103
|
+
await kernel.ready;
|
|
104
|
+
await kernel.handleMessage(msg);
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (
|
|
108
|
+
error instanceof Error &&
|
|
109
|
+
error.message.includes('request for lock canceled')
|
|
110
|
+
) {
|
|
111
|
+
// expected to throw when mutex.cancel() is called below on cell execution error or on interrupt
|
|
112
|
+
const cancelReason = this._cancelReason.get(mutex);
|
|
113
|
+
if (
|
|
114
|
+
(cancelReason === 'interrupt' ||
|
|
115
|
+
cancelReason === 'interrupt-subsequent') &&
|
|
116
|
+
msg.header.msg_type === 'execute_request'
|
|
117
|
+
) {
|
|
118
|
+
if (cancelReason === 'interrupt') {
|
|
119
|
+
// Change cancel reason so that only one cell includes the error.
|
|
120
|
+
// Needs to go before await for mutex.
|
|
121
|
+
this._cancelReason.set(mutex, 'interrupt-subsequent');
|
|
122
|
+
}
|
|
123
|
+
await mutex.waitForUnlock();
|
|
124
|
+
// Send interrupt error to all clients
|
|
125
|
+
const content: KernelMessage.IReplyErrorContent = {
|
|
126
|
+
status: 'error',
|
|
127
|
+
ename: 'Kernel Interrupt',
|
|
128
|
+
evalue: 'Interrupted',
|
|
129
|
+
traceback: [],
|
|
130
|
+
};
|
|
131
|
+
const sendMessage = this._kernelSends.get(kernelId);
|
|
132
|
+
if (sendMessage === undefined) {
|
|
133
|
+
console.warn('Did not find kernel send method');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (cancelReason === 'interrupt') {
|
|
137
|
+
sendMessage(
|
|
138
|
+
KernelMessage.createMessage<KernelMessage.IErrorMsg>({
|
|
139
|
+
channel: 'iopub',
|
|
140
|
+
session: clientId,
|
|
141
|
+
parentHeader: msg.header,
|
|
142
|
+
msgType: 'error',
|
|
143
|
+
content,
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
sendMessage(
|
|
148
|
+
KernelMessage.createMessage<KernelMessage.IExecuteReplyMsg>({
|
|
149
|
+
channel: 'shell',
|
|
150
|
+
session: clientId,
|
|
151
|
+
parentHeader: (msg as KernelMessage.IExecuteRequestMsg).header,
|
|
152
|
+
msgType: 'execute_reply',
|
|
153
|
+
content: {
|
|
154
|
+
...content,
|
|
155
|
+
execution_count: 0,
|
|
156
|
+
},
|
|
157
|
+
metadata: {
|
|
158
|
+
cause: 'interrupt',
|
|
159
|
+
},
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
sendMessage(
|
|
163
|
+
KernelMessage.createMessage<KernelMessage.IStatusMsg>({
|
|
164
|
+
channel: 'iopub',
|
|
165
|
+
session: clientId,
|
|
166
|
+
parentHeader: msg.header,
|
|
167
|
+
msgType: 'status',
|
|
168
|
+
content: {
|
|
169
|
+
execution_state: 'idle',
|
|
170
|
+
},
|
|
171
|
+
}),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
socket.on(
|
|
181
|
+
'message',
|
|
182
|
+
async (message: string | ArrayBuffer | Blob | ArrayBufferView) => {
|
|
183
|
+
let msg;
|
|
184
|
+
if (message instanceof ArrayBuffer) {
|
|
185
|
+
message = new Uint8Array(message).buffer;
|
|
186
|
+
msg = deserialize(message, KERNEL_WEBSOCKET_PROTOCOL);
|
|
187
|
+
} else if (typeof message === 'string') {
|
|
188
|
+
const encoder = new TextEncoder();
|
|
189
|
+
const encodedData = encoder.encode(message);
|
|
190
|
+
msg = deserialize(encodedData.buffer, KERNEL_WEBSOCKET_PROTOCOL);
|
|
191
|
+
} else {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (msg.header.msg_type === 'input_reply') {
|
|
196
|
+
if (this._stdinPromise !== undefined) {
|
|
197
|
+
// Stdin handled by Service Worker.
|
|
198
|
+
this._stdinPromise.resolve(msg as KernelMessage.IInputReplyMsg);
|
|
199
|
+
} else {
|
|
200
|
+
// Stdin handled by SharedArrayBuffer which is like conventional message
|
|
201
|
+
// passing to kernel except we cannot use processMsg as the mutex is
|
|
202
|
+
// already held.
|
|
203
|
+
void kernel.handleMessage(msg);
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
void processMsg(msg);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const removeClient = () => {
|
|
212
|
+
this._clients.delete(clientId);
|
|
213
|
+
this._kernelClients.get(kernelId)?.delete(clientId);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
kernel.disposed.connect(removeClient);
|
|
217
|
+
socket.onclose = removeClient;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// ensure kernel id
|
|
221
|
+
const kernelId = id ?? UUID.uuid4();
|
|
222
|
+
|
|
223
|
+
// There is one server per kernel which handles multiple clients
|
|
224
|
+
const kernelUrl = URLExt.join(
|
|
225
|
+
LiteKernelClient.WS_BASE_URL,
|
|
226
|
+
KernelAPI.KERNEL_SERVICE_URL,
|
|
227
|
+
encodeURIComponent(kernelId),
|
|
228
|
+
'channels',
|
|
229
|
+
);
|
|
230
|
+
const runningKernel = this._kernels.get(kernelId);
|
|
231
|
+
if (runningKernel) {
|
|
232
|
+
return {
|
|
233
|
+
id: runningKernel.id,
|
|
234
|
+
name: runningKernel.name,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// start the kernel
|
|
239
|
+
const sendMessage = (msg: KernelMessage.IMessage): void => {
|
|
240
|
+
const clientId =
|
|
241
|
+
msg.channel === 'stdin' ? msg.parent_header.session : msg.header.session;
|
|
242
|
+
const socket = this._clients.get(clientId);
|
|
243
|
+
if (!socket) {
|
|
244
|
+
console.warn(`Trying to send message on removed socket for kernel ${kernelId}`);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const message = serialize(msg, KERNEL_WEBSOCKET_PROTOCOL);
|
|
249
|
+
// process iopub messages
|
|
250
|
+
if (msg.channel === 'iopub') {
|
|
251
|
+
const clients = this._kernelClients.get(kernelId);
|
|
252
|
+
clients?.forEach((id) => {
|
|
253
|
+
this._clients.get(id)?.send(message);
|
|
254
|
+
});
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
// cancel the execution of other cells if there is an execute error
|
|
258
|
+
// to match the JupyterLab behavior
|
|
259
|
+
if (msg.header.msg_type === 'execute_reply') {
|
|
260
|
+
const executeReplyMsg = msg as KernelMessage.IExecuteReplyMsg;
|
|
261
|
+
if (
|
|
262
|
+
executeReplyMsg.content.status === 'error' &&
|
|
263
|
+
executeReplyMsg.metadata.cause !== 'interrupt'
|
|
264
|
+
) {
|
|
265
|
+
this._cancelReason.set(mutex, 'error');
|
|
266
|
+
mutex.cancel();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
socket.send(message);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const kernel = await factory({
|
|
273
|
+
id: kernelId,
|
|
274
|
+
sendMessage,
|
|
275
|
+
name: kernelName,
|
|
276
|
+
location: location ?? '',
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
this._kernels.set(kernelId, kernel);
|
|
280
|
+
this._kernelClients.set(kernelId, new Set<string>());
|
|
281
|
+
this._kernelSends.set(kernelId, sendMessage);
|
|
282
|
+
|
|
283
|
+
// create the websocket server for the kernel
|
|
284
|
+
const wsServer = new WebSocketServer(kernelUrl, {
|
|
285
|
+
mock: false,
|
|
286
|
+
selectProtocol: () => KERNEL_WEBSOCKET_PROTOCOL,
|
|
287
|
+
});
|
|
288
|
+
wsServer.on('connection', (socket: WebSocketClient): void => {
|
|
289
|
+
const url = new URL(socket.url);
|
|
290
|
+
const clientId = url.searchParams.get('session_id') ?? '';
|
|
291
|
+
hook(kernelId, clientId, socket);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// clean up closed connection
|
|
295
|
+
wsServer.on('close', (): void => {
|
|
296
|
+
this._clients.keys().forEach((clientId) => {
|
|
297
|
+
const socket = this._clients.get(clientId);
|
|
298
|
+
if (socket?.readyState === WebSocket.CLOSED) {
|
|
299
|
+
this._clients.delete(clientId);
|
|
300
|
+
this._kernelClients.get(kernelId)?.delete(clientId);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// cleanup on kernel shutdown
|
|
306
|
+
kernel.disposed.connect(() => {
|
|
307
|
+
wsServer.close();
|
|
308
|
+
this._kernels.delete(kernelId);
|
|
309
|
+
this._kernelClients.delete(kernelId);
|
|
310
|
+
this._mutexMap.delete(kernelId);
|
|
311
|
+
this._kernelSends.delete(kernelId);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
id: kernel.id,
|
|
316
|
+
name: kernel.name,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Restart a kernel.
|
|
322
|
+
*
|
|
323
|
+
* @param kernelId The kernel id.
|
|
324
|
+
*/
|
|
325
|
+
async restart(kernelId: string): Promise<void> {
|
|
326
|
+
const kernel = this._kernels.get(kernelId);
|
|
327
|
+
if (!kernel) {
|
|
328
|
+
throw Error(`Kernel ${kernelId} does not exist`);
|
|
329
|
+
}
|
|
330
|
+
const { id, name, location } = kernel;
|
|
331
|
+
kernel.dispose();
|
|
332
|
+
await this.startNew({ id, name, location });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Interrupt a kernel.
|
|
337
|
+
*/
|
|
338
|
+
async interrupt(kernelId: string): Promise<void> {
|
|
339
|
+
const kernel = this._kernels.get(kernelId);
|
|
340
|
+
if (!kernel) {
|
|
341
|
+
throw Error(`Kernel ${kernelId} does not exist`);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Wait for kernel to be ready
|
|
345
|
+
await kernel.ready;
|
|
346
|
+
|
|
347
|
+
// Cancel execution of following cells
|
|
348
|
+
const mutex = this._mutexMap.get(kernelId);
|
|
349
|
+
if (!mutex) {
|
|
350
|
+
console.warn('No mutex to cancel');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
this._cancelReason.set(mutex, 'interrupt');
|
|
354
|
+
mutex.cancel();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* List the running kernels.
|
|
359
|
+
*/
|
|
360
|
+
async listRunning(): Promise<Kernel.IModel[]> {
|
|
361
|
+
return [...this._kernels.values()].map((kernel) => ({
|
|
362
|
+
id: kernel.id,
|
|
363
|
+
name: kernel.name,
|
|
364
|
+
}));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Shut down a kernel.
|
|
369
|
+
*
|
|
370
|
+
* @param id The kernel id.
|
|
371
|
+
*/
|
|
372
|
+
async shutdown(id: string): Promise<void> {
|
|
373
|
+
this._kernels.delete(id)?.dispose();
|
|
374
|
+
this._kernelClients.delete(id);
|
|
375
|
+
this._kernelSends.delete(id);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Shut down all kernels.
|
|
380
|
+
*/
|
|
381
|
+
async shutdownAll(): Promise<void> {
|
|
382
|
+
this._kernels.keys().forEach((id) => {
|
|
383
|
+
this.shutdown(id);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Get a kernel by id
|
|
389
|
+
*/
|
|
390
|
+
async getModel(id: string): Promise<IKernel | undefined> {
|
|
391
|
+
return this._kernels.get(id);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Handle stdin request received from Service Worker.
|
|
396
|
+
*/
|
|
397
|
+
async handleStdin(
|
|
398
|
+
inputRequest: KernelMessage.IInputRequestMsg,
|
|
399
|
+
): Promise<KernelMessage.IInputReplyMsg> {
|
|
400
|
+
this._stdinPromise = new PromiseDelegate<KernelMessage.IInputReplyMsg>();
|
|
401
|
+
|
|
402
|
+
const clientId = inputRequest.parent_header.session;
|
|
403
|
+
const kernelId = this._getClientKernel(clientId);
|
|
404
|
+
if (kernelId !== undefined) {
|
|
405
|
+
const sendMessage = this._kernelSends.get(kernelId);
|
|
406
|
+
if (sendMessage !== undefined) {
|
|
407
|
+
sendMessage(inputRequest);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Promise is resolved by input reply message.
|
|
412
|
+
return this._stdinPromise.promise;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Get a kernel id corresponding to a client id.
|
|
417
|
+
*/
|
|
418
|
+
private _getClientKernel(clientId: string): string | undefined {
|
|
419
|
+
// Walk the _kernelClients to find a match.
|
|
420
|
+
return this._kernelClients
|
|
421
|
+
.keys()
|
|
422
|
+
.find((kernelId) => this._kernelClients.get(kernelId)!.has(clientId));
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
private _kernels = new ObservableMap<IKernel>();
|
|
426
|
+
private _clients = new ObservableMap<WebSocketClient>();
|
|
427
|
+
private _mutexMap = new Map<string, Mutex>();
|
|
428
|
+
private _kernelClients = new ObservableMap<Set<string>>();
|
|
429
|
+
private _kernelspecs: IKernelSpecs;
|
|
430
|
+
private _serverSettings: ServerConnection.ISettings;
|
|
431
|
+
private _changed = new Signal<this, IObservableMap.IChangedArgs<IKernel>>(this);
|
|
432
|
+
private _stdinPromise?: PromiseDelegate<KernelMessage.IInputReplyMsg>;
|
|
433
|
+
private _kernelSends = new ObservableMap<(msg: KernelMessage.IMessage) => void>();
|
|
434
|
+
private _cancelReason = new WeakMap<
|
|
435
|
+
Mutex,
|
|
436
|
+
'interrupt' | 'interrupt-subsequent' | 'error'
|
|
437
|
+
>();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* A namespace for Kernels statics.
|
|
442
|
+
*/
|
|
443
|
+
export namespace LiteKernelClient {
|
|
444
|
+
/**
|
|
445
|
+
* Options to create a new Kernels.
|
|
446
|
+
*/
|
|
447
|
+
export interface IOptions {
|
|
448
|
+
/**
|
|
449
|
+
* The kernel specs service.
|
|
450
|
+
*/
|
|
451
|
+
kernelSpecs: IKernelSpecs;
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Server settings for the kernel client.
|
|
455
|
+
*/
|
|
456
|
+
serverSettings?: ServerConnection.ISettings;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Options to start a new kernel.
|
|
461
|
+
*/
|
|
462
|
+
export interface IKernelOptions {
|
|
463
|
+
/**
|
|
464
|
+
* The kernel id.
|
|
465
|
+
*/
|
|
466
|
+
id?: string;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* The kernel name.
|
|
470
|
+
*/
|
|
471
|
+
name?: string;
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* The location in the virtual filesystem from which the kernel was started.
|
|
475
|
+
*/
|
|
476
|
+
location?: string;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* The base url for the Kernels manager
|
|
481
|
+
*/
|
|
482
|
+
export const WS_BASE_URL = PageConfig.getBaseUrl().replace(/^http/, 'ws');
|
|
483
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { KernelSpec, ServerConnection } from '@jupyterlab/services';
|
|
5
|
+
|
|
6
|
+
import { IKernelSpecs } from './tokens';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Placeholder for the kernel specs.
|
|
10
|
+
*/
|
|
11
|
+
const EMPTY_KERNELSPECS: KernelSpec.ISpecModels = {
|
|
12
|
+
default: '',
|
|
13
|
+
kernelspecs: {},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An in-browser client for the kernel spec API.
|
|
18
|
+
*/
|
|
19
|
+
export class LiteKernelSpecClient implements KernelSpec.IKernelSpecAPIClient {
|
|
20
|
+
/**
|
|
21
|
+
* Construct a new kernel spec client.
|
|
22
|
+
*/
|
|
23
|
+
constructor(options: LiteKernelSpecClient.IOptions) {
|
|
24
|
+
this._kernelspecs = options.kernelSpecs;
|
|
25
|
+
this._serverSettings = options.serverSettings ?? ServerConnection.makeSettings();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The server settings used by the client.
|
|
30
|
+
*/
|
|
31
|
+
get serverSettings(): ServerConnection.ISettings {
|
|
32
|
+
return this._serverSettings;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get the kernel specs.
|
|
37
|
+
*/
|
|
38
|
+
async get(): Promise<KernelSpec.ISpecModels> {
|
|
39
|
+
return Promise.resolve(this._kernelspecs.specs ?? EMPTY_KERNELSPECS);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private _kernelspecs: IKernelSpecs;
|
|
43
|
+
private _serverSettings: ServerConnection.ISettings;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* A namespace for LiteKernelSpecClient statics.
|
|
48
|
+
*/
|
|
49
|
+
export namespace LiteKernelSpecClient {
|
|
50
|
+
/**
|
|
51
|
+
* The options used to create a kernel spec client.
|
|
52
|
+
*/
|
|
53
|
+
export interface IOptions {
|
|
54
|
+
/**
|
|
55
|
+
* The in-browser kernel specs.
|
|
56
|
+
*/
|
|
57
|
+
kernelSpecs: IKernelSpecs;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The server settings used by the client.
|
|
61
|
+
*/
|
|
62
|
+
serverSettings?: ServerConnection.ISettings;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { PageConfig } from '@jupyterlab/coreutils';
|
|
2
|
+
|
|
3
|
+
import { KernelSpec } from '@jupyterlab/services';
|
|
4
|
+
|
|
5
|
+
import { ISignal, Signal } from '@lumino/signaling';
|
|
6
|
+
|
|
7
|
+
import { FALLBACK_KERNEL, IKernel, IKernelSpecs } from './tokens';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A class to register in-browser kernel specs.
|
|
11
|
+
*/
|
|
12
|
+
export class KernelSpecs implements IKernelSpecs {
|
|
13
|
+
/**
|
|
14
|
+
* Get the kernel specs.
|
|
15
|
+
*/
|
|
16
|
+
get specs(): KernelSpec.ISpecModels | null {
|
|
17
|
+
if (this._specs.size === 0) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
default: this.defaultKernelName,
|
|
23
|
+
kernelspecs: Object.fromEntries(this._specs),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the default kernel name.
|
|
29
|
+
*/
|
|
30
|
+
get defaultKernelName(): string {
|
|
31
|
+
let defaultKernelName = PageConfig.getOption('defaultKernelName');
|
|
32
|
+
|
|
33
|
+
if (!defaultKernelName && this._specs.size) {
|
|
34
|
+
const keys = Array.from(this._specs.keys());
|
|
35
|
+
keys.sort();
|
|
36
|
+
defaultKernelName = keys[0];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return defaultKernelName || FALLBACK_KERNEL;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the kernel factories for the current kernels.
|
|
44
|
+
*/
|
|
45
|
+
get factories(): KernelSpecs.KernelFactories {
|
|
46
|
+
return this._factories;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Signal emitted when the specs change.
|
|
51
|
+
*/
|
|
52
|
+
get changed(): ISignal<IKernelSpecs, KernelSpec.ISpecModels | null> {
|
|
53
|
+
return this._changed;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Register a new kernel.
|
|
58
|
+
*
|
|
59
|
+
* @param options The options to register a new kernel.
|
|
60
|
+
*/
|
|
61
|
+
register(options: KernelSpecs.IKernelOptions): void {
|
|
62
|
+
const { spec, create } = options;
|
|
63
|
+
this._specs.set(spec.name, spec);
|
|
64
|
+
this._factories.set(spec.name, create);
|
|
65
|
+
|
|
66
|
+
// notify a new spec has been added
|
|
67
|
+
this._changed.emit(this.specs);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private _specs = new Map<string, KernelSpec.ISpecModel>();
|
|
71
|
+
private _factories = new Map<string, KernelSpecs.KernelFactory>();
|
|
72
|
+
private _changed = new Signal<this, KernelSpec.ISpecModels | null>(this);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A namespace for KernelSpecs statics.
|
|
77
|
+
*/
|
|
78
|
+
export namespace KernelSpecs {
|
|
79
|
+
/**
|
|
80
|
+
* Registration options for a new kernel.
|
|
81
|
+
*/
|
|
82
|
+
export interface IKernelOptions {
|
|
83
|
+
/**
|
|
84
|
+
* The kernel spec.
|
|
85
|
+
*/
|
|
86
|
+
spec: KernelSpec.ISpecModel;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The factory function to instantiate a new kernel.
|
|
90
|
+
*/
|
|
91
|
+
create: KernelFactory;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The type for a kernel factory function used to instantiate new kernels.
|
|
96
|
+
*/
|
|
97
|
+
export type KernelFactory = (options: IKernel.IOptions) => Promise<IKernel>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The type for the record of kernel factory functions.
|
|
101
|
+
*/
|
|
102
|
+
export type KernelFactories = Map<string, KernelFactory>;
|
|
103
|
+
}
|