Skip to content

Commit 1af1f5d

Browse files
committed
fix(ws): enable ws proxy via MessageChannel
1 parent 58083f4 commit 1af1f5d

2 files changed

Lines changed: 97 additions & 3 deletions

File tree

vue3-app/src/main.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import wslink from "./core/wslink";
44
import { handlePageResources, loadScript } from "./core/trame/setup";
55
import { createTrameInstance } from "./core/trame";
66
import { registerUserScripts } from "./user_script_handler";
7+
import { createMessageChannelWSFactory } from "./messageChannel";
78
import TrameUse from "./use";
89

910
const { createApp } = window.Vue;
@@ -12,7 +13,7 @@ async function start() {
1213
// Check if we need to override websocket
1314
try {
1415
// Can throw exception if parent is cross-origin
15-
if (window?.parent?.trameJupyter?.init) {
16+
if (!window.WSLINK && window?.parent?.trameJupyter?.init) {
1617
window.WSLINK = window.parent.trameJupyter.init(window);
1718
}
1819
} catch (e) {
@@ -123,11 +124,31 @@ async function start() {
123124
registerUserScripts();
124125
}
125126

127+
const urlParams = vtkURLExtract.extractURLParameters();
126128
// Initialize service worker to override headers for SharedArrayBuffer
127129
// > Cross-Origin-Opener-Policy: same-origin
128130
// > Cross-Origin-Embedder-Policy: require-corp
129-
if (vtkURLExtract.extractURLParameters().enableSharedArrayBufferServiceWorker) {
131+
if (urlParams.enableSharedArrayBufferServiceWorker) {
130132
loadScript("coi-serviceworker.min.js");
131133
}
132134

133-
start();
135+
if (urlParams.wsChannel) {
136+
window.addEventListener("message", (event) => {
137+
// Waiting for message initializing channel communication
138+
// for websocket proxying
139+
if (event.data !== "trame-ws-channel-init") {
140+
// not for us! skip
141+
return;
142+
}
143+
144+
// Grab communication port and register fake WebSocket
145+
window.WSLINK = {
146+
createWebSocket: createMessageChannelWSFactory(event.ports[0]),
147+
};
148+
149+
// Start trame client
150+
start();
151+
});
152+
} else {
153+
start();
154+
}

vue3-app/src/messageChannel.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
class MessageChannelWebSocket {
2+
constructor(port) {
3+
console.log("create MessageChannelWebSocket");
4+
this._channel_port = port;
5+
this.onmessage = null;
6+
this.onclose = null;
7+
this.onerror = null;
8+
9+
// Listen to channel messages
10+
this._channel_port.onmessage = (e) => {
11+
if (!this.onmessage) return;
12+
const { a, b, t } = e.data;
13+
14+
if (a === "s") {
15+
this.onmessage({ data: b || t });
16+
return;
17+
}
18+
if (a === "c" && this.onclose) {
19+
this.onclose(e.data.c);
20+
return;
21+
}
22+
if (a === "e" && this.onerror) {
23+
this.onerror(e.data.e);
24+
return;
25+
}
26+
};
27+
}
28+
29+
set onopen(callback) {
30+
// Auto open but allow current listeners registration to complete before triggering
31+
setTimeout(callback, 0);
32+
}
33+
34+
send(data) {
35+
console.log("send", data);
36+
if (data.buffer) {
37+
// may need a copy
38+
if (data.buffer.byteLength !== data.length) {
39+
const tmp = new Uint8Array(data.length);
40+
tmp.set(data);
41+
self._channel_port.postMessage(
42+
{
43+
a: "s",
44+
b: tmp.buffer,
45+
},
46+
[tmp.buffer]
47+
);
48+
return;
49+
}
50+
self._channel_port.postMessage(
51+
{
52+
a: "s",
53+
b: data.buffer,
54+
},
55+
[data.buffer]
56+
);
57+
return;
58+
}
59+
self._channel_port.postMessage({
60+
a: "s",
61+
t: data,
62+
});
63+
}
64+
65+
close() {
66+
self._channel_port.postMessage({ a: "c", c: "Closing from client" });
67+
self._channel_port.close();
68+
}
69+
}
70+
71+
export function createMessageChannelWSFactory(port) {
72+
return () => new MessageChannelWebSocket(port);
73+
}

0 commit comments

Comments
 (0)