Skip to content

Commit d2cf4e8

Browse files
feat(Wind): Forward extension host protocol messages to Mountain
Add ForwardToMountain function in Preload.ts to relay binary extension host protocol messages to Mountain for gRPC relay to Cocoon. Implements bidirectional messaging by listening for cocoon:extensionHostReply Tauri events and posting responses back to the workbench port. Adds performance.mark() calls for handshake-complete and message flow tracing. This completes the IPC bridge enabling VS Code extension host bidirectional communication with the workbench via Mountain. Refs: Vine protocol (Mountain ↔ Cocoon)
1 parent 52da71f commit d2cf4e8

File tree

2 files changed

+118
-22
lines changed

2 files changed

+118
-22
lines changed

Source/Preload.ts

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ const ipcRenderer = {
186186

187187
const ipcMessagePort = {
188188
acquire: (responseChannel: string, nonce: string) => {
189-
190189
// Create an in-memory MessageChannel.
191190
// port2 is posted to the window so acquirePort() (ipc.mp.ts) picks it up
192191
// via its window 'message' listener (filters e.data === nonce && e.ports[0]).
@@ -200,19 +199,28 @@ const ipcMessagePort = {
200199
port1.start();
201200

202201
let HandshakeComplete = false;
203-
204-
port1.onmessage = (Event: MessageEvent) => {
205-
if (HandshakeComplete) {
206-
// After handshake, silently drop extension-host protocol
207-
// messages (activate, executeCommand, etc.) until
208-
// a real Cocoon relay is wired.
209-
return;
202+
let MessageCount = 0;
203+
204+
const ForwardToMountain = (Data: ArrayBuffer | Uint8Array) => {
205+
// Forward binary extension host protocol messages to Mountain
206+
// for relay to Cocoon via gRPC. Mountain will handle decoding.
207+
const Invoke =
208+
(window as any).__TAURI__?.core?.invoke ??
209+
(window as any).__TAURI__?.invoke;
210+
211+
if (typeof Invoke === "function") {
212+
const Bytes =
213+
Data instanceof Uint8Array
214+
? Array.from(Data)
215+
: Array.from(new Uint8Array(Data));
216+
Invoke("MountainIPCInvoke", {
217+
method: "cocoon:extensionHostMessage",
218+
params: [{ data: Bytes, responseChannel }],
219+
}).catch(() => {});
210220
}
221+
};
211222

212-
// The first large message from VS Code is the init data
213-
// (JSON-encoded IExtensionHostInitData wrapped in VSBuffer).
214-
// Any message with byteLength > 1 is init data; single-byte
215-
// messages are control (Ready=2, Initialized=1, Terminate=3).
223+
port1.onmessage = (Event: MessageEvent) => {
216224
const Data = Event.data;
217225
const Length =
218226
Data instanceof ArrayBuffer
@@ -223,13 +231,58 @@ const ipcMessagePort = {
223231
? Data.byteLength
224232
: 0;
225233

226-
if (Length > 1) {
227-
HandshakeComplete = true;
228-
// MessageType.Initialized → byte 1
229-
port1.postMessage(new Uint8Array([1]));
234+
if (!HandshakeComplete) {
235+
// The first large message from VS Code is the init data
236+
// (JSON-encoded IExtensionHostInitData wrapped in VSBuffer).
237+
// Any message with byteLength > 1 is init data; single-byte
238+
// messages are control (Ready=2, Initialized=1, Terminate=3).
239+
if (Length > 1) {
240+
HandshakeComplete = true;
241+
try {
242+
performance.mark("land:exthost:handshake-complete");
243+
} catch {}
244+
245+
// Forward init data to Mountain for Cocoon
246+
ForwardToMountain(
247+
Data instanceof Uint8Array
248+
? Data
249+
: new Uint8Array(Data),
250+
);
251+
252+
// MessageType.Initialized → byte 1
253+
port1.postMessage(new Uint8Array([1]));
254+
}
255+
return;
256+
}
257+
258+
// Post-handshake: forward extension host protocol messages
259+
MessageCount++;
260+
try {
261+
performance.mark(`land:exthost:message:${MessageCount}`, {
262+
detail: { bytes: Length },
263+
});
264+
} catch {}
265+
266+
if (Length > 0) {
267+
ForwardToMountain(
268+
Data instanceof Uint8Array ? Data : new Uint8Array(Data),
269+
);
230270
}
231271
};
232272

273+
// Listen for Cocoon → workbench messages via Tauri events
274+
const TauriListen = (window as any).__TAURI__?.event?.listen;
275+
if (typeof TauriListen === "function") {
276+
TauriListen(
277+
"cocoon:extensionHostReply",
278+
(Event: { payload: { data: number[] } }) => {
279+
if (Event?.payload?.data) {
280+
port1.postMessage(new Uint8Array(Event.payload.data));
281+
}
282+
},
283+
).catch(() => {});
284+
}
285+
233286
// Send Ready after a tick so VS Code's onMessage listener is registered.
234287
// MessageType.Ready → byte 2
235288
setTimeout(() => {

Target/Preload.js

Lines changed: 49 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)