@jupyterlab/services
Version:
Client APIs for the Jupyter services REST APIs
305 lines • 10.2 kB
JavaScript
"use strict";
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommHandler = exports.CommsOverSubshells = void 0;
const coreutils_1 = require("@lumino/coreutils");
const disposable_1 = require("@lumino/disposable");
const KernelMessage = __importStar(require("./messages"));
/**
* The Comm Over Subshell Enum
*/
var CommsOverSubshells;
(function (CommsOverSubshells) {
CommsOverSubshells["Disabled"] = "disabled";
CommsOverSubshells["PerComm"] = "perComm";
CommsOverSubshells["PerCommTarget"] = "perCommTarget";
})(CommsOverSubshells || (exports.CommsOverSubshells = CommsOverSubshells = {}));
/**
* Comm channel handler.
*/
class CommHandler extends disposable_1.DisposableDelegate {
/**
* Construct a new comm channel.
*/
constructor(target, id, kernel, disposeCb, commsOverSubshells) {
super(disposeCb);
this._subshellStarted = new coreutils_1.PromiseDelegate();
this._subshellId = null;
this._target = '';
this._id = '';
this._id = id;
this._target = target;
this._kernel = kernel;
// Clean subshell ids upon restart
this._kernel.statusChanged.connect(() => {
if (this._kernel.status === 'restarting') {
this._cleanSubshells();
}
});
this.commsOverSubshells =
commsOverSubshells !== null && commsOverSubshells !== void 0 ? commsOverSubshells : CommsOverSubshells.PerCommTarget;
}
/**
* The unique id for the comm channel.
*/
get commId() {
return this._id;
}
/**
* The target name for the comm channel.
*/
get targetName() {
return this._target;
}
/**
* The current subshell id.
*/
get subshellId() {
return this._subshellId;
}
/**
* Promise that resolves when the subshell started, if any
*/
get subshellStarted() {
return this._subshellStarted.promise;
}
/**
* Whether comms are running on a subshell, or not
*/
get commsOverSubshells() {
return this._commsOverSubshells;
}
/**
* Set whether comms are running on subshells, or not
*/
set commsOverSubshells(value) {
this._commsOverSubshells = value;
if (this._commsOverSubshells === CommsOverSubshells.Disabled) {
this._maybeCloseSubshell();
}
else {
void this._maybeStartSubshell();
}
}
/**
* Get the callback for a comm close event.
*
* #### Notes
* This is called when the comm is closed from either the server or client.
*
* **See also:** [[ICommClose]], [[close]]
*/
get onClose() {
return this._onClose;
}
/**
* Set the callback for a comm close event.
*
* #### Notes
* This is called when the comm is closed from either the server or client. If
* the function returns a promise, and the kernel was closed from the server,
* kernel message processing will pause until the returned promise is
* fulfilled.
*
* **See also:** [[close]]
*/
set onClose(cb) {
this._onClose = cb;
}
/**
* Get the callback for a comm message received event.
*/
get onMsg() {
return this._onMsg;
}
/**
* Set the callback for a comm message received event.
*
* #### Notes
* This is called when a comm message is received. If the function returns a
* promise, kernel message processing will pause until it is fulfilled.
*/
set onMsg(cb) {
this._onMsg = cb;
}
/**
* Open a comm with optional data and metadata.
*
* #### Notes
* This sends a `comm_open` message to the server.
*
* **See also:** [[ICommOpen]]
*/
open(data, metadata, buffers = []) {
if (this.isDisposed || this._kernel.isDisposed) {
throw new Error('Cannot open');
}
const msg = KernelMessage.createMessage({
msgType: 'comm_open',
channel: 'shell',
username: this._kernel.username,
session: this._kernel.clientId,
subshellId: this._subshellId || this._kernel.subshellId,
content: {
comm_id: this._id,
target_name: this._target,
data: data !== null && data !== void 0 ? data : {}
},
metadata,
buffers
});
return this._kernel.sendShellMessage(msg, false, true);
}
/**
* Send a `comm_msg` message to the kernel.
*
* #### Notes
* This is a no-op if the comm has been closed.
*
* **See also:** [[ICommMsg]]
*/
send(data, metadata, buffers = [], disposeOnDone = true) {
if (this.isDisposed || this._kernel.isDisposed) {
throw new Error('Cannot send');
}
const msg = KernelMessage.createMessage({
msgType: 'comm_msg',
channel: 'shell',
username: this._kernel.username,
session: this._kernel.clientId,
subshellId: this._subshellId || this._kernel.subshellId,
content: {
comm_id: this._id,
data: data
},
metadata,
buffers
});
return this._kernel.sendShellMessage(msg, false, disposeOnDone);
}
/**
* Close the comm.
*
* #### Notes
* This will send a `comm_close` message to the kernel, and call the
* `onClose` callback if set.
*
* This is a no-op if the comm is already closed.
*
* **See also:** [[ICommClose]], [[onClose]]
*/
close(data, metadata, buffers = []) {
if (this.isDisposed || this._kernel.isDisposed) {
throw new Error('Cannot close');
}
const msg = KernelMessage.createMessage({
msgType: 'comm_close',
channel: 'shell',
username: this._kernel.username,
session: this._kernel.clientId,
subshellId: this._subshellId || this._kernel.subshellId,
content: {
comm_id: this._id,
data: data !== null && data !== void 0 ? data : {}
},
metadata,
buffers
});
const future = this._kernel.sendShellMessage(msg, false, true);
const onClose = this._onClose;
if (onClose) {
const ioMsg = KernelMessage.createMessage({
msgType: 'comm_close',
channel: 'iopub',
username: this._kernel.username,
session: this._kernel.clientId,
subshellId: this._subshellId || this._kernel.subshellId,
content: {
comm_id: this._id,
data: data !== null && data !== void 0 ? data : {}
},
metadata,
buffers
});
// In the future, we may want to communicate back to the user the possible
// promise returned from onClose.
void onClose(ioMsg);
}
this.dispose();
return future;
}
dispose() {
this._maybeCloseSubshell();
super.dispose();
}
_cleanSubshells() {
CommHandler._commTargetSubShellsId = {};
}
async _maybeStartSubshell() {
await this._kernel.info;
if (!this._kernel.supportsSubshells) {
return;
}
if (this._commsOverSubshells === CommsOverSubshells.PerComm) {
// Create subshell
const replyMsg = await this._kernel.requestCreateSubshell({}).done;
this._subshellId = replyMsg.content.subshell_id;
this._subshellStarted.resolve();
return;
}
// One shell per comm-target
if (CommHandler._commTargetSubShellsId[this._target]) {
this._subshellId = await CommHandler._commTargetSubShellsId[this._target];
this._subshellStarted.resolve();
}
else {
// Create subshell
CommHandler._commTargetSubShellsId[this._target] = this._kernel
.requestCreateSubshell({})
.done.then(replyMsg => {
this._subshellId = replyMsg.content.subshell_id;
return this._subshellId;
});
await CommHandler._commTargetSubShellsId[this._target];
this._subshellStarted.resolve();
}
}
_maybeCloseSubshell() {
// Only close subshell if we have one subshell per comm
if (this._commsOverSubshells !== CommsOverSubshells.PerComm) {
this._subshellId = null;
return;
}
if (this._subshellId && this._kernel.status !== 'dead') {
this._kernel.requestDeleteSubshell({ subshell_id: this._subshellId }, true);
}
this._subshellId = null;
}
}
exports.CommHandler = CommHandler;
CommHandler._commTargetSubShellsId = {};
//# sourceMappingURL=comm.js.map