UNPKG

@nteract/epics

Version:
246 lines 10.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.restartKernelEpic = exports.launchKernelWhenNotebookSetEpic = exports.extractNewKernel = exports.acquireKernelInfoEpic = exports.acquireKernelInfo = exports.watchExecutionStateEpic = void 0; const messaging_1 = require("@nteract/messaging"); const mythic_notifications_1 = require("@nteract/mythic-notifications"); const redux_observable_1 = require("redux-observable"); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const actions = __importStar(require("@nteract/actions")); const selectors = __importStar(require("@nteract/selectors")); const types_1 = require("@nteract/types"); const types_2 = require("@nteract/types"); const path = require("path"); /** * Sets the execution state after a kernel has been launched. * * @oaram {ActionObservable} action$ ActionObservable for LAUNCH_KERNEL_SUCCESSFUL action */ exports.watchExecutionStateEpic = (action$) => action$.pipe(redux_observable_1.ofType(actions.LAUNCH_KERNEL_SUCCESSFUL), operators_1.switchMap((action) => action.payload.kernel.channels.pipe(operators_1.filter((msg) => msg.header.msg_type === "status"), operators_1.map((msg) => actions.setExecutionState({ kernelStatus: msg.content.execution_state, kernelRef: action.payload.kernelRef })), operators_1.takeUntil(action$.pipe(redux_observable_1.ofType(actions.KILL_KERNEL_SUCCESSFUL), operators_1.filter((killAction) => killAction.payload.kernelRef === action.payload.kernelRef))), operators_1.catchError((error) => { return rxjs_1.of(actions.executeFailed({ error: new Error("The WebSocket connection has unexpectedly disconnected."), code: types_2.errors.EXEC_WEBSOCKET_ERROR, contentRef: action.payload.contentRef })); })))); /** * Send a kernel_info_request to the kernel. * * @param {Object} channels A object containing the kernel channels * @returns {Observable} The reply from the server */ function acquireKernelInfo(channels, kernelRef, contentRef, state, kernelSpecName) { const message = messaging_1.createMessage("kernel_info_request"); const obs = channels.pipe(messaging_1.childOf(message), messaging_1.ofMessageType("kernel_info_reply"), operators_1.first(), operators_1.mergeMap(msg => { const c = msg.content; const l = c.language_info; const info = { protocolVersion: c.protocol_version, implementation: c.implementation, implementationVersion: c.implementation_version, banner: c.banner, helpLinks: c.help_links, languageName: l.name, languageVersion: l.version, mimetype: l.mimetype, fileExtension: l.file_extension, pygmentsLexer: l.pygments_lexer, codemirrorMode: l.codemirror_mode, nbconvertExporter: l.nbconvert_exporter }; let result; if (!c.protocol_version.startsWith("5")) { result = [ actions.launchKernelFailed({ kernelRef, contentRef, error: new Error("The kernel that you are attempting to launch does not support the latest version (v5) of the messaging protocol.") }) ]; } else { result = [ // The original action we were using actions.setLanguageInfo({ langInfo: msg.content.language_info, kernelRef, contentRef }), actions.setKernelInfo({ kernelRef, info }), actions.setExecutionState({ kernelStatus: types_1.KernelStatus.Launched, kernelRef }) ]; if (kernelSpecName) { const kernelspec = selectors.kernelspecByName(state, { name: kernelSpecName }); if (kernelspec) { result.push(actions.setKernelMetadata({ contentRef, kernelInfo: kernelspec })); } } } return rxjs_1.of(...result); })); return rxjs_1.Observable.create((observer) => { const subscription = obs.subscribe(observer); channels.next(message); return subscription; }); } exports.acquireKernelInfo = acquireKernelInfo; /** * Gets information about newly launched kernel. * * @param {ActionObservable} The action type */ exports.acquireKernelInfoEpic = (action$, state$) => action$.pipe(redux_observable_1.ofType(actions.LAUNCH_KERNEL_SUCCESSFUL), operators_1.switchMap((action) => { const { payload: { kernel: { channels, kernelSpecName }, kernelRef, contentRef } } = action; return acquireKernelInfo(channels, kernelRef, contentRef, state$.value, kernelSpecName); })); exports.extractNewKernel = (filepath, notebook) => { const cwd = (filepath && path.dirname(filepath)) || "/"; const kernelSpecName = notebook.getIn(["metadata", "kernelspec", "name"]) || notebook.getIn(["metadata", "language_info", "name"]) || "python3"; return { cwd, kernelSpecName }; }; /** * NOTE: This function is _exactly_ the same as the desktop loading.js version * with one strong exception -- extractNewKernel * Can they be combined without incurring a penalty on the web app? * The native functions used are `path.dirname`, `path.resolve`, and `process.cwd()` * We could always inject those dependencies separately... */ exports.launchKernelWhenNotebookSetEpic = (action$, state$) => action$.pipe(redux_observable_1.ofType(actions.FETCH_CONTENT_FULFILLED), operators_1.mergeMap((action) => { const state = state$.value; const contentRef = action.payload.contentRef; const content = selectors.content(state, { contentRef }); if (!content || content.type !== "notebook" || content.model.type !== "notebook") { // This epic only handles notebook content return rxjs_1.EMPTY; } /** * Avoid relaunching kernels for notebooks that have already * launched their content. */ if (content.model.kernelRef) { const kernel = selectors.kernel(state, { kernelRef: content.model.kernelRef }); if (kernel && kernel.channels) { return rxjs_1.EMPTY; } } const filepath = content.filepath; const notebook = content.model.notebook; const { cwd, kernelSpecName } = exports.extractNewKernel(filepath, notebook); return rxjs_1.of(actions.launchKernelByName({ kernelSpecName, cwd, kernelRef: action.payload.kernelRef, selectNextKernel: true, contentRef: action.payload.contentRef })); })); /** * Restarts a Jupyter kernel in the local scenario, where a restart requires * killing the existing kernel process and starting an ew one. */ exports.restartKernelEpic = (action$, state$) => action$.pipe(redux_observable_1.ofType(actions.RESTART_KERNEL), operators_1.concatMap((action) => { var _a; const state = state$.value; const oldKernelRef = selectors.kernelRefByContentRef(state$.value, { contentRef: action.payload.contentRef }); if (!oldKernelRef) { return rxjs_1.of(mythic_notifications_1.sendNotification.create({ title: "Failure to Restart", message: "Unable to restart kernel, please select a new kernel.", level: "error" })); } const oldKernel = selectors.kernel(state, { kernelRef: oldKernelRef }); if (oldKernel && oldKernel.type === "websocket") { return rxjs_1.EMPTY; } if (!oldKernelRef || !oldKernel) { return rxjs_1.of(mythic_notifications_1.sendNotification.create({ title: "Failure to Restart", message: "Unable to restart kernel, please select a new kernel.", level: "error" })); } const newKernelRef = types_2.createKernelRef(); const initiatingContentRef = action.payload.contentRef; const successNotification = mythic_notifications_1.sendNotification.create({ title: "Kernel Restarting...", message: `Kernel ${oldKernel.kernelSpecName || "unknown"} is restarting.`, level: "success" }); const kill = actions.killKernel({ restarting: true, kernelRef: oldKernelRef }); const relaunch = actions.launchKernelByName({ kernelSpecName: (_a = oldKernel.kernelSpecName) !== null && _a !== void 0 ? _a : undefined, cwd: oldKernel.cwd, kernelRef: newKernelRef, selectNextKernel: true, contentRef: initiatingContentRef }); const awaitKernelReady = action$.pipe(redux_observable_1.ofType(actions.LAUNCH_KERNEL_SUCCESSFUL), operators_1.filter((action) => action.payload.kernelRef === newKernelRef), operators_1.take(1), operators_1.timeout(60000), // If kernel doesn't come up within this interval we will abort follow-on actions. operators_1.concatMap(() => { const restartSuccess = actions.restartKernelSuccessful({ kernelRef: newKernelRef, contentRef: initiatingContentRef }); if (action.payload.outputHandling === "Run All") { return rxjs_1.of(restartSuccess, actions.executeAllCells({ contentRef: initiatingContentRef })); } else { return rxjs_1.of(restartSuccess); } }), operators_1.catchError(error => { return rxjs_1.of(actions.restartKernelFailed({ error, kernelRef: newKernelRef, contentRef: initiatingContentRef })); })); return rxjs_1.merge(rxjs_1.of(kill, relaunch, successNotification), awaitKernelReady); })); //# sourceMappingURL=kernel-lifecycle.js.map