UNPKG

@jupyterlite/xeus-python-kernel

Version:

A Python kernel for JupyterLite, powered by Xeus

148 lines (147 loc) 4.3 kB
// Copyright (c) Thorsten Beier // Copyright (c) JupyterLite Contributors // Distributed under the terms of the Modified BSD License. import { wrap } from 'comlink'; import { Signal } from '@lumino/signaling'; import { PromiseDelegate } from '@lumino/coreutils'; import { PageConfig } from '@jupyterlab/coreutils'; export class WebWorkerKernel { /** * Instantiate a new WebWorkerKernel * * @param options The instantiation options for a new WebWorkerKernel */ constructor(options) { this._isDisposed = false; this._disposed = new Signal(this); this._executeDelegate = new PromiseDelegate(); this._parentHeader = undefined; this._parent = undefined; const { id, name, sendMessage, location } = options; this._id = id; this._name = name; this._location = location; this._sendMessage = sendMessage; this._worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }); this._worker.onmessage = e => { this._processWorkerMessage(e.data); }; this._remote = wrap(this._worker); this.initFileSystem(options); } async handleMessage(msg) { this._parent = msg; this._parentHeader = msg.header; await this._sendMessageToWorker(msg); } async _sendMessageToWorker(msg) { // TODO Remove this?? if (msg.header.msg_type !== 'input_reply') { this._executeDelegate = new PromiseDelegate(); } await this._remote.processMessage({ msg, parent: this.parent }); if (msg.header.msg_type !== 'input_reply') { return await this._executeDelegate.promise; } } /** * Get the last parent header */ get parentHeader() { return this._parentHeader; } /** * Get the last parent message (mimick ipykernel's get_parent) */ get parent() { return this._parent; } /** * Get the kernel location */ get location() { return this._location; } /** * Process a message coming from the pyodide web worker. * * @param msg The worker message to process. */ _processWorkerMessage(msg) { var _a, _b, _c, _d; if (!msg.header) { return; } msg.header.session = (_b = (_a = this._parentHeader) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : ''; msg.session = (_d = (_c = this._parentHeader) === null || _c === void 0 ? void 0 : _c.session) !== null && _d !== void 0 ? _d : ''; this._sendMessage(msg); // resolve promise if (msg.header.msg_type === 'status' && msg.content.execution_state === 'idle') { this._executeDelegate.resolve(); } } /** * A promise that is fulfilled when the kernel is ready. */ get ready() { return Promise.resolve(); } /** * Return whether the kernel is disposed. */ get isDisposed() { return this._isDisposed; } /** * A signal emitted when the kernel is disposed. */ get disposed() { return this._disposed; } /** * Dispose the kernel. */ dispose() { if (this.isDisposed) { return; } this._worker.terminate(); this._worker = null; this._remote = null; this._isDisposed = true; this._disposed.emit(void 0); } /** * Get the kernel id */ get id() { return this._id; } /** * Get the name of the kernel */ get name() { return this._name; } async initFileSystem(options) { let driveName; let localPath; if (options.location.includes(':')) { const parts = options.location.split(':'); driveName = parts[0]; localPath = parts[1]; } else { driveName = ''; localPath = options.location; } await this._remote.ready(); if (options.mountDrive) { await this._remote.mount(driveName, '/drive', PageConfig.getBaseUrl()); await this._remote.cd(localPath); } } }