Skip to content

Commit 2e47ca1

Browse files
committed
Support server-side execution
1 parent b49bc4f commit 2e47ca1

File tree

5 files changed

+4513
-3173
lines changed

5 files changed

+4513
-3173
lines changed

jupyter_collaboration/app.py

+8
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ class YDocExtension(ExtensionApp):
5757
directory.""",
5858
)
5959

60+
server_side_execution = Bool(
61+
False,
62+
config=True,
63+
help="""Whether to execute notebooks in the server using the REST API, not using the kernel
64+
protocol over WebSocket. The frontend only interacts with the notebook through its shared
65+
model.""",
66+
)
67+
6068
def initialize(self):
6169
super().initialize()
6270
self.serverapp.event_logger.register_event_schema(EVENTS_SCHEMA_PATH)

packages/collaboration-extension/package.json

+14-13
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,20 @@
5656
"@jupyter/collaboration": "^2.0.11",
5757
"@jupyter/docprovider": "^2.0.11",
5858
"@jupyter/ydoc": "^1.1.0-a0",
59-
"@jupyterlab/application": "^4.0.5",
60-
"@jupyterlab/apputils": "^4.0.5",
61-
"@jupyterlab/codemirror": "^4.0.5",
59+
"@jupyterlab/application": "^4.2.0-beta.0",
60+
"@jupyterlab/apputils": "^4.2.0-beta.0",
61+
"@jupyterlab/codemirror": "^4.2.0-beta.0",
6262
"@jupyterlab/coreutils": "^6.0.5",
63-
"@jupyterlab/docregistry": "^4.0.5",
64-
"@jupyterlab/filebrowser": "^4.0.5",
65-
"@jupyterlab/fileeditor": "^4.0.5",
66-
"@jupyterlab/logconsole": "^4.0.5",
67-
"@jupyterlab/notebook": "^4.0.5",
63+
"@jupyterlab/docregistry": "^4.2.0-beta.0",
64+
"@jupyterlab/filebrowser": "^4.2.0-beta.0",
65+
"@jupyterlab/fileeditor": "^4.2.0-beta.0",
66+
"@jupyterlab/logconsole": "^4.2.0-beta.0",
67+
"@jupyterlab/notebook": "^4.2.0-beta.0",
6868
"@jupyterlab/services": "^7.0.5",
69-
"@jupyterlab/settingregistry": "^4.0.5",
70-
"@jupyterlab/statedb": "^4.0.5",
71-
"@jupyterlab/translation": "^4.0.5",
72-
"@jupyterlab/ui-components": "^4.0.5",
69+
"@jupyterlab/settingregistry": "^4.2.0-beta.0",
70+
"@jupyterlab/statedb": "^4.2.0-beta.0",
71+
"@jupyterlab/translation": "^4.2.0-beta.0",
72+
"@jupyterlab/ui-components": "^4.2.0-beta.0",
7373
"@lumino/commands": "^2.1.0",
7474
"@lumino/widgets": "^2.1.0",
7575
"y-protocols": "^1.0.5",
@@ -97,7 +97,8 @@
9797
"schemaDir": "./schema",
9898
"outputDir": "../../jupyter_collaboration/labextension",
9999
"disabledExtensions": [
100-
"@jupyterlab/filebrowser-extension:defaultFileBrowser"
100+
"@jupyterlab/filebrowser-extension:defaultFileBrowser",
101+
"@jupyterlab/notebook-extension:cell-executor"
101102
],
102103
"sharedPackages": {
103104
"@codemirror/state": {

packages/collaboration-extension/src/collaboration.ts

+63-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import {
1414
EditorExtensionRegistry,
1515
IEditorExtensionRegistry
1616
} from '@jupyterlab/codemirror';
17+
import { type MarkdownCell } from '@jupyterlab/cells';
18+
import { INotebookCellExecutor, runCell } from '@jupyterlab/notebook';
1719
import { WebSocketAwarenessProvider } from '@jupyter/docprovider';
1820
import { SidePanel, usersIcon } from '@jupyterlab/ui-components';
19-
import { URLExt } from '@jupyterlab/coreutils';
21+
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
2022
import { ServerConnection } from '@jupyterlab/services';
2123
import { IStateDB, StateDB } from '@jupyterlab/statedb';
2224
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
@@ -189,3 +191,63 @@ export const userEditorCursors: JupyterFrontEndPlugin<void> = {
189191
});
190192
}
191193
};
194+
195+
export const notebookCellExecutor: JupyterFrontEndPlugin<INotebookCellExecutor> = {
196+
id: '@jupyter/collaboration-extension:notebook-cell-executor',
197+
description:
198+
'Add notebook cell executor that uses REST API instead of kernel protocol over WebSocket.',
199+
autoStart: true,
200+
provides: INotebookCellExecutor,
201+
activate: (
202+
app: JupyterFrontEnd
203+
): INotebookCellExecutor => {
204+
if (PageConfig.getOption('serverSideExecution') === 'true') {
205+
return Object.freeze({ runCell: runCellServerSide });
206+
}
207+
return Object.freeze({ runCell });
208+
}
209+
};
210+
211+
212+
async function runCellServerSide({
213+
cell,
214+
notebook,
215+
notebookConfig,
216+
onCellExecuted,
217+
onCellExecutionScheduled,
218+
sessionContext,
219+
sessionDialogs,
220+
translator
221+
}: INotebookCellExecutor.IRunCellOptions): Promise<boolean> {
222+
switch (cell.model.type) {
223+
case 'markdown':
224+
(cell as MarkdownCell).rendered = true;
225+
cell.inputHidden = false;
226+
onCellExecuted({ cell, success: true });
227+
break;
228+
case 'code':
229+
const kernelId = sessionContext?.session?.kernel?.id;
230+
const settings = ServerConnection.makeSettings();
231+
const apiURL = URLExt.join(
232+
settings.baseUrl,
233+
`api/kernels/${kernelId}/execute`
234+
);
235+
const cellId = cell.model.sharedModel.getId();
236+
const documentId = `json:notebook:${notebook.sharedModel.getState(
237+
'file_id'
238+
)}`;
239+
const body = `{"cell_id":"${cellId}","document_id":"${documentId}"}`;
240+
const init = {
241+
method: 'POST',
242+
body
243+
};
244+
try {
245+
await ServerConnection.makeRequest(apiURL, init, settings);
246+
} catch (error: any) {
247+
throw new ServerConnection.NetworkError(error);
248+
}
249+
default:
250+
break;
251+
}
252+
return Promise.resolve(true);
253+
}

packages/collaboration-extension/src/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
menuBarPlugin,
2020
rtcGlobalAwarenessPlugin,
2121
rtcPanelPlugin,
22-
userEditorCursors
22+
userEditorCursors,
23+
notebookCellExecutor
2324
} from './collaboration';
2425
import { sharedLink } from './sharedlink';
2526

@@ -37,7 +38,8 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
3738
rtcGlobalAwarenessPlugin,
3839
rtcPanelPlugin,
3940
sharedLink,
40-
userEditorCursors
41+
userEditorCursors,
42+
notebookCellExecutor
4143
];
4244

4345
export default plugins;

0 commit comments

Comments
 (0)