Skip to content

Commit c296d2d

Browse files
committed
Add notebook repl and server manager
1 parent cd5f141 commit c296d2d

3 files changed

Lines changed: 40 additions & 30 deletions

File tree

src/server/src/routes/code_routes.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ import { runNodeCode } from '../runner/nodejs';
44
const codeRoute = express.Router();
55

66

7-
87
codeRoute.post('/nodejs/run', async (req, res) => {
98
const { content, language, activeNotebookName } = req.body;
10-
console.log({ content, language, activeNotebookName });
119
res.writeHead(200, {
1210
"Content-Type": "text/event-stream",
1311
"Cache-control": "no-cache"
1412
});
15-
runNodeCode({ code: content, language, res });
13+
runNodeCode({ code: content, language, res, activeNotebookName });
1614
})
1715

1816

src/server/src/runner/nodejs.ts

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,46 @@ import { transformSync } from "@babel/core";
77
import { RunNodeCodeOptions } from "../types";
88
import { generateBashCode } from '../utils';
99

10+
const ReplKernelManager: any = {}
11+
1012
//A simple repl server to evaluate code from the browser
11-
const replServer = repl.start({
12-
prompt: '',
13-
eval: replEvalCode,
14-
ignoreUndefined: true,
15-
terminal: true,
16-
useColors: true,
17-
useGlobal: false
18-
});
19-
20-
replServer.context.__dirname = process.cwd();
21-
replServer.context.require = require;
22-
replServer.context.spawn = spawn;
23-
replServer.context.util = util;
13+
function getDefaultReplServer() {
14+
const replServer = repl.start({
15+
prompt: '',
16+
eval: replEvalCode,
17+
ignoreUndefined: true,
18+
terminal: true,
19+
useColors: true,
20+
useGlobal: false
21+
});
22+
23+
replServer.context.__dirname = process.cwd();
24+
replServer.context.require = require;
25+
replServer.context.spawn = spawn;
26+
replServer.context.util = util;
27+
28+
return replServer
29+
30+
}
2431

2532
async function replEvalCode(code: string) {
2633
/**@ts-ignore */
2734
return runNodeCode({ code });
2835
}
2936

30-
const runNodeCode = ({ code, res, language }: RunNodeCodeOptions) => {
37+
const runNodeCode = ({ code, res, language, activeNotebookName }: RunNodeCodeOptions) => {
38+
//switch kernel depending on active notebook
39+
ReplKernelManager[activeNotebookName] = ReplKernelManager[activeNotebookName] || getDefaultReplServer()
40+
3141
switch (language) {
3242

3343
case "sh":
3444
const bashCode = generateBashCode(code);
35-
runJsCodeInContext({ code: bashCode, res });
45+
runJsCodeInContext({ code: bashCode, res, activeNotebookName });
3646
break;
3747
case "javascript":
3848
try {
49+
//Transpile all JS code to ES5 version
3950
let transformedJsCode = transformSync(code, {
4051
presets: [
4152
[
@@ -50,7 +61,7 @@ const runNodeCode = ({ code, res, language }: RunNodeCodeOptions) => {
5061
})?.code || code;
5162

5263
transformedJsCode = `${transformedJsCode}\nconsole.log('')`
53-
runJsCodeInContext({ code: transformedJsCode, res })
64+
runJsCodeInContext({ code: transformedJsCode, res, activeNotebookName })
5465

5566
} catch (err) {
5667
let errMsg = formatErrorOutput(err)
@@ -61,26 +72,26 @@ const runNodeCode = ({ code, res, language }: RunNodeCodeOptions) => {
6172
break;
6273

6374
case "process":
64-
handleProcessCmds(code, res);
75+
handleProcessCmds({ code, res, activeNotebookName });
6576
break;
6677

6778
default:
6879
throw new Error(`Language ${language} is not supported`);
6980
}
7081
}
7182

72-
const runJsCodeInContext = async ({ code, res }: any) => {
83+
const runJsCodeInContext = async ({ code, res, activeNotebookName }: any) => {
7384
try {
7485
//Ensures all console.log statements in code are written to the response
75-
replServer.context.console = {
86+
ReplKernelManager[activeNotebookName].console = {
7687
log: (...args: any[]) => {
7788
res.write(`${args[0]}<br />`);
7889
}
7990
};
8091

81-
replServer.context.res = res;
82-
83-
await vm.runInNewContext(code, replServer.context, {
92+
ReplKernelManager[activeNotebookName].res = res;
93+
94+
await vm.runInNewContext(code, ReplKernelManager[activeNotebookName], {
8495
displayErrors: true,
8596
microtaskMode: "afterEvaluate"
8697
})
@@ -96,20 +107,20 @@ const formatErrorOutput = (err: any) => {
96107
return JSON.stringify({ output: err.message, name: err.name, __$hasError: true })
97108
}
98109

99-
const handleProcessCmds = async (code: string, res: Response) => {
110+
const handleProcessCmds = async ({ code, res, activeNotebookName }: { code: string, res: Response, activeNotebookName: string }) => {
100111
switch (code) {
101112
case "stop":
102-
stopKernel(res);
113+
stopKernel(res, activeNotebookName);
103114
break;
104115
default:
105116
break;
106117
}
107118
}
108119

109-
const stopKernel = async (res: Response) => {
120+
const stopKernel = async (res: Response, activeNotebookName: string) => {
110121
console.log("Stopping running kernel...")
111-
replServer.context.process.exit();
112-
res.write("STOPPED");
122+
ReplKernelManager[activeNotebookName].process.exit();
123+
res.end("Kernel Stopped Successfully");
113124
}
114125

115126
export {

src/server/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export type RunNodeCodeOptions = {
44
code: string,
55
language: string,
66
res: Response,
7+
activeNotebookName: string
78
}

0 commit comments

Comments
 (0)