1
>
/*---------------------------------------------------------------------------------------------
agentHostChannel.ts
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
>
// Server-side IPC channel that proxies the agent host protocol from a
7
>
// renderer to the agent host process running on the server. For each
8
>
// renderer client (identified by IPC context) the channel opens its own
9
>
// AHP-over-WebSocket connection upstream and pipes raw JSON frames.
10
>
//
11
>
// The renderer-side counterpart is `AgentHostIpcChannelTransport` in
12
>
// `src/vs/platform/agentHost/browser/`. Together they reuse the existing
13
>
// `RemoteAgentHostProtocolClient` over IPC instead of a raw WebSocket.
14
>
15
>
import { Emitter, Event } from '../../base/common/event.js';
16
>
import { Disposable, IDisposable } from '../../base/common/lifecycle.js';
17
>
import { connectionTokenQueryName } from '../../base/common/network.js';
18
>
import { IPCServer, IServerChannel } from '../../base/parts/ipc/common/ipc.js';
19
>
import { ILogService } from '../../platform/log/common/log.js';
20
>
import type * as wsTypes from 'ws';
21
>
import type * as netTypes from 'net';
22
>
23
>
const agentHostProxyUnavailableMessage = 'Agent host proxy is not available because no upstream agent host endpoint was configured.';
24
>
25
>
/**
26
>
* Endpoint description for the upstream agent host. One of `port` or
27
>
* `socketPath` must be set, matching how `setWebSocketConfig` is called
28
>
* for `NodeAgentHostStarter`.
29
>
*/
30
>
export interface IAgentHostUpstreamEndpoint {
31
>
readonly host?: string;
32
>
readonly port?: string;
33
>
readonly socketPath?: string;
34
>
readonly connectionToken?: string;
35
>
}
36
>
37
>
/**
38
>
* Lazy-loaded `ws` module. Imported once on first connection so renderers
39
>
* that never touch the agent host don't pay the cost.
40
>
*/
41
>
let _wsModule: typeof wsTypes | undefined;
42
async function loadWs(): Promise<typeof wsTypes> {
43
return _wsModule ??= await import('ws');
44
}
46
>
let _netModule: typeof netTypes | undefined;
47
async function loadNet(): Promise<typeof netTypes> {
48
return _netModule ??= await import('net');
49
}
51
>
/**
52
>
* One upstream connection to the agent host, owned by a single renderer
53
>
* client. The default implementation wraps a `ws.WebSocket`; tests inject
54
>
* a custom factory via {@link AgentHostChannel.upstreamFactory}.
55
>
*/
56
>
export interface IUpstreamConnection extends IDisposable {
57
>
readonly onFrame: Event<string>;
58
>
readonly onClose: Event<void>;
59
>
connect(): Promise<void>;
60
>
send(frame: string): void;
61
>
}
62
>
63
>
export type UpstreamConnectionFactory = (endpoint: IAgentHostUpstreamEndpoint) => IUpstreamConnection;
64
>
65
>
/**
66
>
* IPC channel registered when the remote server has no agent host upstream.
67
>
* Keeping the channel present lets renderers fail explicitly without making
68
>
* the IPC layer report `Unknown channel: agentHostProxy`.
69
>
*/
70
>
export class UnavailableAgentHostChannel<TContext> implements IServerChannel<TContext> {
71
>
72
>
listen<T>(_ctx: TContext, event: string): Event<T> {
73
switch (event) {
74
case 'frame':