Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/electron-browser/tunnelRelayTransport.ts
13394 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Emitter } from '../../../base/common/event.js';
7
import { Disposable } from '../../../base/common/lifecycle.js';
8
import type { AhpServerNotification, JsonRpcResponse, ProtocolMessage } from '../common/state/sessionProtocol.js';
9
import type { IProtocolTransport } from '../common/state/sessionTransport.js';
10
import type { ITunnelAgentHostMainService, ITunnelRelayMessage } from '../common/tunnelAgentHost.js';
11
import { MALFORMED_FRAMES_FORCE_CLOSE_THRESHOLD, MALFORMED_FRAMES_LOG_CAP } from '../common/transportConstants.js';
12
13
/**
14
* A protocol transport that relays messages through the shared process
15
* tunnel relay via IPC, instead of using a direct WebSocket connection.
16
*
17
* The shared process manages the actual dev tunnel relay connection
18
* and forwards messages bidirectionally through this IPC channel.
19
*/
20
export class TunnelRelayTransport extends Disposable implements IProtocolTransport {
21
22
private readonly _onMessage = this._register(new Emitter<ProtocolMessage>());
23
readonly onMessage = this._onMessage.event;
24
25
private readonly _onClose = this._register(new Emitter<void>());
26
readonly onClose = this._onClose.event;
27
28
private _malformedFrames = 0;
29
30
constructor(
31
private readonly _connectionId: string,
32
private readonly _tunnelService: ITunnelAgentHostMainService,
33
) {
34
super();
35
36
// Listen for relay messages from the shared process
37
this._register(this._tunnelService.onDidRelayMessage((msg: ITunnelRelayMessage) => {
38
if (msg.connectionId !== this._connectionId) {
39
return;
40
}
41
let parsed: ProtocolMessage;
42
try {
43
parsed = JSON.parse(msg.data) as ProtocolMessage;
44
} catch (err) {
45
this._malformedFrames++;
46
if (this._malformedFrames <= MALFORMED_FRAMES_LOG_CAP) {
47
const preview = msg.data.length > 80 ? msg.data.slice(0, 80) + '…' : msg.data;
48
console.warn(
49
`[TunnelRelayTransport] Malformed frame #${this._malformedFrames} (len=${msg.data.length}): ${preview}`,
50
err instanceof Error ? err.message : String(err)
51
);
52
}
53
if (this._malformedFrames > MALFORMED_FRAMES_FORCE_CLOSE_THRESHOLD) {
54
console.warn('[TunnelRelayTransport] Malformed frame threshold exceeded; closing relay.');
55
this._tunnelService.disconnect(this._connectionId).catch(() => { /* best effort */ });
56
}
57
return;
58
}
59
this._onMessage.fire(parsed);
60
}));
61
62
// Listen for relay close
63
this._register(this._tunnelService.onDidRelayClose((closedId: string) => {
64
if (closedId === this._connectionId) {
65
this._onClose.fire();
66
}
67
}));
68
}
69
70
override dispose(): void {
71
// Tear down the shared-process relay connection
72
this._tunnelService.disconnect(this._connectionId).catch(() => { /* best effort */ });
73
super.dispose();
74
}
75
76
send(message: ProtocolMessage | AhpServerNotification | JsonRpcResponse): void {
77
this._tunnelService.relaySend(this._connectionId, JSON.stringify(message)).catch(() => {
78
// Send failed — connection probably closed
79
});
80
}
81
}
82
83