Skip to content

Commit 4ffac95

Browse files
committed
Use ws-backend in website
1 parent 914ecc2 commit 4ffac95

File tree

4 files changed

+57
-17
lines changed

4 files changed

+57
-17
lines changed

bin/bin.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import { fork, isMaster } from "cluster";
2424
import * as opn from "opn";
2525
import * as WebSocket from "ws";
26-
import { ClusterRPC } from "../src/rpc";
2726
import { createHTTPServer } from "./server";
2827

2928
// Constants
@@ -38,33 +37,37 @@ if (isMaster) {
3837
// For now, let's create a new process for each connection and load
3938
// sandbox.ts in there.
4039
const worker = fork();
41-
const rpc = new ClusterRPC(worker, true);
42-
// To prevent "channel not active." error.
43-
rpc.start({});
4440
// Route all messages from child process to client.
4541
worker.on("message", msg => {
4642
const message = JSON.stringify(msg);
4743
ws.send(message);
4844
});
45+
// Handle worker exit.
46+
worker.on("exit", () => {
47+
console.log("[%s] Worker exited.", worker.process.pid);
48+
if (ws.readyStatus === ws.OPEN) {
49+
ws.close();
50+
}
51+
});
4952
// Route all valid messages to the child process.
5053
ws.on("message", rawData => {
5154
try {
5255
const data = JSON.parse(String(rawData));
53-
rpc.call(data.type, data);
56+
worker.send(data);
5457
} catch (e) {
5558
console.error(e);
5659
}
5760
});
5861
// Kill a child process whenever user disconnects.
5962
ws.on("close", () => {
60-
rpc.stop();
6163
worker.kill();
6264
});
6365
});
6466

6567
server.listen(PORT, () => {
6668
console.log("Propel server started on port %s.", PORT);
67-
opn(`http://localhost:${PORT}/?ws=${PORT}`);
69+
const wsUrl = `ws://localhost:${PORT}`;
70+
opn(`http://localhost:${PORT}/#ws/${encodeURIComponent(wsUrl)}`);
6871
});
6972
} else {
7073
console.log("[%s] Worker started.", process.pid);

src/app.tsx

+21
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import * as db from "./db";
1818
import { push, Router } from "./router";
1919
import * as types from "./types";
2020
import { equal } from "./util";
21+
import { VM } from "./vm";
2122

2223
import { ErrorPage } from "./components/error";
2324
import { GlobalHeader } from "./components/header";
@@ -190,6 +191,25 @@ export const NotebookPage = bind(Notebook, {
190191
});
191192

192193
export const HomePage = bind(Home as any, {});
194+
195+
// TODO remove any
196+
export class WSSetupPage extends Component<any> {
197+
componentWillMount() {
198+
// TODO maybe /notebook/ws ?
199+
setTimeout(() => push("/notebook/anonymous"), 2000);
200+
console.log(this.props);
201+
const ws = decodeURIComponent(this.props.matches.server);
202+
VM.wsServer = ws;
203+
}
204+
205+
render() {
206+
return (
207+
<div>
208+
Use websocket server. { VM.wsServer }
209+
</div>
210+
);
211+
}
212+
}
193213
// tslint:enable:variable-name
194214

195215
export interface AppState {
@@ -226,6 +246,7 @@ export class App extends Component<{}, AppState> {
226246
<RecentPage path="/notebook" userInfo={userInfo} />
227247
<NotebookPage path="/notebook/:nbId" userInfo={userInfo} />
228248
<ProfilePage path="/user/:userId" userInfo={userInfo} />
249+
<WSSetupPage path="/ws/:server" />
229250
<ErrorPage message="The page you're looking for doesn't exist." />
230251
</Router>
231252
</div>

src/rpc.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ export class ClusterRPC extends RPCBase {
224224
}
225225

226226
private receive = (message: Message) => {
227-
super.onMessage(message);
227+
super.onMessage(message);
228228
}
229229

230230
start(handlers: RpcHandlers): void {
@@ -236,6 +236,6 @@ export class ClusterRPC extends RPCBase {
236236

237237
stop(): void {
238238
super.stop();
239-
this.process.removeListener("message");
239+
this.process.removeListener("message", this.receive);
240240
}
241241
}

src/vm.ts

+24-8
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
import { escape } from "he";
1717
import { OutputHandlerDOM } from "./output_handler_dom";
18-
import { RPC, WindowRPC } from "./rpc";
19-
import { randomString } from "./util";
18+
import { RPC, WebSocketRPC, WindowRPC } from "./rpc";
19+
import { createResolvable, randomString } from "./util";
2020

2121
function createIframe(rpcChannelId): HTMLIFrameElement {
2222
const base = new URL("/sandbox", window.document.baseURI).href;
@@ -49,32 +49,48 @@ export type CellId = number | string;
4949
export class VM {
5050
private iframe: HTMLIFrameElement;
5151
private RPC: RPC;
52+
private ws: WebSocket;
5253
readonly id: string;
54+
static wsServer = null;
5355

5456
constructor(private rpcHandler) {
5557
this.id = randomString();
5658
}
5759

58-
init() {
60+
async init() {
5961
if (this.RPC) return;
60-
this.iframe = createIframe(this.id);
61-
this.RPC = new WindowRPC(this.iframe.contentWindow, this.id);
62-
this.RPC.start(this.rpcHandler);
62+
if (VM.wsServer) {
63+
console.log("Connecting to ws-backend: %s.", VM.wsServer);
64+
const wsPromise = createResolvable();
65+
this.ws = new WebSocket(VM.wsServer);
66+
this.ws.onopen = wsPromise.resolve;
67+
await wsPromise;
68+
this.RPC = new WebSocketRPC(this.ws);
69+
this.RPC.start(this.rpcHandler);
70+
} else {
71+
this.iframe = createIframe(this.id);
72+
this.RPC = new WindowRPC(this.iframe.contentWindow, this.id);
73+
this.RPC.start(this.rpcHandler);
74+
}
6375
}
6476

6577
async exec(code: string, id: CellId) {
66-
this.init();
78+
await this.init();
6779
await this.RPC.call("runCell", code, id);
6880
}
6981

7082
destroy() {
7183
if (!this.RPC) return;
7284
this.RPC.stop();
73-
if (this.iframe.parentNode) {
85+
if (this.iframe && this.iframe.parentNode) {
7486
this.iframe.parentNode.removeChild(this.iframe);
7587
}
88+
if (this.ws) {
89+
this.ws.close();
90+
}
7691
this.RPC = null;
7792
this.iframe = null;
93+
this.ws = null;
7894
}
7995
}
8096

0 commit comments

Comments
 (0)